【问题标题】:Integer Pointer Array整数指针数组
【发布时间】:2014-03-07 11:34:27
【问题描述】:

我已经开始了 C 的介绍性课程。我无法解释运行下面的代码得到的输出

./a.out 6

输出是:

Array A elements: 0 1 2 3 4 5 
Array B elements: 1 2 3 4 5 796830176

我认为代码在做什么: 执行 manup_array 时,各个 pointers 的每个 value 都会递增,但由于是 post-fix,只有在返回原始值后才会生效。

确实,当我们首先打印数组 A 时,我们得到 0 1 2 3 4 5(即在递增之前)。 随后当我们打印数组B时,自增生效,所以我们得到1 2 3 [...]

真正让我感到困惑的是为什么最后一个数字是 796830176。此外,在不同的计算机上运行它每次都会产生不同的最后一个数字,这表明指针寻址在某种程度上对此负责。

谁能给我解释一下?

注意: 如果我使用前缀运算符,每个数组的输出都是相同的(1 2 3 4 5 6)。这与我认为正在发生的事情一致-> 指针不会改变;仅更新值。

#include <stdio.h>
#include <stdlib.h>

void manup_array(int *array[], int n); // Forward declaration.

int main(int argc, char *argv[])
{
    // The size N of 2 arrays are the same; obtain them from cmd line.
    int N = atoi(argv[1]); // Convert from str to int in C.

    int arrayA[N];  // Declare integer array.
    int *arrayB[N]; // Declare integer pointer array.

    for (int i = 0; i < N; i++)
    {
        arrayA[i] = i;
        arrayB[i] = &arrayA[i]; // Assign address of each element in A to element in B.
    }

    manup_array(arrayB, N);

    printf("Array A elements: ");
    for (int i = 0; i < N; i++)
    {
        printf("%d ", arrayA[i]);
    }

    printf("\n");

    printf("Array B elements: ");
    for (int i = 0; i < N; i++)
    {
        printf("%d ", *arrayB[i]);
    }

    printf("\n");

    return 0;
}

void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        *array[i]++;
    }
}

【问题讨论】:

  • 这个是你写的还是作为你应该学习的例子传递的?在后者的情况下,向你的老师扔一个西红柿,然后忘记整件事;你不会在真正的应用程序中编写这样的代码......
  • []-operator 比 *-operator 绑定得更紧密。因此,请检查您的代码,了解两者都应用于同一个变量的位置,并检查它们的使用是否真的符合预期。

标签: c arrays pointers


【解决方案1】:

这真的是晦涩难懂的代码。是做什么的:

该函数将一个指针数组作为参数。由于该函数的参数类型为int *array[],因此array 的项目的任何更改都会影响调用者并改变arrayB

函数中有趣的部分是*array[i]++;。 C 中的运算符优先级规则表明 [] 的优先级高于后缀 ++,后缀 ++ 的优先级高于一元 *。

由于array 是一个指针数组,array[i] 给你一个指针。不是它指向的值。然后++ 递增指针 以指向main 的arrayA 中的下一项。

最后有一个*,它获取指针指向的内容,然后对它们不做任何事情。 * 是多余的,只是为了混淆读者。

所以回到main,你已经改变了arrayB的所有指针。 arrayB[0] 现在指向 arrayA[1] 等等。 arrayB 的最后一项将指向 arrayA 末尾之后的一项,因此对于最后一项,您越界访问数组并获得垃圾值。

【讨论】:

  • 经验教训可能是永远++ 与其他运算符混合。这是 C 中错误的一个非常常见的原因。
  • 谢谢!对发生的事情的出色解释;意识到我的想法是错误的。具体来说,我误以为我实际上是在增加指针指向的值,因为我没有考虑运算符的优先级。
  • 我在试图解释我所看到的内容时也弄错了后缀运算符的工作原理。这确实是一道课堂题。我们应该尝试得到如下输出: A: 0 1 2 3 4 5 B: 1 2 3 4 5 4732439 我们应该“将 [array B] 的每个元素增加 1”。
  • @kevinze 请注意,越界访问数组是一个错误,因为您调用了未定义的行为。你不能保证得到一个垃圾值——你可能会得到一个“分段错误”运行时崩溃,或者程序甚至可能完全失控。你的老师应该指出这一点,这样没有学生开始编写依赖于“获取垃圾值”的程序。
  • 谢谢!!事实上,我也确实遇到了一些分段错误。
【解决方案2】:
void manup_array(int *arr[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        int val = (*arr[0]); // get the value pointed to by the current value of arr
        val++;               // increment it
        *(arr[0]) = val;     // assign it back
        arr++;               // increase the pointer
    }
}

令人难以置信的迟钝,但它展示了您的意图以及您晦涩的代码如何混淆了运算符。

添加,使调试方式更容易!

【讨论】:

  • 除了,如果是他自己写的,他可能不打算增加指针。另外,您将arr++arr[i]++ 混淆了。此外,您还有一个错字 [0],其中 [i] 是有意的。
【解决方案3】:

manup_array() 增加指针,而不是预期的值。

修改 manup_array().

void manup_array(int *array[], int n) { // Take in B as input, then increase each elem by 1
    for (int i = 0; i < n; i++)
    {
        //*array[i]++;
        (*array[i])++;
    }
}

建议参考Pointer Arithmetic: ++*ptr or *ptr++?

【讨论】:

  • (*array[i])++; 应该没问题。这里的问题是 *array[i]++ 被读取为 *array[i] = *(array[i] + 1);,由于 c 使用的操作顺序。
  • @RedAlert 你能详细说明一下吗?
  • 你修改的manup_array()++被解析后转换为*array[i] = (*array[i]) = (*array[i]) + 1;,有点多余。
  • 我很确定 *array[i] = (*array[i])++; 是未定义的行为。您在同一操作中对array 进行了两次写入,中间没有序列点。无论如何,不​​要教人写那样的代码......
  • @Lundin 错误地添加了array[i] = (*array[i])++;。我觉得(*array[i])++; 可以胜任。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
  • 2019-10-27
  • 2017-07-16
  • 1970-01-01
相关资源
最近更新 更多