2016-12-16 62 views
1

假设我们有文件,其中包含:如何从文件中获取int和string并将其保存在结构中?

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

您不能分配_before_,因为您不知道大小。 'strlen'你的每个名字都来自文件然后'malloc' – mihai

+1

你至少有两个选择。 (1)大多数可移植的:'char buffer [1024]; if(fscanf(fp,“%d%1023s”,&prt [0] .n,buffer)== 2){prt [0] .name = strdup(buffer); ...检查strdup后使用值工作...}其他{...处理错误...}'它使用一个大缓冲区来读取值,然后分配内存;或者(2)使用['fscanf()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html)的POSIX特性:'if(fscanf(fp,“%d%ms” ,&prt.n,&prt [0] .name)== 2){...使用值读取...} else {...处理错误...}'。请注意第一次通话的大小限制。 –

+0

对'fscanf()'的调用不应该编译 - 你省略了文件指针参数。 –

回答

2

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()是 “复制” 的字符串的常用方法,但它不是标准C库的一部分。易于编码:Example implementation

+0

在分配和修剪名称末尾的多余空格之后,可以使用'if(record-> name == NULL)'进行额外的错误检查。 – chux

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… 
    } 
    

    注意,在这种情况下,你作为fscanf()通过指针prt[0].name的地址分配必要的内存为您服务。

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

相关问题