【问题标题】:C struct with pointer think I'm not allocating memory correctly带有指针的 C 结构认为我没有正确分配内存
【发布时间】:2012-08-05 01:52:53
【问题描述】:
  typedef struct Data* DATAS;

  struct Data {
      char *name;
      char *city;
      DATAS next;
  };
  typedef struct Data DATA;

  int main(void){
     DATAS tmp;

     tmp=(DATAS) malloc(sizeof(DATA));   
     printf("please enter name:\n");
     scanf("%s",&tmp->name);
     printf("%s\n",&tmp->name);
     printf("please enter city:\n");
     scanf("%s",&tmp->city);
     printf("%s\n",&tmp->name);
     printf("%s\n",&tmp->city);

  return 0;
  }

这是家庭作业的一部分。或者更确切地说,这个概念是。我需要使用'typedef struct Data* DATAS;'这让我失望。当我运行它时,我会用城市的一部分覆盖名称,所以我得到了这个结果。

please enter name:
name
name
please enter city:
city
namecity
city

任何帮助都会很棒。谢谢。我已经使用

尝试了不同的 malloc 变体
tmp=(DATAS) malloc(sizeof(DATA));
tmp=(DATA) malloc(sizeof(DATA));

【问题讨论】:

    标签: c unix structure


    【解决方案1】:

    分配struct Data 的最佳方式是:

    struct Data *tmp;
    tmp = malloc(sizeof *tmp);
    if (tmp == NULL) {
        /* malloc failed, abort or take corrective action */
    }
    

    不建议为指针类型定义 typedef(至少我是这样);显式使用struct Data * 可以让读者更清楚您正在处理指针。

    也不需要为结构类型定义 typedef。 typedef 只是为现有类型声明一个新名称;你的类型已经有了一个很好的名字,struct Data。诚然,您必须重复输入 struct 关键字,但这不是问题。

    不需要转换malloc 的结果; malloc 返回 void* 结果,可以隐式转换为您的指针类型。演员表可以隐藏错误,例如忘记所需的#include <stdlib.h>

    但这些都是风格问题。您当前的代码:

    tmp=(DATAS) malloc(sizeof(DATA));
    

    没问题,它应该可以工作。问题出现在您的代码后面。

    scanf 格式为"%s" 需要char* argument. You're giving it the *address* of achar* 对象,即char** 类型的值。编译器不一定会就此发出警告。所以这个:

    scanf("%s",&tmp->name);
    

    应该是:

    scanf("%s", tmp->name);
    

    但这仍然是个问题,因为tmp->name 是一个未初始化的指针。它可能指向内存中的某个随机位置,并且调用尝试在该位置存储数据。或者它可能持有无效地址,从而导致崩溃。行为未定义。

    您需要分配空间来保存名称,并让tmp->name 指向它。您可能需要在此处再次致电malloc()

    那么您需要分配多少空间?好吧,没有好的答案,因为scanf("%s", ...) 没有限制它将读取多少字节。不管分配的空间有多大,只要输入足够的数据就会溢出。

    您可能还不需要担心这个;只是为了将来记住它。现在,您可以分配“足够”的空间(例如 100 个字节)并注意不要输入太多数据。这应该足以让您的程序正常工作。 (查看scanf 的文档,并考虑使用"100s" 之类的东西。)

    请记住,scanf("%s", ...") 读取的是空格分隔的输入字符串;如果你输入“John Doe”,它只会读取“John”,留下“Doe”用于下一个输入操作。

    (我希望这不会太过分。)

    【讨论】:

    • 这很棒。没有比一般指针更压倒性的了。就在我认为我已经完成的时候,我感到困惑。我正在使用“&tmp->name”,因为正如您指出的“tmp->name”正在崩溃。我以为 'tmp=(DATAS) malloc(sizeof(DATA));'将为包括“name”和“city”在内的整个结构分配内存。
    • 我认为您会发现comp.lang.c FAQ 是一种宝贵的资源。
    【解决方案2】:

    您将未初始化的指针传递给scanf,它使用它们来执行写入;这是未定义的行为。您还将字符串指针的地址传递给scanfprintf; C 中的字符串已经是指针,你不应该将指向它们的指针传递给 I/O 例程。

    如果您知道名称/城市名称中的字符数限制,则可以读取如下字符串:

    char buf[128]; // 127 is the limit; buffer needs an extra character
    printf("please enter name:\n");
    scanf("%127s", buf);
    size_t len = strlen(buf)+1; // plus one for null terminator
    tmp->name = malloc(len);
    strcpy(tmp->name, buf);
    printf("%s\n", tmp->name); // No ampersand
    

    【讨论】:

    • 谢谢,这很有帮助
    • 由于Keith Thompson给出的解释,我将给出答案。如果我可以投票给你回答我会的。
    【解决方案3】:

    您已经为包含三个指针的结构分配了空间。您还需要为这两个字符串分配空间。您还应该确保 next 字段已正确初始化 - 可能使用 NULL。

    就我个人而言,我不会为DATAS 类型定义而烦恼,而且最好保留宏的所有大写名称(尽管有FILE * 类型)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-23
      • 2013-08-17
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2017-01-03
      • 1970-01-01
      • 2014-02-23
      相关资源
      最近更新 更多