带有malloc的结构体的C内存分配



我试图了解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: %dn", sizeof(*joe));
    printf("1. Address of joe t= %xn", joe);
    printf("2. Address of Age t= %xn", &joe->age);
    printf("3. Address of Height t= %xn", &joe->height);
    printf("4. Address of Weight t= %xn", &joe->weight);
    printf("5. Address of name t= %xn", joe->name);
...

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

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

问题:

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

对象joe的地址和数据成员age的地址之间没有间隔。该extent被数据成员name占用。

struct Person {
    char *name;
    int age;
    //...

根据输出

1. Address of joe   = 602010
2. Address of Age   = 602018

占用8字节,即sizeof( char * )在您的平台上等于8。并且它的地址与对象joe本身的地址一致。

printf("5. Address of name t= %xn", joe->name);

您没有输出name本身的地址。您打印了存储在该指针中的值,该值是使用strdup获得的字符串字面值"ABC"副本的第一个字符的地址。

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

由于name是一个指针,所以它的大小计算如下

sizeof( char * )

sizeof( joe->name )

等于8,正如我在文章开头所解释的。

如果你想确定字符串字面值的长度,你应该使用标头<string.h>中声明的标准函数strlen。例如

printf( "%zun", strlen( joe->name ) );

为什么1和2之间有一个间隙?

结构体的起始地址总是等于它的第一个成员的地址。来自C标准:

6.7.2.1-13。结构体对象的指针经过适当转换后,指向其初始成员

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

printf("1. Address of joe t= %xn", joe);
printf("1. Address of name-pointer t= %xn", &joe->name);

在你的代码中,

printf("5. Address of name t= %xn", joe->name);

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

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

name是一个指针,它占用8字节的内存,不管它指向的数据的大小(可能是一个字符串,在你的情况下,单个字符,int或其他)。

为什么4和5之间有一个间隙?

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

请注意,填充和内存对齐只是结构体大小的一个因素(它们与您显式陈述的问题无关)。由于该结构体包含一个指针(在您的机器上为8字节)和3个整数(每个整数为4字节),因此可以假设总大小为20字节。在大多数平台上,内存是8字节对齐的——这就是为什么你的结构体的大小被四舍五入到24字节。这样,如果你声明一个 Persons的数组,每个数组元素都从一个8字节对齐的地址开始,也就是说,地址值可以被8平均除以。

c标准唯一保证的是第一个成员的地址与结构体的地址相同,并且后续成员的地址随其在结构体中的位置而增加。

编译器允许在成员之间插入空格;这叫做填充。把它看作是针对特定平台优化结构的编译器。

数组在内存中必须始终是连续的

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

C/c++中的每个数据类型都有对齐要求(实际上它是由处理器体系结构强制的,而不是由语言强制的)

然后扩展对结构的要求:

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

结构体的内存布局是机器相关的,所以除非你试图实现DBMS或设备驱动程序或类似的东西,否则你不应该为此烦恼。

sizeof(*name)等于sizeof(char),我不明白你这里有什么困惑,你能进一步解释一下吗?

相关内容

  • 没有找到相关文章

最新更新