我想问一下关于char * buffer的内存分配问题; buffer = malloc(5);和char缓冲区[5]。
我的测试代码如下:]
#include <stdio.h>
void echo1();
void echo2();
int main() {
echo1();
printf("\n");
echo2();
printf("Back to Main \n");
return 0;
}
void echo1() {
int i;
unsigned long addr;
char *buffer;
printf("[Echo1] Buffer : %p \n", buffer);
printf("[Echo1] &Buffer : %p \n", &buffer);
buffer = malloc(5);
printf("[Echo1] &Buffer : %p \n", &buffer);
printf("[Echo1] Buffer : %p \n", buffer);
for (i = 0; i < 5; i++) {
buffer[i] = 'A';
}
printf("[Echo1] Buffer[] : %s \n", buffer);
addr = &buffer;
printf("[Echo1] *Buffer : %p \n", *buffer);
printf("[Echo1] addr : %p \n", addr);
printf("[Echo1] &addr : %p \n", &addr);
}
void echo2() {
int i;
unsigned long addr;
char buffer[5];
printf("[Echo2] Buffer : %p \n", buffer);
printf("[Echo2] &Buffer : %p \n", &buffer);
for (i = 0; i < 5; i++) {
buffer[i] = 'A';
}
printf("[Echo2] Buffer[] : %s \n", buffer);
addr = &buffer;
printf("[Echo2] *Buffer : %p \n", *buffer);
printf("[Echo2] addr : %p \n", addr);
printf("[Echo2] &addr : %p \n", &addr);
}
我在ubuntu上通过输入gcc test.c -o test -m32(我使用64机器)来编译它。下图显示了结果。
我想我理解了echo1()的情况(除了为什么addr在缓冲区之上),并且做了一个数字来显示内存中发生了什么。
但我不知道echo2()案例中发生了什么。
所以我想问下列问题:
非常感谢。
答案 0 :(得分:4)
为什么一样?
堆栈中数组的地址及其第一个元素的地址是相同的。不同之处在于增加了结果指针,因为它们具有不同的大小。
介于两者之间的是什么?
指针的地址是堆栈地址,而malloc()
返回并存储在指针中的地址来自堆。
注意:您的代码还会显示许多未定义行为的来源,例如
*Buffer
说明符打印"%p"
。unsigned long addr
未初始化且使用"%p"
说明符,两者都会调用未定义的行为。null
说明符打印非"%s"
终止的数组。所以你不能指望echo2()
中的给定行为以及整个程序中的一般行为。
答案 1 :(得分:2)
任何人都可以帮我理解发生的事情 ehco2()?
这整个问题的最佳答案是使用gcc的-O0标志来生成未优化的代码,并在调试器中运行它或者使用-S来查看与其生成的代码相对应的程序集。
- 在echo1()中,我在缓冲区之前声明了addr,为什么addr被放在堆栈中的缓冲区之上? (因为堆栈向上移动,不应该 程序首先推送addr,然后将缓冲区推到它上面?)
醇>
但是在将一个值分配给缓冲区之前,你没有为addr赋值,因此编译器不必为它分配内存,直到稍后。
对于其他一些观点,请参阅iharob的好答案。
答案 2 :(得分:1)
在echo1()中,我在缓冲区之前声明了addr,为什么addr被放在堆栈中的缓冲区之上?
因为编译器不必按照它们声明的顺序将自动变量放入堆栈,并且显然选择不这样做。 (实际上,它不必将它们放在堆栈中 - 如果它们适合寄存器,它可以将它们放入寄存器中。)
在echo2()中,为什么buffer和&amp; buffer给出相同的值?这不是指缓冲区指向自身吗?
这意味着buffer
是一个数组,并且在大多数情况下,表达式buffer
求值为指向buffer
的第一个元素的指针,即它计算为{{1} }和'&amp; buffer`求值为指向数组的指针 - 但数组的地址与数组的第一个元素的地址相同。
&buffer[0]
和buffer
具有不同的数据类型(“指向&buffer
”与“指向5 char
s的数组的指针”)。
在echo2()中,addr的地址和addr的内容(缓冲区的地址)之间用12个字节分隔,存储在它们中的是什么?
无论编译器决定将其置于堆栈帧中。堆栈帧的布局不受C(或C ++)程序员的直接控制。也许编译器决定使跟随数组的地址处于4字节边界,而不是将第一个元素放在4字节边界上。也许,因为你没有打开优化编译,它没有将char
放入寄存器,而是把它放在堆栈上。
C不是一种编程语言,它指定自动变量和堆栈上的位置之间的严格映射;编译器可以自由地将变量放在它选择的任何地方(如上所述,如果可能的话,包括寄存器)。