关于char * buffer和char buffer的内存分配[5]

时间:2016-01-28 01:38:33

标签: c ubuntu memory stack

我想问一下关于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机器)来编译它。下图显示了结果。 enter image description here

我想我理解了echo1()的情况(除了为什么addr在缓冲区之上),并且做了一个数字来显示内存中发生了什么。 enter image description here

但我不知道echo2()案例中发生了什么。

所以我想问下列问题:

  1. 在echo1()中,我在缓冲区之前声明了addr,为什么addr被放在堆栈中的缓冲区之上? (因为堆栈向上移动,程序首先应该推送addr然后将缓冲区推到它上面?)
  2. 在echo2()中,为什么缓冲区和&amp;缓冲区给出相同的值?难道这不是指缓冲区指向自身吗?
  3. 在echo2()中,addr的地址和addr的内容(缓冲区的地址)用12个字节分隔,存储在它们中的是什么?
  4. 任何人都可以帮我理解ehco2()中发生的事情吗?
  5. 非常感谢。

3 个答案:

答案 0 :(得分:4)

  

为什么一样?

堆栈中数组的地址及其第一个元素的地址是相同的。不同之处在于增加了结果指针,因为它们具有不同的大小。

  

介于两者之间的是什么?

指针的地址是堆栈地址,而malloc()返回并存储在指针中的地址来自堆。

注意:您的代码还会显示许多未定义行为的来源,例如

  • 使用*Buffer说明符打印"%p"
  • 打印未初始化的指针。
  • 打印unsigned long addr未初始化且使用"%p"说明符,两者都会调用未定义的行为。
  • 使用null说明符打印非"%s"终止的数组。

所以你不能指望echo2()中的给定行为以及整个程序中的一般行为。

答案 1 :(得分:2)

  

任何人都可以帮我理解发生的事情      ehco2()?

这整个问题的最佳答案是使用gcc的-O0标志来生成未优化的代码,并在调试器中运行它或者使用-S来查看与其生成的代码相对应的程序集。

  
      
  1. 在echo1()中,我在缓冲区之前声明了addr,为什么addr被放在堆栈中的缓冲区之上? (因为堆栈向上移动,不应该   程序首先推送addr,然后将缓冲区推到它上面?)
  2.   

但是在将一个值分配给缓冲区之前,你没有为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不是一种编程语言,它指定自动变量和堆栈上的位置之间的严格映射;编译器可以自由地将变量放在它选择的任何地方(如上所述,如果可能的话,包括寄存器)。