2014-09-28 43 views
2

返回值不好意思做這種問題(因爲有關於互聯網上這麼多),但我不得不問這樣的:問題的fscanf的在C

演習涉及從閱讀文件與學生名單(記錄包含:姓名,序號)。我已經創建的文檔,幷包括13條線路,但是當我寫終端./a.out,輸出爲13行這種類型的列表:(null) (null) (null)

的代碼是:

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#define EOF (-1) 
#define BUF 100 

typedef struct stud{ 
    char *surname; 
    char *name; 
    char *serial; 
} student; 

int main(void){ 
    FILE *fd; 
    int n = BUF; 
    int k = 0; 
    int i = 0; 
    int ret; 
    char *s = malloc(BUF * sizeof(char)); 
    if((fd = fopen("registry_office_students.txt","r")) == NULL){ 
     perror("error opening file"); 
     return -1; 
    } 
    while(fgets(s,n,fd)!=NULL){ 
     k++; 
    } 
    student *a = malloc(k*sizeof(student)); 
    rewind(fd); 
    ret = fscanf(fd, "%s, %s, %s", a[i].surname, a[i].name, a[i].serial); 
    while(fscanf(fd, "%s, %s, %s", a[i].surname, a[i].name, a[i].serial) == ret){ 
     i++; 
    } 
    for(i=0;i<k;i++){ 
     printf("%s, %s, %s \n", a[i].surname, a[i].name, a[i].serial); 
    } 
    fclose(fd); 
    return 0; 
} 

我再次道歉並希望得到適當的迴應,謝謝。

+0

您是否仔細閱讀了幾次[fscanf(3)]的文檔(http://man7.org/linux/man-pages/man3/fscanf.3.html)?問題是什麼? – 2014-09-28 15:49:24

+0

@JeroenvanderHooft上面的代碼是有效的。它允許Carmine將該結構稱爲「struct stud」或「student」。 – 2014-09-28 15:53:23

回答

5

fscanf(3)%s不會爲字符串分配任何內存。該字符串應該已經存在。

至少,東西取代

ret = fscanf(fd, "%s, %s, %s", 
       a[i].surname, a[i].name, a[i].serial); 

{ 
     char surname[48]; 
     char name[64]; 
     char serial[32]; 
     memset (surname, 0, sizeof(surname)); 
     memset (name, 0, sizeof(name)); 
     memset (serial, 0, sizeof(serial)); 
     memset (a+i, 0, sizeof(struct stud)); 
     ret = fscanf(fd, "%47s, %63s, %31s", surname, name, serial); 
     if (ret==3) { 
     a[i].surname = strdup(surname); 
     if (!a[i].surname) 
      { perror("strdup surname"); exit(EXIT_FAILURE); } 
     a[i].name = strdup(name); 
     if (!a[i].name) 
      { perror("strdup name"); exit(EXIT_FAILURE); } 
     a[i].serial = strdup(serial); 
     if (!a[i].serial) 
      { perror("strdup serial"); exit(EXIT_FAILURE); } 
     } 
    } 

通知閱讀它之前,我清理內存。我明確給出了格式爲fscanf的字符串大小。我將測試過的strdup複製到堆中。

其實,我相信你的方法可能是錯的。你可能會決定每個學生應該是一個單一的線,你將與getline(3)閱讀並sscanf(3)解析(也許%n將是有益的!)或者,也許strtok(或「手動」使用isalpha

請閱讀更多關於C編程的材料,然後編譯所有警告和調試信息(gcc -Wall -g),學會使用調試器(gdb)和內存泄漏檢測器(valgrind)。

2

首先,你永遠不會爲存儲在結構中的字符串分配內存。即您的fscanf嘗試將數據讀入不存在的緩衝區中。

其次,您的讀取代碼將數據讀取到a[0]兩次。即第一個fscanf將讀取a[0]中的第一條記錄,然後下一個fscanf將再次讀取下一條記錄到a[0],覆蓋之前讀取的內容。爲什麼?這是你的意圖(就像跳過表頭或類似的東西)?

第三,您的計數代碼(fgets)與您的閱讀代碼(fscanf)不一樣。如果讀碼因爲fscanf特定的原因過早失敗,您將讀取的記錄少於k。然而,您的打印代碼無條件打印所有k。 (如果你的閱讀代碼fscanf格式立即失敗,由於一些錯誤?在這種情況下,你從來不看任何東西。)

第四,在你的計數的代碼每次調用fgets100字符或一個換行符的限制(也就是fgets如何工作)。這與fscanf的工作方式完全不同步,您的情況不受任何限制。這意味着計數代碼看到的記錄數可能很容易與讀代碼看到的記錄數不同(大於)。