带有malloc的struct的C内存分配

Seb*_*Seb 5 c memory malloc struct memory-management

我试图理解C中的结构的内存分配,但我坚持下去.

struct Person {
    char *name;
    int age;
    int height;
    int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->age = age;
    who->height = height;
    who->weight = weight;
    who->name = strdup(name);

    return who;
}
int main(int argc, char *argv[])
{
    struct Person *joe = Person_create("ABC", 10, 170, 60);
    printf("Size of joe: %d\n", sizeof(*joe));
    printf("1. Address of joe \t= %x\n", joe);
    printf("2. Address of Age \t= %x\n", &joe->age);
    printf("3. Address of Height \t= %x\n", &joe->height);
    printf("4. Address of Weight \t= %x\n", &joe->weight);
    printf("5. Address of name \t= %x\n", joe->name);
...
Run Code Online (Sandbox Code Playgroud)

我不明白的是这个结构的内存分配.在我的打印输出上,我看到了这个:

Size of joe: 24
1. Address of joe   = 602010
2. Address of Age   = 602018
3. Address of Height    = 60201c
4. Address of Weight    = 602020
5. Address of name  = 602030
Run Code Online (Sandbox Code Playgroud)

问题:

  • 为什么1和2之间存在差距?
  • 为什么4和5之间存在差距?
  • 如何*name计算名称的大小仅指向第一个字符?

Vla*_*cow 9

对象joe的地址与数据成员的地址之间没有间隙age.此范围由数据成员占用 name.

struct Person {
    char *name;
    int age;
    //...
Run Code Online (Sandbox Code Playgroud)

根据输出

1. Address of joe   = 602010
2. Address of Age   = 602018
Run Code Online (Sandbox Code Playgroud)

它占用平台中的8个字节sizeof( char * )等于8.它的地址与对象joe本身的地址一致.

在这个声明中

printf("5. Address of name \t= %x\n", joe->name);
Run Code Online (Sandbox Code Playgroud)

你没有输出name自己的地址.您打印了存储在此指针中的值,该值是"ABC"通过使用获得的字符串文字副本的第一个字符的地址 strdup.

因此,输出4和5中的值之间存在差距,因为它们是不同的存储器范围.数据成员weight属于对象,joe而字符串文字的副本"ABC"存储在对象外部.该对象只有数据成员name,指向文字副本的第一个字符.

作为name一个指针然后它的大小计算如下

sizeof( char * )
Run Code Online (Sandbox Code Playgroud)

要么

sizeof( joe->name )
Run Code Online (Sandbox Code Playgroud)

如我在帖子开头所解释的那样等于8.

如果要确定字符串文字的长度,则应使用标strlen头中声明的标准函数<string.h>.例如

printf( "%zu\n", strlen( joe->name ) );
Run Code Online (Sandbox Code Playgroud)


mor*_*ort 7

为什么1和2之间存在差距?

struct的起始地址始终等于它的第一个成员的地址.从C标准:

6.7.2.1-13.指向适当转换的结构对象的指针指向其初始成员

第一个成员不是age,但是name.所以以下两行应该打印相同的地址:

printf("1. Address of joe \t= %x\n", joe);
printf("1. Address of name-pointer \t= %x\n", &joe->name);
Run Code Online (Sandbox Code Playgroud)

在你的代码中,

printf("5. Address of name \t= %x\n", joe->name);
Run Code Online (Sandbox Code Playgroud)

不打印指针的地址,而是指针指向的数据的地址.

如何计算*name的大小,因为名称仅指向第一个char?

name是一个指针,它占用8个字节的内存,无论它指向的数据大小如何(可能是一个字符串,如你的情况,一个char,一个int或其他).

为什么4和5之间存在差距?

用于存储实际name字符串的内存不在struct中 - 在某处strdup分配内存以将字符串复制到其中.这恰好是结构的最后一个成员之后的16个字节.然后指针指向此内存位置.name

请注意,填充和内存对齐只是结构大小的一个因素(它们与您明确陈述的问题无关).由于struct包含一个指针(在您的机器上为8个字节)和3个整数(每个4个字节),因此可以假设总大小为20个字节.在大多数平台上,内存是8字节对齐的 - 这就是为什么结构的大小向上舍入到24字节的原因.这样,如果声明一个Persons 数组,则每个数组元素从一个8字节对齐的地址开始,即地址值可以均匀地除以8.


Har*_*ris 0

这是由于所谓的数据对齐。引用自本网站

C/C++ 中的每种数据类型都会有对齐要求(实际上它是由处理器架构而不是语言强制要求的)。

然后将这一要求扩展到结构:

由于各种数据类型的对齐要求,结构体的每个成员都应该自然对齐。

您可以通过这篇文章进行详细阅读。

  • 这个答案的大量赞成/反对票可能是由于[这个元问题](http://meta.stackoverflow.com/q/303130/472495)。 (5认同)
  • -1,抱歉。数据对齐不是这里的主要因素。OP 有三个问题:“为什么 1 和 2 之间有差距?”、“为什么 4 和 5 之间有差距?”和“如何将 \*name 的大小计算为名称点只到第一个字符?”。数据对齐确实在第二个问题中发挥了作用,但这并不是故事的全部(也不是故事的重要部分);对于回答第一个问题和第三个问题没有任何作用。 (2认同)