C++指针/数组(我现在完全困惑,真的需要帮助)
C++ Pointers/Arrays(I'm completely and utterly confused at this moment and really need help)
这就是我最终想出的。我目前无法弄清楚如何将我的反向数组函数放入主...如果我只是将代码复制并粘贴到其中,则每次运行时都会崩溃......我不知道为什么它会导致它崩溃或任何东西。感谢到目前为止帮助我的所有人。
using namespace std;
// Prototype for printArray goes here
void reverseArray(int*, int);
void printArray(int*, int);
int main()
{
int size; // size of the dynamically allocated array
// Declare as needed for a dynamically allocated array of
ints named "data".
// Declare other variables as needed
// Edit to display your own name
cout << "" << endl << endl;
// Prompt the user for the array size
cout << "Array size: ";
cin >> size;
// Add code to validate array size, so it is greater than one
while (size < 2)
{
cout << "Array size must be greater than 1: ";
cin >> size;
}
// Add code to dynamically allocate "data". Don't forget to release the memory before
// the program ends
int *data = new int[size],
*p = data;
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
for (int i = 0; i < size; i++, p++)
{
*p = rand() % 100 + 1;
}
// Call function to print the original "data" array
cout << "nOriginal array:n" << endl;
printArray(data, size);
// Reset "data" to point to the beginning of the array
// Add code to reverse the array. Use 2 pointers: one starts at the beginning of the array and
// moves forward, the other starts at its last element and works backward. Swap the values they
// point to.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
// For this, I made the function reverseArray instead of coding it in main.
reverseArray(data, size);
cout << endl;
cout << "nReversed array:n" << endl;
printArray(data, size);
cout << endl << endl;
// Finish up
delete[] data;
system("pause");
return 0;
}
// Function printArray() goes here. Print the array, 5 numbers per line,
right-aligned
void printArray(int*p, int size)
{
for (int i = 0; i < size; i++, p++)
{
cout << setw(5) << right << *p;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
// Function reverseArray() Reverses the array.
void reverseArray(int *data, int size)
{
int *e = data + size - 1; // Pointer at the end
for (; e > data; data++, e--) // while end pointer (e)> start pointer, swap start w/ end
{
int arrayFlip = *data;
*data = *e;
*e = arrayFlip;
}
}
你可能无缘无故地折磨自己,或者把头撞到砖墙上(别担心 - 我们都去过那里......并有瘀伤来证明这一点。
首先,让我们从任何分配的内存块开始,比如:
int *a = new int[NELEM], ...
什么是a
?(一个指针 - 是的,但指向什么?它是指向内存块中起始地址的指针,大小为NELEM * sizeof *a
字节。它是什么类型的指针?(int
)。每个整数多少字节?(一般4
)。
那么,为什么让指针成为类型int
很重要呢?(好吧,它设置了控制指针算术在通过该指针引用内存块时如何操作的类型大小)这意味着由于您的指针类型是int
,编译器知道a + 1
是a + 4-bytes
,这允许您引用内存块中的下一个值。
好的,但是我为a
分配了内存,我对a
的责任是什么?在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有 2个责任:(1)始终保留指向内存块起始地址的指针,以便 (2) 当不再需要内存块时可以释放它。
这对我意味着什么?这意味着,如果您不能简单地递增a
(例如a++
)在声明a
的范围内。如果这样做,您将丢失对块的起始地址的引用,并且无法再释放该块(这是内存泄漏)。
因此,如果我无法使用任何索引(例如a[i]
或*(a + i)
),并且我不能增加指针a
- 那么我有什么选择?使用另一个指针...,例如
int *a = new int[NELEM],
*p = a;
...
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << 'n';
您是否履行了分配给a
的内存块的责任?当然,a
仍然指向块的起始地址,因此可以释放它。您所做的只是使用第二个指针p
并使用p
进行迭代,a
保持不变。
嗯。。使用第二个指针..我想知道我是否可以使用相同的方案反转我的数组。是的。在最简单的形式中,您可以执行以下操作:
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
但是等等!!您说您无法在不丢失我分配的块的起始地址的情况下增加a
- 我现在如何free
它?(a
main()
永远不会改变,函数rev
接收a
的副本,并且在rev
内存块的范围内,您可以自由地增加/减少或做任何您喜欢a
的事情,在内存块的范围内,因为rev
中的a
与main()
中的原始指针有自己的(并且非常不同)的地址。
(题外话...你可以在rev
内声明第三个指针,例如
int *s = a, /* start pointer */
*e = a + size - 1; /* end pointer */
然后在迭代和交换中使用s
而不是a
,但没有必要。如果您更清楚正在使用哪个指针,则可以自由地这样做。它只是另一个 8 字节(或 x86 上的 4 个字节),因此额外的存储空间不是问题。
把它放在一个简短的例子中,你可以做类似于下面的事情:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#define NELEM 10
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
int main (void) {
int *a = new int[NELEM],
*p = a;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << 'n';
rev (a, NELEM);
p = a;
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << 'n';
delete[] a;
}
示例使用/输出
$ ./bin/array_reverse
array : 11 6 78 93 25 71 82 58 97 68
reverse: 68 97 58 82 71 25 93 78 6 11
所有这些都需要一点时间才能沉浸其中。我们的额头上都有同一堵墙上的瘀伤。只要接受这样一个事实,即指针只是一个变量,它保存其他东西的地址作为它的值(例如,它指向其他东西的存储位置)。
了解指针的type
如何影响指针算术(和索引),例如,有多少字节以p++
或for (i = 0; i < size; i++) p[i]
前进,并确保你确切地知道指针指向的位置,事情应该开始到位。
如果你在弄清楚指针发生了什么时遇到任何问题,拿出一张8.5 x 11的纸和一支2号铅笔,把它画出来——在每次迭代时填写你的指针指向的块,等等——它真的很有帮助。一旦你画了足够的图表,完成了足够的链表、堆栈等......你不会像现在这样需要纸张(你仍然需要它 - 所以请随身携带)
使用函数反转main()
作为对您的评论的回应,当您查看main()
时,您已经声明了一个额外的指针p
。因此,您可以简单地将其用作开始指针,并从rev()
函数中添加e
作为结束指针。一个简单的实现是:
int main (void) {
int *a = new int[NELEM],
*p = a,
*e = a + NELEM - 1;;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << 'n';
p = a; /* reset pointer */
for (; e > p; p++, e--) { /* reverse array */
int tmp = *p;
*p = *e;
*e = tmp;
}
p = a; /* reset pointer -- again */
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << 'n';
delete[] a;
}
(相同的输出)
仔细查看,如果您有其他问题,请告诉我。
main
中的以下行不正确。
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
他们只是设置数组第一个元素的值并打印相同的元素。
请改用data[i]
。
data[i] = rand() % 100 + 1;
cout << setw(5) << right << data[i];
如果必须使用指针表示法,请使用*(data+i)
。
*(data+i) = rand() % 100 + 1;
cout << setw(5) << right << *(data+i);
可以使用的另一种方法是使用临时指针变量来迭代数组。
int* iter = data;
for (int i = 0; i < size; i++. ++iter)
{
*iter = rand() % 100 + 1;
cout << setw(5) << right << *iter;
...
}
这可确保不会丢失原始指针,这是能够释放内存所必需的。
PS可能有其他错误,也可能没有,但我在快速浏览您的代码后注意到了上述问题。
移动指针
data++;
和
data--;
主要。您还可以执行其他操作,但您的教师要求递增和递减。
所以
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
成为
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
请注意,只有一个data++
,它是第二次使用data
。你应该能够弄清楚为什么。
重置指针
最简单和最明显的是
int*reset = data;
然后你可以随心所欲地data
,当你想重置时,
data = reset;
所以上面的循环最终看起来像
int*reset = data;
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
data = reset;
但。。。您还可以将逻辑分离到函数中,并利用按值传递
void fill(int * data,
int size)
{
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
main
的相关部分现在看起来像
data = new int[size];
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
cout << "This is just the test to see if the pointer is successfully creating the array" << endl;
fill(data, size);
// Reset "data" to point to the beginning of the array
"等一下!"你在想。 "克罗姆的名义int * data
如何按价值传递?这是一个<咒骂删除>指针!指向的数据通过引用传递,但指针本身按值传递。data
填写是main
中data
的副本。fill
中的所有data++
都发生在副本上,因此main
中的data
仍然指向您离开它的位置。咒骂删除>
无需重置,并且通过将部分职责剥离到自己的简单且可独立测试的功能中,简化了main
的职责。在我看来,让一切尽可能简单、小巧和愚蠢是值得的。
- 需要帮助设置在C++中使用的Potrace
- 在指针的帮助下,文本文件中单词的频率
- 在决定是通过参考还是通过价值时,尺寸真的是一个问题吗
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 如何在Qbutton的帮助下更改Q对话框的宽度
- 需要帮助将结构数组传递给函数
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 字节真的是最小可寻址单元吗
- 需要帮助在 c++ 中将字符串转换为字符 ----错误 "const char *" 类型的值不能用于初始化 "char" 类型的实体
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 如何在 std::vector 中找到<bool>哪些索引是真的?
- 有人可以帮助我处理正则表达式吗?
- C++调用具有 *this 属性的单个帮助程序函数
- C++:需要帮助了解运算符重载错误
- std::string 的对象真的可以移动吗?
- 需要以下代码的帮助,下面的代码有什么问题
- 在这种情况下,我真的复制了字节还是复制了字符?
- C++指针/数组(我现在完全困惑,真的需要帮助)
- 简而言之,我真的很纠结语法,有人可以帮助我解决这个问题
- 真的需要一些帮助,第一个编程项目