所以这就是我为此提出的建议。我目前无法弄清楚如何将reverseArray功能放入主...如果我只是将代码复制并粘贴到其中,它每次运行时都会崩溃...我不会...我知道它为什么会导致它崩溃或任何事情。感谢迄今为止帮助我的每一个人。
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;
}
}
答案 0 :(得分:3)
你可能无缘无故折磨自己,或者把头撞到砖墙上(别担心 - 我们都在那里......并且有瘀伤来证明这一点。)
首先,让我们从任何已分配的内存块开始,比如说:
int *a = new int[NELEM], ...
什么是a
? (一个指针 - 是的,但是对于什么?)它是一个指向内存块中起始地址的指针,大小为NELEM * sizeof *a
个字节。它是什么类型的指针? (int
)。每个int有多少字节? (一般4
)。
那么为什么指针的类型int
很重要? (好吧,它设置了控制指针算术在引用内存块时如何操作的类型大小),因为指针类型为int
,编译器知道a + 1
是{{} 1}}允许您引用内存块中的下一个值。
好的,但我为a + 4-bytes
分配了内存,我对a
的责任是什么?在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有2个职责:(1)始终保留指向块的起始地址的指针因此,(2)当不再需要时,它可以释放。
这对我意味着什么?这意味着,如果您不能简单地在声明a
的范围内增加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
中的a
与rev
中的原始指针有自己的(并且非常不同)地址。 / p>
(旁边......)你可以在main()
内声明第三个指针,例如
rev
然后在您的迭代和交换中使用 int *s = a, /* start pointer */
*e = a + size - 1; /* end pointer */
而不是s
,但没有任何需要。如果你更清楚你正在使用哪个指针,你可以自由地这样做。它只是另一个8字节(或x86上的4个字节),因此附加存储不是问题。
在一个简短的例子中,你可以做类似以下的事情:
a
示例使用/输出
#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++
提前了多少字节,并确保您确切知道指针指向的位置,并且事情应该开始落实到位。
如果您在弄清楚指针发生了什么问题时,请拉出一张8.5 x 11的纸和一支2号铅笔然后将其画出来 - 在每次迭代时填写你的指针指针指向等等。 - 它确实有帮助。一旦你绘制了足够的图表,做了足够的链接列表,堆栈等等......你现在就不需要这篇论文了(你仍然需要它 - 所以保持方便)
在[{1}}中使用函数
进行反转在回复您的评论时,当您查看for (i = 0; i < size; i++) p[i]
时,您已经宣布了另一个指针main()
。因此,您只需将其用作开始指针,并从main()
函数添加p
作为结束指针。一个简单的实现是:
e
(相同的输出)
仔细看看,如果您有其他问题,请告诉我。
答案 1 :(得分:1)
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 可能还有其他错误,但在快速浏览一下代码后,我注意到了上述问题。
答案 2 :(得分:1)
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
&#34;等一下!&#34;你在想什么。 &#34; Crom的名字int * data
如何通过值传递?这是&lt; expletive deleted&gt;指针!&#34;指向的数据通过引用传递,但指针本身按值传递。填充中的data
是data
中main
的副本。 data++
fill
中的所有data
都发生在副本中,因此main
中的main
仍指向您离开的位置。
不需要重置和您已将部分内容分解为自己简单且可独立测试的功能,从而简化了{{1}}的职责。在我看来,保持一切尽可能简单,小巧和愚蠢是比得上比特币的重量。