我们假设我们有包含以下内容的文件:
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);
好的,它有效,但是如何从文本文件中获取内存之前为每个名称分配内存? 我决定使用结构数组,因为我将使用它来实现哈希表。
答案 0 :(得分:2)
sizeof("John")
适用于字符串文字,但文件中的名称不是先前已知的,因此必须动态确定大小。
使用fgets()
读取一行。
使用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()
是"复制"的常用方法。一个字符串,但它不是标准C库的一部分。很容易编码:Example implementation
答案 1 :(得分:0)
将评论转换为答案。
您至少有两个选择。
最便携:
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()
没有。
使用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()
会为您分配必要的内存。
您需要稍后为每个名称释放分配的内存,当然,无论您使用哪种解决方案。