【问题标题】:Address of an array changed despite using a pointer to navigation尽管使用了指向导航的指针,但数组的地址发生了变化
【发布时间】:2018-01-15 23:58:57
【问题描述】:

我想更好地理解指针算法。我知道如何用索引重写它,但我想了解这里的指针问题。

int     main(int argc, char **argv)
{
    int i;
    char **tmp;

    i=1;
    argv++;
    tmp = argv; // address of first element of array is:  e2b9f187
    printf("ptr: %x **ptr: %x\n", argv, &(**argv));
    printf("tmp: %x **tmp: %x\n", tmp, &(**tmp));
    while (--argc)
    {
        while(**tmp)
            (*tmp)++;
        printf("step %x ptr %x **ptr %x\n", i, argv, &(**argv));
        printf("step %x tmp %x **tmp %x\n", i, tmp, &(**tmp));
        i++;
        tmp++;
    } 
}

/* 在第一次迭代中,两个地址都改变了:**tmp: e2b9f18b**argv: e2b9f18b,在下一次迭代中只改变了*tmp 的位置。 我的问题是为什么尽管使用了指针,**argv 的地址却发生了变化。 提前致谢。

【问题讨论】:

  • 您只复制了argv,而不是**argv。因此,您将获得 2 个指向同一内存的指针(*argv**argv):如果一个指针更改了该内存地址,另一个指针(查看同一地址)也会看到该更改。
  • 如果你去掉一层间接性(让事情更简单一些),你可以简单地在一张纸上画东西,用正方形作为内存地址:你会得到箭头(从你的两个指针)指向同一个正方形。
  • @Evert。 Thx,我明白这一点。但是这里我既不使用 *argv 也不使用 **argv,那为什么它们会改变呢?
  • 那你没看懂重点:你改变的是**tmp指向的值,而**argv也恰好指向了这个值。
  • 您 (argv) 指向一辆白色 (&(**argv)) 的汽车 (**argv)。你要求你的朋友也这样做(tmp = argv),即指向同一辆车(因此,**tmp == **argv);他们还看到这辆车是白色的 (&(**tmp))。现在您的朋友将汽车涂成彩虹色((*tmp)++ 或类似颜色),而您的朋友(&(**tmp))看到的汽车颜色实际上是彩虹的所有颜色。你,作为argv,现在也看到了彩虹色的汽车 (&(**argv)),而不是白色。

标签: c arrays pointers memory-address pointer-arithmetic


【解决方案1】:

我的问题是为什么尽管使用了指针,但 **argv 的地址却发生了变化。

要理解这一点,首先需要了解双指针(pointer to pointer)的概念。

让我们考虑一个例子:

#include <stdio.h>

int main()
{   
    int X = 1; 
    int *ptr1, *ptr2;

    ptr1 = &X;
    ptr2 = ptr1;

    printf ("ptr1 : %p, ptr2 : %p\n", ptr1, ptr2);
    printf ("*ptr1 : %d, *ptr2 : %d\n", *ptr1, *ptr2);

    (*ptr1)++;
    printf ("ptr1 : %p, ptr2 : %p\n", ptr1, ptr2);
    printf ("*ptr1 : %d, *ptr2 : %d\n", *ptr1, *ptr2);

    return 0;
}

在示例中,我们使用两个指针ptr1ptr2,它们都指向变量X 的地址。 内存中的视图类似于:

                 +----------------+
            ptr1 | 0x7ffeeb1c4b48 |
                 +----------------+
                              |
                              |
                            X v
     +----------------+     +---+
ptr2 | 0x7ffeeb1c4b48 |---->| 1 |
     +----------------+     +---+

您通过ptr1X的值所做的任何更改,当X的内存位置的值将通过ptr2访问时,更改的值将反映,反之亦然。

The output of program is:
ptr1 : 0x7ffeeb1c4b48, ptr2 : 0x7ffeeb1c4b48
*ptr1 : 1, *ptr2 : 1
ptr1 : 0x7ffeeb1c4b48, ptr2 : 0x7ffeeb1c4b48
*ptr1 : 2, *ptr2 : 2

现在,让我们修改一下程序,引入双指针:

#include <stdio.h>
int main()
{
    int X = 1;
    int *ptr1;

    ptr1 = &X;
    printf ("ptr1 : %p\n", ptr1);

    int **ptr3, **ptr4;

    ptr3 = &ptr1;
    ptr4 = ptr3;

    printf ("ptr3 : %p, ptr4 : %p\n", ptr3, ptr4);
    printf ("*ptr3 : %p, *ptr4 : %p\n", *ptr3, *ptr4);
    printf ("**ptr3 : %d, **ptr4 : %d\n", **ptr3, **ptr4);

    (*ptr3)++;
    printf ("ptr1 : %p, *ptr1: %d\n", ptr1, *ptr1);
    printf ("ptr3 : %p, ptr4 : %p\n", ptr3, ptr4);
    printf ("*ptr3 : %p, *ptr4 : %p\n", *ptr3, *ptr4);
    printf ("**ptr3 : %d, **ptr4 : %d\n", **ptr3, **ptr4);

    return 0;
}

在程序中,声明:

(*ptr3)++;

将更改ptr1 的值(地址),ptr3ptr4 都指向。因此,在此之后,当您访问 *ptr4**ptr4 时,更改的值将被反映,类似于第一个示例中的单指针 ptr2

内存中的视图现在将类似于:

                           ptr1                       X
     +---------------+      +----------------+      +---+
ptr3 | 0x7ffeebc3fb40|----->| 0x7ffeebc3fb48 |----->| 1 |
     +---------------+      +----------------+      +---+
                                ^
                                |
                    +----------------+
               ptr4 | 0x7ffeebc3fb40 |
                    +----------------+

程序输出为:

ptr1 : 0x7ffeeab5db48
ptr3 : 0x7ffeeab5db40, ptr4 : 0x7ffeeab5db40
*ptr3 : 0x7ffeeab5db48, *ptr4 : 0x7ffeeab5db48
**ptr3 : 1, **ptr4 : 1
ptr1 : 0x7ffeeab5db4c, *ptr1: 0      <=============== ptr1 now pointing to different mem location
ptr3 : 0x7ffeeab5db40, ptr4 : 0x7ffeeab5db40
*ptr3 : 0x7ffeeab5db4c, *ptr4 : 0x7ffeeab5db4c
**ptr3 : 0, **ptr4 : 0

这里可以看到ptr1指向的地址因为(*ptr3)++而改变了。

这就是你的程序中发生的事情。在你的程序中,你正在做:

        while(**tmp)
        (*tmp)++;

这改变了tmpargv 指向的地址的值。 这就是为什么当您访问&amp;(**argv) 的地址时,您会得到与初始值不同的值。

另外,在外部while 循环中,你正在做:

tmp++;

因此,在第一次迭代之后,tmpargv 不再指向同一个地址。 在进一步的迭代中,您将获得不同的 &amp;(**tmp) 值但相同的 &amp;(**argv) 值。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多