我一直在阅读“以艰难的方式学习C”,我遇到了一个有趣的问题,我希望有人可以详细解释。基本练习是使用涉及示例Person结构的结构。在第一种情况下,我有一个构造函数方法(我不完全明白为什么教程这样做,如果有人不介意在旁边解释:D)以及像这样的结构:
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->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
}
除了代码的其余部分,这运行得很好,但是当我打印指向这些结构的指针的内存位置时:
int main(int argc, char* argv[]) {
struct Person *joe = Person_create("joe alex", 12, 80, 100);
struct Person *joe = Person_create("frank blank", 20, 72, 140);
}
它们的内存值的差异总是精确到40.相比之下,结构构造函数的实现如:
struct Person{//is the same as above};
struct Person Person_create (char* name, int age, int height, int weight) {
struct Person newPerson;
newPerson.name = name; //and so on
return newPerson
}
当我打印出joe和frank的内存位置时,用上面相同的值初始化,通过上面的实现,它们的内存位置的差异似乎总是为20.
我研究了一些程序集,我知道编译器根据结构的数据类型分配内存块,所以我在想..在任一实现中,char数组都有这么多的字符所以n个字符* 1 = char空间,然后我有3个整数,所以3 * 4 = 12; 12 + 9(Joe Alex \ 0对吗?)= 21 ..我可能得到\ 0错了所以它等于20或者其他东西,但是无论我的结构的具体内存大小如何,我都更感兴趣为什么这两个不同的实现导致内存中的大小不同(据我所知,DOUBLE内存成本相当大)。
答案 0 :(得分:1)
在第一种情况下,进行了4次动态分配:两个名称字符串strdup
和2个人结构malloc
。结构地址之间的差异大致告诉您分配了多少内存,包括第一个结构,在第二个结构之前[*]
在第二种情况下,没有进行动态分配,但我想你已经在堆栈上创建了两个Person
对象:
struct Person joe = Person_create("joe alex", 12, 80, 100);
struct Person frank = Person_create("frank blank", 20, 72, 140);
它们的地址之间的差异大致告诉你第一个占用多少内存[*]。
由于您尚未复制字符串,因此非常需要使用字符串文字作为名称,或者与Person
结构分开管理其内存。字符串数据不是 struct Person
的一部分 - 永远不会。 newPerson.name = name
只存储指针,而不是字符串数据。
一旦你开始从文件或终端读取名称,这就变得很麻烦:无论如何你必须动态分配它们,所以你不会保存任何内存,但你必须编写更多的代码。该练习可能包含一个Person_Destroy
函数free
的名称,以便struct Person
的用户不必单独担心。
[*]除了不需要实现一个接一个地分配这些东西,所以你的方法一般不起作用。它恰好在这个场合给出了结果,这与分配按照你做出的顺序放置的理论一致。
答案 1 :(得分:0)
这两种方法的使用方式差异很大:
定义:
struct Person *Person_create(char *name, int age, int height, int weight)
用途:
struct Person *p = Person_create(...);
Person_create
函数分配结构。此结构的位置取决于函数的实现。调用者只需要定义一个指向这个内存的指针,而不是整个人的结构。
定义:
struct Person Person_create (char* name, int age, int height, int weight)
用途:
struct Person p = Person_create(...);
这里,调用者分配了一个完整的人员结构,而不仅仅是一个指针。调用该函数时,它返回的数据将被复制到调用者的人员结构中。所以结构的位置取决于调用者。