2016-12-16 64 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的地址分配必要的內存爲您服務。

您需要爲以後每個名稱釋放分配的內存,當然,無論您使用哪種解決方案。

相關問題