1
#include<stdlib.h>

int main()
{
   char ch, *p1, **p2, ***p3, ****p4;
   ch='a';
   p1=&ch;
   printf("%c %d %c\n", ch, p1, *p1);

   p2=&p1;
   printf("%d %d %c\n", p2, *p2, **p2);

   p3=&p2;
   printf("%d %d %d %c\n", p3, *p3, **p3, ***p3);

   p4=&p3;
   printf("%d %d %d %d %c\n", p4, *p4, **p4, ***p4, ****p4);
}

输出看起来像:

a 298923415 a                                                                                                                 
298923416 298923415 a                                                                                                          
298923424 298923416 298923415 a                                                                                                
298923432 298923424 298923416 298923415 a           

为什么对于 p1 和 p2 分配的地址以 1 递增,而对于 p3 和 p4 分配的地址以 8 递增?

寻址是否遵循任何模式,因为它们被分配在连续的内存位置?

4

3 回答 3

4

在这种情况下,您的对象在内存中按顺序排列。他们不一定非要如此。编译器可以根据需要在内存中布局。

在您的情况下,您的记忆看起来像这样:

298923415 +-----------+
          |    'a'    | ch
298923416 +-----------+
          |           |
          |           |
          |           |
          | 298923415 | p1
          |           |
          |           |
          |           |
          |           |
298923124 +-----------+
          |           |
          |           |
          |           |
          | 298923416 | p2
          |           |
          |           |
          |           |
          |           |
298923132 +-----------+
          |           |
          |           |
          |           |
          | 298923424 | p3
          |           |
          |           |
          |           |
          |           |
298923140 +-----------+
          |           |
          |           |
          |           |
          | 298923432 | p4
          |           |
          |           |
          |           |
          |           |
          +-----------+

请记住,在大多数现代系统上,指向对象的类型只是整数,其工作是存储内存地址。在您的系统上(我猜是 x86_64)指针的大小为 8 个字节。不过,这完全取决于系统。例如,一个指针在 32 位 x86 系统上是 4 字节,并且还有很多其他平台具有奇异的指针大小。

a 的大小也char被定义为 1,因此第一个指针位于 之后的一个字节ch

于 2018-10-08T08:27:55.733 回答
2

发生什么取决于编译器做了什么。语言本身没有保证,但通常它们在堆栈上彼此靠近。这里有一个很好的例子来说明它如何在 x86-64(你的 PC 可能有)上工作:

该示例使用以下代码:

long myfunc(long a, long b, long c, long d,
        long e, long f, long g, long h)
{
    long xx = a * b * c * d * e * f * g * h;
    long yy = a + b + c + d + e + f + g + h;
    long zz = utilfunc(xx, yy, xx % yy);
    return zz + 20;
}

x86-64 上的堆栈帧布局

与您的问题相关的是xx yy zz部分。就像您的问题一样,这些是在堆栈上声明的变量。正如您在图像上看到的,它们彼此相邻放置。xx有最高的地址,然后来yy,然后zz。为了说明这一点,您可以做(&xx)[-1]并且可能得到 的值yy。请注意,这是未定义的行为,只有在我们知道编译器对它做什么时才有效,在任何不同的设置中它可能不起作用,可能导致错误和程序崩溃(或更糟)。

另外,请考虑这篇关于内存对齐的文章,这可能会导致数据之间出现间隙,以使其运行得更快。

于 2018-10-08T08:27:45.810 回答
1

您正在以错误的方式阅读输出。ch分配在地址 298923415。指针p1分配在下一个字节 298923416。从那里开始,每个指针分配 8 个字节的倍数,这表明是 64 位系统。

这仅仅意味着编译器的分配char方式与指针不同。这是因为char是 1 个字节,没有对齐要求,所以可能会放在一个未对齐的地址。

一般来说,编译器可以自由地在它喜欢的地方分配变量,你不能保证。如果没有考虑到特定的系统,讨论堆栈内存布局是没有意义的。

将您的示例修复为更清晰的内容,结果并不引人注目:

#include <stdio.h>

int main (void)
{
   char ch = 'a';
   char*    p1 = &ch;
   char**   p2 = &p1; 
   char***  p3 = &p2;
   char**** p4 = &p3;
   printf("ch:\t%p\n", (void*)p1);
   printf("p1:\t%p\n", (void*)p2);
   printf("p2:\t%p\n", (void*)p3);
   printf("p3:\t%p\n", (void*)p4);
   printf("p4:\t%p\n", (void*)&p4);
}

输出(x64 Windows PC,十六进制地址):

ch:     000000000022FE4F
p1:     000000000022FE40
p2:     000000000022FE38
p3:     000000000022FE30
p4:     000000000022FE28
于 2018-10-08T08:42:21.590 回答