如何从文件中获取int和string并将其保存在结构中?

时间:2016-12-16 19:01:13

标签: c arrays file struct allocation

我们假设我们有包含以下内容的文件:

 1 John 
 2 Alex 
 3 Michael 

我们可以使用fscanf()函数获取一行,但如何将其保存到结构下面:

 typedef struct entry { 
 int n; 
 char *name; 
 } entry_t; 

我想创建结构数组并将值从文件保存到它,并动态地执行。我试过这样做

entry_t *prt = malloc ( size * sizof(entry_t) ); 
//opening file 
prt[0].name = malloc ( sizeof("John") ); 
fscanf (fp,"%d %s", prt[0].n, prt[0].name); 

好的,它有效,但是如何从文本文件中获取内存之前为每个名称分配内存? 我决定使用结构数组,因为我将使用它来实现哈希表。

2 个答案:

答案 0 :(得分:2)

sizeof("John")适用于字符串文字,但文件中的名称不是先前已知的,因此必须动态确定大小。

  1. 使用fgets()读取一行。

  2. 使用sscanf()strtol()strtok()来解析该行。

  3. 示例:

    int read_entry(FILE *istream, struct entry *record) {
      char buf[200];
      if (fgets(buf, sizeof buf, istream) == NULL) return -1;  // EOF
      buf[strcspn(buf, "\n")] = 0;  // lop off potential trailing \n
    
      int start;
      int end = 0;
      sscanf(buf, "%d %n%*s%n", &record->n, &start, &end); 
    
      if (end == 0) {
        return 0;  // failed to parse
      }
      record->name = strdup(&buf[start]);
      return 1; // Success
    } 
    

    用法

    struct entry record;
    while (read_entry(stdin, &record) == 1) {
      printf("%d '%s'\n", record.n, record.name);
      ...
      // when done with the record,
      free(record.name);
    }
    

    strdup()是"复制"的常用方法。一个字符串,但它不是标准C库的一部分。很容易编码:Example implementation

答案 1 :(得分:0)

将评论转换为答案。

您至少有两个选择。

  1. 最便携:

     char buffer[1024];
     if (fscanf(fp, "%d %1023s", &prt[0].n, buffer) != 2)
         …handle I/O (format?) error…
     else if ((prt[0].name = strdup(buffer)) == 0)
         …handle out-of-memory error…
     else
     {
         …use values, or continue loop…
     }
    

    这使用一个大缓冲区来读取值,然后分配适当的内存以便在结构中使用。注意参数中的溢出保护(并且需要区分一个)。请注意strdup()是POSIX的一部分,而不是标准C的一部分。虽然很容易编写:

    char *strdup(const char *str)
    {
        size_t len = strlen(str) + 1;
        char *copy = malloc(len);
        if (copy != 0)
            memmove(copy, str, len);
        return copy;
    }
    

    memmove() vs memcpy()的常见辩论;两者都在这种情况下工作,但memmove()无处不在,memcpy()没有。

  2. 使用fscanf()的POSIX功能:

    if (fscanf(fp, "%d %ms", &prt.n, &prt[0].name) != 2)
        …handle I/O (format?) error…
    else
    {
        …use values, or continue loop…
    }
    

    请注意,在此上下文中,您确实传递了指针prt[0].name的地址,因为fscanf()会为您分配必要的内存。

  3. 您需要稍后为每个名称释放分配的内存,当然,无论您使用哪种解决方案。