首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于char *缓冲区和char buffer[5]的内存分配

关于char *缓冲区和char buffer[5]的内存分配
EN

Stack Overflow用户
提问于 2016-01-28 01:38:32
回答 3查看 1.1K关注 0票数 1

我想问一个关于char *缓冲区、buffer =malloc(5)和char buffer5的内存分配问题。

我的测试代码如下:]

代码语言:javascript
复制
#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); 
}

我通过输入gcc test.c -o测试-m32 (我使用64台机器)在ubuntu上编译了它。下图显示了结果。

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

但我不知道在echo2()情况下发生了什么。

所以我想问以下几个问题:

  1. 在echo1()中,我在缓冲区之前声明了addr,为什么addr放在堆栈缓冲区的上方?(既然堆栈向上移动,那么程序不应该先推送addr,然后再将缓冲区推到上面吗?)
  2. 在echo2()中,为什么缓冲区和&缓冲区提供相同的值?这不意味着缓冲区是指向自己的吗?
  3. 在echo2()中,addr的地址和addr的内容(缓冲区的地址)被分隔为12个字节,其中存储了什么?
  4. 有人能做一个数字来帮助我理解ehco2()中发生的事情吗?

非常感谢。

EN

回答 3

Stack Overflow用户

发布于 2016-01-28 01:41:05

为什么是一样的?

堆栈上的数组的地址与其第一个元素的地址相同。差异在于增加结果指针,因为它们有不同的大小。

中间是什么?

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

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

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

因此,您不能期望在echo2()和整个程序中出现给定的行为。

票数 4
EN

Stack Overflow用户

发布于 2016-01-28 02:09:34

有人能做一个数字来帮助我理解ehco2()中发生的事情吗?

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

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

但是,直到将一个值分配给缓冲区之后,才为addr分配一个值,所以编译器直到稍后才会为其分配内存。

其他几点见艾哈洛布的好答案。

票数 2
EN

Stack Overflow用户

发布于 2016-01-28 02:42:38

在echo1()中,我在缓冲区之前声明了addr,为什么addr放在堆栈缓冲区的上方?

因为编译器不需要按照声明的顺序将自动变量放到堆栈上,而且显然,它选择不这样做。(实际上,它根本不需要将它们放到堆栈中--如果它们适合于寄存器,它可以将它们放入寄存器中。)

在echo2()中,为什么缓冲区和&缓冲区提供相同的值?这不意味着缓冲区是指向自己的吗?

这意味着buffer是数组,在大多数上下文中,表达式buffer计算为指向buffer的第一个元素的指针,即计算为&buffer[0],而'&buffer`‘计算为指向数组的指针,但数组的地址与数组的第一个元素的地址相同。

然而,buffer&buffer有不同的数据类型(“指向char的指针”与“指向5char的数组的指针”)。

在echo2()中,addr的地址和addr的内容(缓冲区的地址)被分隔为12个字节,其中存储了什么?

无论编译器决定将其放在堆栈框架中。堆栈帧的布局不受C(或C++)程序员的直接控制。也许编译器决定将数组后面的地址设置为4字节边界,而不是将第一个元素放在4字节边界上。也许,由于您没有在打开优化的情况下进行编译,所以它没有将i放入寄存器中,而是将其放在堆栈中。

C不是一种编程语言,它指定自动变量与堆栈上位置之间的严格映射;编译器可以自由地将变量放在它选择的任何位置(如我前面所说,如果可能的话,可以将变量放入寄存器中)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35051415

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档