0

我一直在阅读“Learn C the Hard Way”,遇到了一个有趣的问题,希望有人能详细解释一下。基本练习是使用包含示例 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 构造函数的实现如下:

 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 或其他东西,但不管我的结构的具体内存大小如何,我更感兴趣的是为什么这两个不同的实现会导致不同的内存大小(据我了解,双倍的内存成本是相当可观的)。

4

2 回答 2

1

在第一种情况下,进行了 4 次动态分配:两个名称字符串带有strdup,以及 2 个 Person 结构带有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不必单独担心。

[*] 除了实现不需要一个接一个地分配这些东西,所以你的方法通常不起作用。它恰好在这种情况下给出的结果与分配按您制作它们的顺序放置的理论一致。

于 2012-05-24T09:33:01.197 回答
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(...);
在这里,调用者分配了一个完整的人结构,而不仅仅是一个指针。当函数被调用时,它返回的数据将被复制到调用者的 person 结构中。所以结构的位置取决于调用者。

于 2012-05-24T09:41:47.680 回答