将指针元素赋值到数组中的另一个指针元素是什么意思?

What does assignment of a pointer element to another pointer element in the array mean?

提问人:Yan Jin 提问时间:8/9/2019 最后编辑:Vlad from MoscowYan Jin 更新时间:8/10/2019 访问量:94

问:

我不太明白将一个指针分配给另一个指针是什么意思?这里 **p 是指针/2D 数组的数组,然后 p[0] 分配给 p[1],它们是否都指向同一个地址?

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int i,j;
    int **p = (int **)malloc(2 * sizeof(int *));
    p[0] = (int *)malloc(2 * sizeof(int));
    p[1] = p[0];
    for(i = 0; i < 2; i++)
        for(j = 0; j < 2; j++)
            p[i][j] = i + j;
    printf("%d",p[0][0]);
    return 0;
}

我预计输出为 0,但实际上是 1,为什么?

C for 循环 指针 值运算符

评论

1赞 Serge 8/9/2019
p是指针数组。因此,您将指针从 p[0] 分配给 p[1]。因此,它们都指向同一个区域,大小为 2 个整数。对我来说看起来一团糟。
0赞 Ôrel 8/9/2019
p 不是数组(或你说的 **p),指针和数组有很大不同

答:

2赞 Vlad from Moscow 8/9/2019 #1

两个指针在表达式语句后具有相同的值p[0]p[1]

p[1] = p[0];

因此,在使用表达式的情况下,可以将其替换为表达式,因为两个表达式具有相同的值,反之亦然。p[1]p[0]

在这个循环中

for(i = 0; i < 2; i++)
    for(j = 0; j < 2; j++)
        p[i][j] = i + j;

when 等于 和 等于 (假设与 相同。所以等于,等于那个是。i1j0p[1]p[0]p[1][0]p[0][0]i + j1

事实上,这个循环

for (i = 0; i < 2; i++)
    for (j = 0; j < 2; j++)
        p[i][j] = i + j;

等价于循环

for (i = 0; i < 2; i++)
    for (j = 0; j < 2; j++)
        p[0][j] = i + j;

因此,外部循环的第二次迭代将重写存储在第一次迭代中和之后的值。p[0][0]p[0][1]

在第二次迭代中,我们得到的是相等的。因此,在 [0, 1] 范围内,我们有i1j

p[0][0] = i + j (when i == 1 and j == 0 ) = 1

p[0][1] = i + j (when i == 1 and j == 1 ) = 2
0赞 John Bollinger 8/9/2019 #2

我不太明白将一个指针分配给是什么意思 另一个指针?这里 **p 是指针/2D 数组的数组,然后是 p[0] 被分配给 p[1],它们是否都指向同一个地址?

是的。但是,从概念上讲,忽略 和 值的重要性(这些值是指针,以及这些值指向什么)可能更有用,而将重点放在赋值后它们的值相同的事实上。然后这些值指向同一事物,由此而来。p[0]p[1]

请注意,我特意选择了区分存储位置的指示符(例如“”)和这些位置的内容(它们的值)的措辞。我们经常使用模糊区别的语言,因为以这种方式精确地说话很麻烦,但你必须在脑海中保持这种区别。从形式上讲,指针不是表达式,甚至不是它指定的存储位置,而是存储在那里的值。赋值运算符将该值复制到另一个存储位置,因此,如果根据相同的数据类型解释该其他存储位置的内容,则它们与原始值具有相同的含义。p[1]p[1]

我预计输出为 0,但实际上是 1,为什么?

因为在设置之后,表达式指定了相同的对象。因此,在赋值后,可以从 或 中读回结果值 (1)。p[1] = p[0]p[1][0]p[0][0]p[1][0] = 1 + 0p[1][0]p[0][0]

0赞 Steve Summit 8/9/2019 #3

它们都指向同一个地址吗?

是的。

这是对程序的修改,应该更清楚地说明这一点:

int main(void) {
    int i,j;
    int **p = (int **)malloc(2 * sizeof(int *));
    p[0] = (int *)malloc(2 * sizeof(int));
    p[1] = p[0];
    for(i = 0; i < 2; i++)
        for(j = 0; j < 2; j++)
            p[i][j] = i + j;
    for(i = 0; i < 2; i++) {
        printf("%d (%p)\t", i, p[i]);
        for(j = 0; j < 2; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    return 0;
}

在这里,我们打印出指针值 和 ,以及“二维”数组的所有四个单元格——除了,是的,实际上只有两个单元格,对两行中的每一行都执行双重任务。在我的系统上,这打印出来了p[0]p[1]

0 (0x7f92ca402710)  1 2 
1 (0x7f92ca402710)  1 2 

您可以清楚地看到这两个指针是相同的。

在记忆中,我们可以把它想象成这样:

   +-------+
p: |   *   |
   +---|---+
       |
       v
   +-------+           +---+---+
   |   *----------+--->| 1 | 2 |
   +-------+     /     +---+---+
   |   *--------'
   +-------+

另一方面,如果您打了三次电话,而不是两次,如下所示:malloc

    int **p = (int **)malloc(2 * sizeof(int *));
    p[0] = (int *)malloc(2 * sizeof(int));
    p[1] = (int *)malloc(2 * sizeof(int));

你会得到一个更像这样的打印输出:

0 (0x7fb747402710)  0 1 
1 (0x7fb747402720)  1 2 

你会在记忆中得到一张图片,如下所示:

   +-------+
p: |   *   |
   +---|---+
       |
       v
   +-------+           +---+---+
   |   *-------------->| 0 | 1 |
   +-------+           +---+---+
   |   *--------.
   +-------+     \     +---+---+
                  '--->| 1 | 2 |
                       +---+---+