C

时间:2017-01-25 21:00:15

标签: c pointers stack malloc heap

我目前正在学习C,而且我对内存布局和指针感到困惑。

在下面的代码中,我理解数组是在堆栈上分配的。

#include <stdio.h>

int main () {
   int x[4];
   x[0] = 3; x[1] = 2; x[2] = 1;
   printf("%p\n",x);
   printf("%p\n", &x);
}

我的问题是,为什么两个打印调用输出相同的值?

我尝试使用malloc(在堆上分配)的类似代码段,并且值不同。

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

int main () {
   int *x = malloc(sizeof(int) * 4);
   x[0] = 3; x[1] = 2; x[2] = 1;
   printf("%p\n",x);
   printf("%p\n", &x);
}

3 个答案:

答案 0 :(得分:3)

您的两个打印调用打印相同的值,因为一个尝试打印数组,该数组衰减到指向数组的指针,另一个打印数组的地址。指向数组的指针包含数组的地址,因此它们的值相同。

在第二种情况下,一个打印x的值,另一个打印x的地址。由于x是指向您分配的内存块的指针,因此它们必须是不同的值。

所以在第一种情况下,你所拥有的只是一个数组(x)。在第二种情况下,您有一个已分配的内存块(未命名)和一个指向该已分配块(x)的指针。

答案 1 :(得分:2)

原因在于,与您可能教过的不同,数组不是指针。在某些情况下,C 中的数组会衰减成指针 1 。将数组传递给函数时,它会衰减为指向第一个元素的指针。该元素的地址与整个数组的地址相同(地址始终是对象的第一个字节)。

你从malloc获得的不是一个数组,而是一块内存的地址。您将地址分配给指针。但指针和块是单独的实体。因此,打印指针的值而不是其地址会产生不同的结果。

(1)Decay是一种隐式类型转换的奇特术语。当数组表达式用于大多数位置时(例如作为参数传递给需要指针的函数),它会自动变成指向其第一个元素的指针。 &#34;衰变&#34;是因为你丢失了类型信息,即数组大小。

答案 2 :(得分:2)

或许可以令人惊讶的是,人们确实可以获取整个数组的地址,部分原因是人们不需要经常使用。从某种意义上说,数组是一个对象,它有一个地址,它是第一个字节的地址。与所有对象一样,地址是通过地址运算符&获得的。

数组的第一个元素(与其所有元素一样)也有一个地址,它是第一个字节的地址。指向其第一个元素的指针是将数组类型作为参数传递给函数时“调整”的内容。

这两个字节是相同的,并且具有相同的地址。但是它们有不同的类型,如果你向它们添加1并再次打印它们就会变得很明显。

相反,指针y是它自己的独特对象(大小可能是4或8个字节;足以在其中存储地址)。与任何对象一样,它具有可以使用&运算符获取的地址。也许令人困惑的是,它还包含一个地址,在这种情况下是数组第一个字节的地址。这两个当然不相等:指针对象驻留在与数组不同的位置(即在堆栈旁边,即使Olaf不喜欢它)。

次要评论:您使用%p打印指针,这很好。如果你这样做,你应该严格地说出你打印的指针到一个无效指针:printf("%p\n", (void *)x);