c - c语言在内存中存储数组的机制是什么

标签 c arrays pointers

我正在学习c语言,练习自己。我想知道 c 如何为数组分配内存。因为我有这样的代码:

#include<stdio.h>

int main(void)
{
     char a[] = {1,2,3,4,5,6,7,8,9,10};
     int i = 578;
     char * p1;
     int * p2;
     printf("\nAddress of pointer p1 : %p", &p1);
     printf("\nAddress of pointer p2 : %p", &p2);
     printf("\nAddress of int i : %p", &i);
     p1 = 0x0028FF34;
     p2 = 0x0028FF35;
     /* Print the Addresses */
     for (i = 0; i < 10; i++)
     {
          printf("\nAddress of a[%d] : %p", i, (void *) &a[i]);
     }
     printf("\nThe content in the address 0x0028FF34: %x", *p1);
     printf("\nThe content in the address 0x0028FF35: %x", *p2);
     return 0;
}

在我的计算机上运行此代码会得到如下输出

Address of pointer p1 : 0028FF2C
Address of pointer p2 : 0028FF28
Address of int i : 0028FF30
Address of a[0] : 0028FF36
Address of a[1] : 0028FF37
Address of a[2] : 0028FF38
Address of a[3] : 0028FF39
Address of a[4] : 0028FF3A
Address of a[5] : 0028FF3B
Address of a[6] : 0028FF3C
Address of a[7] : 0028FF3D
Address of a[8] : 0028FF3E
Address of a[9] : 0028FF3F
The character content in the addresss 0x0028FF34: ffffff80
The character content in the addresss 0x0028FF35: 3020100

字符指针p占32位,即4个字节。因此,指针 p2 到指针 p1 的距离是 4 个字节长,指针 p1 到 int i 的距离也是如此。在我的系统中 int i 也是 4 个字节。在我看来,int i 与数组 a[] 的距离应该是 4 个字节。数组a[]的起始地址应该是0028FF34,为什么是0028FF36?

0028FF34和0028FF35的内容是什么意思? 0028FF34 指向一个字符,输出为 ffffff80,0028ff35 指向一个 int,输出为 3020100。

最佳答案

您想知道 C 如何为数组和其他数据类型分配内存。好的。嗯,这取决于数组(或其他变量)的定义方式。在您的例子中,您已将它们定义为自动分配的(“本地”)变量,因此它们存储在 C 运行时堆栈中。 (从技术上讲,可以有另一种自动存储变量的分配机制,但实际上大多数系统都使用运行时堆栈。)如果您在 int main(void) 上面的几行中定义了数组和其他变量 code>,它们将是“全局变量”,并且将通过外部链接静态分配,因此它们对其他编译单元(其他 .c 文件)可见。如果将关键字static放在它们前面,它们仍然会被静态分配,但它们的链接将是内部的,因此它们对其他编译单元(.c 文件)不可见。无论您在函数体内部还是外部定义变量,最后一部分都是如此;如果您在函数体外部将它们定义为static,则它们可供同一编译单元中的其他函数使用;如果您在函数体内将它们定义为static,则编译器只允许该函数访问它们;事实上,它们仅在定义它们的范围内可见。

至于它们的具体放置位置,编译器/链接器可以自由地将它们放置在其选择的存储类区域内的任何位置;在这种情况下,编译器将它们放置在运行时堆栈上,但它们的顺序和相对位置不是由语言定义的,因此编译器可以自由地以任何它喜欢的方式排列它们。

通常会在变量之间分配填充,以确保它们对齐,以便它们从数据大小的最佳边界开始,因为(由于硬件问题)在与其匹配的字节边界上访问数据通常会更快数据宽度,这正是这里发生的情况。您可能会说,“但是 i 以 4 字节边界结束,并且 a[] 没有对齐要求,那为什么要在 i 之后添加填充呢? 在分配a[] 之前?”但这是因为您正在考虑按内存地址递增的顺序进行分配。您是否注意到您的变量似乎是“向后”分配在内存中的?事实上他们不是!在大多数系统上,堆栈在内存中从高地址向低地址增长。考虑到这一点,很明显,分配的变量集中的第一个变量是 a[],后面是 i(位于较低的地址)。因为a[]后面的字节地址不是4的倍数,所以编译器在分配i之前,添加了2个字节的填充!

现在,至于您在 0x0028FF34 和 0x0028FF35 处读取的值:无论是什么,都只是上次写入这些地址的内容留下的垃圾。 0x0028FF34 处的字节是 0x80,它通过 ... varargs 作为整数传递给 'printf()',并且在您的系统上 char 必须经过签名,因此当它被提升为经过符号扩展的整数,并且由于 0x80 的高位为 1,因此结果值为 0xFFFFFF80。您读取的整数 0x0028FF35 显示该地址处的字节是 0x00,其他字节是 03、02 和 01,您应该注意到它们是 a[] 的前 3 个字节。我们还可以从中看出您的系统是小尾数法(如 x86),因为整数的高位字节位于较高字节可寻址位置。

关于c - c语言在内存中存储数组的机制是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58456339/

相关文章:

c - 使用 CMake 和 Clion 构建 C 项目

c - 使用 gethostbyname 的 DNS

c - Eclipse 中不兼容指针类型的赋值

c++ - 奇怪的 C 堆栈内存覆盖

c - 如何在不知道 root 的情况下检测到程序关闭时重新启动程序?

python - 传递给线程时求和 numpy.ndarray 失败

arrays - 如何在 scala 中比较两个数组?

python - 有效地按降序对numpy数组进行排序?

c++ - 关于传递给函数后指针重用的问题

C编程动态初始化二维数组