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

How to get int and string from file and save it in structure?

假设我们的文件包含:

 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); 

好的,它可以工作,但是如何在从文本文件中获取之前为每个名称分配内存? 我决定使用结构数组,因为我将用它来实现哈希 table.

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


  1. 使用fgets()读一行。

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

示例:

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() 是 "duplicate" 字符串的常用方法,但它不是标准 C 库的一部分。足够容易编码:

正在将评论转化为答案。

您至少有两个选择。

  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() 为您分配了必要的内存。

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