【问题标题】:Flipping an array using pointers使用指针翻转数组
【发布时间】:2015-04-20 17:29:05
【问题描述】:
#include <iostream>
using namespace std;

int* flipArray(int input[], int n)
{
    int output[n];
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
    {
        output[pos++] = input[i];
    }
    int* p = output;
    for (int k = 0; k < n; k++)
        cout << *p-k << endl << endl;
    return p;
}

int main()
{
    const int SIZE = 5;
    int firstArray[SIZE];
    for (int n = 0; n < SIZE; n++)
    {
        firstArray[n] = n+1;
    }
    int* a;
    a = flipArray(firstArray, SIZE);
    for (int j = 0; j < SIZE; j++)
        cout << *a-j << endl;

    cout << endl;
    cout << *a << '\t' << *a+1 << '\t' << *a+2;
    return 0;
}

我正在尝试使用返回指针的函数来翻转 firstArray,但我很难理解使用指针访问索引的工作原理。

这就是我感到困惑的原因: 在函数flipArray中,如下for循环:

for (int k = 0; k < n; k++)
    cout << *p-k << ' ';

将“5 4 3 2 1”打印到控制台。我的理解是,我应该使用*(p+k) 而不是*(p-k) 访问向量的元素。如果我打印*(p+k),“5 6 7 8 9”将打印到控制台。如果我打印不带指针的数组并使用 k 作为索引位置,则会将“5 4 3 2 1”打印到控制台。

然而,在我的 main 函数中,*a 的值是从 flipArray 函数分配的指针 p,我没有得到相同的结果:

for (int j = 0; j < SIZE; j++)
    cout << *a-j << endl;

打印 5 0 -1 -2 -3 到控制台,然后

    for (int j = 0; j < SIZE; j++)
    cout << *a+j << endl;

打印 5 2 3 4 5 到控制台。

另外,我认为*p的指针位置和*a的位置指针应该是一样的!但是当我在函数中打印地址&amp;p时,我得到了0x28fde0的位置,当我在main中打印&amp;a的地址时,我得到了0x28fedc的位置。当然,这些都是在同一次运行中完成的。

谁能告诉我我误入歧途了?谢谢!


感谢大家提供的信息丰富的答案。

我已经更新了我的解决方案,现在它正在返回我所期望的结果。我有一个关于内存泄漏以及何时需要删除指针的新问题。

int* flipArray(int input[], int n)
{
    int* output = new int[n];
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
        output[pos++] = input[i];
    return output;
}

int main()
{
    const int SIZE = 5;
    int firstArray[SIZE];
    for (int n = 0; n < SIZE; n++)
    {
        firstArray[n] = n+1;
    }
    int* a;
    a = flipArray(firstArray, SIZE);
    for (int j = 0; j < SIZE; j++)
        cout << a[j] << " "; // can also be written as *(a+j), which is more prone to bugs
    delete [] a;
    return 0;
}

函数flipArray返回时指针输出会被删除吗?如果没有,我应该如何在返回的同时删除输出?在我的主函数中删除指针 a 是否与删除输出相同,因为它们指向相同的位置?

【问题讨论】:

  • 返回一个指向本地数组的指针 :(
  • 我没有收到*p-k。看起来应该是cout &lt;&lt; *p+k &lt;&lt; endl &lt;&lt; endl
  • 从堆栈中创建的不正确的变量返回地址
  • 考虑 std::reverse
  • 在你的新代码中,delete a; 应该是delete [] a;

标签: c++ c arrays pointers


【解决方案1】:

已经指出您的主要问题来自operator precedence*p - k 中的 * 运算符在 - 之前计算。这意味着 k 将从p 指向的 int 值中减去。

这是一个巨大的痛苦,这就是为什么大括号pointer[k] 被普遍使用的原因。在某些情况下,使用指针算法*(pointer + k) 更有意义,但它可能是错误的来源。

这里要注意一点:使用括号总是更好,即使您不确定是否需要它们。


你还有第二个问题:

在这里,您将堆栈上的output 声明为局部变量,然后您将返回output。当您返回上一个堆栈帧时,此指针将指向一个已释放的缓冲区:

int* flipArray(int input[], int n)
{
    int output[n]; // allocated on the stack
    int pos = 0;
    for (int i = n-1; i >= 0; i--)
    {
        output[pos++] = input[i];
    }
    int* p = output;
    for (int k = 0; k < n; k++)
        cout << *p-k << endl << endl;
    return p; // this stack frame ends.
}

这意味着如果重新分配缓冲区正在使用的空间,则可以覆盖缓冲区的内容。使用new在堆上分配:

int* output = new int[n];

使用完后,请务必在指针上调用delete

此错误甚至会在您的应用程序中出现安全漏洞,因此请确保您知道when to allocate on the heap in C++


更新:

问题:当这个函数返回时,数组仍然存在于内存中,它的位置存储在指针a中。返回值输出会删除它吗?如果没有,当我在主函数中完成指针 a 后删除它是否有同样的目的?

当您delete 指针时,指向该指针的内存被释放并且指针悬空。对已删除指针的引用指向技术上空闲的内存,这很糟糕。如果分配器库决定重用该空间,则将重新分配现在处于空闲空间中的缓冲区。这意味着您的缓冲区将失去所有数据完整性,并且其中的数据不可信。

一种常见的做法是在使用完NULL 后为其分配指针。这样你的程序就会崩溃,你就会知道你的错误在哪里:

int* p = new int[10];
...
delete p;
p = NULL;
...
p[0] = 0; // this will now crash because you are accessing NULL.

【讨论】:

  • 感谢您的回答,我认为概念变得更加清晰。现在我根据您的建议使用 new 关键字动态分配数组输出。当这个函数返回时,数组仍然存在于内存中,并且它的位置存储在指针a中。返回值输出会删除它吗?如果没有,当我在主函数中完成指针 a 时删除它是否有同样的目的?感谢您提供翔实的回答。
  • @greedIsGoodAha 如果您有一个与此问题不同的新问题,您应该发布一个新问题。如果与此问题有关,请编辑您现有的问题,我们将回答您的新问题。
【解决方案2】:
for (int k = 0; k < n; k++)
    cout << *p-k ;

我的理解是,我应该使用 *(p+k) 而不是 *(p-k) 访问向量的元素。

你的理解是对的。你不是在这里访问数组。p指向第一个元素5,每次从它减去k,得到5-05-15-2等等在其上等同于 filpped 数组。所以如果你想使用指针访问数组

for (int k = 0; k < n; k++)
    cout << *(p+k) ;// Note the paranthesis

【讨论】:

    【解决方案3】:
    for (int k = 0; k < n; k++)
        cout << *p-k << endl << endl;
    

    这段代码所做的与你想象的完全不同。

    *p - k 将被处理为

    *p = 5 - 0 = 5
    *p = 5 - 1 = 4
    

    等等不是*(p+k)*(p-k)

    为了您的理解:

    int a[5] = { 1,2,6,4,5};
    

    为了访问数组中的第三个元素

    a[2] = *(a+2)
    

    而不是

    *a + 2
    

    *(a + 2) = 6*a + 2 = 1 + 2 = 3

    注意不要返回指向局部变量的指针,否则会导致未定义的行为

    【讨论】:

      猜你喜欢
      • 2017-03-05
      • 1970-01-01
      • 2017-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多