2011-12-03 106 views
1

程序要求用戶輸入一些記錄(結構),如果有必要並將它們附加到現有文件或創建一個新文件(如果沒有),然後列出該文件的內容。追加到C中的文件,讀取到結構數組

#include <stdio.h> 
#include <string.h> 
#define N 25 

int main() { 

    struct studrec { 
    char name[20], surname[20], sex, date[12]; 
    } students[N]; 
    int i, count = 0; 
    char another; 

    FILE *fileptr; 

    for (i = 0; i < 10; i++) { 
    puts("Press y to continue without adding new records"); 
    another = getchar(); 
    if (another == 'y' || another == 'Y') break; 
    while ((another = getchar()) != '\n' && another != EOF); 
    puts("Input info"); 

    puts("Name: "); 
    if (fgets(students[i].name, sizeof(students[i].name), stdin) == NULL) return 1; 
    students[i].name[strlen(students[i].name)-1] = '\0'; 

    puts("Surname: "); 
    if (fgets(students[i].surname, sizeof(students[i].surname), stdin) == NULL) return 1; 
    students[i].surname[strlen(students[i].surname)-1] = '\0'; 

    puts("Sex (m/f): "); 
    students[i].sex = getchar(); 
    while ((another = getchar()) != '\n' && another != EOF); 

    puts("Date (dd.mm.yyyy): "); 
    if (fgets(students[i].date, sizeof(students[i].date), stdin) == NULL) return 1; 
    students[i].date[strlen(students[i].date)-1] = '\0'; 
    while ((another = getchar()) != '\n' && another != EOF); 
    } 
    count = i; 

    fileptr = fopen("students.txt", "a+"); 
    for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr); 

    rewind(fileptr); 
    for (i = 0; (another = fgetc(fileptr)) != EOF && i < N; i++) { 
    fseek(fileptr, -1, SEEK_CUR); 
    fread(&students, sizeof(students), 1, fileptr); 
    } 
    fclose(fileptr); 

    count = i; 
    for (i = 0; i < count; i++) printf("%20s%20s%4c%15s\n", students[i].name, students[i].surname, students[i].sex, students[i].date); 

    return 0; 
} 

寫入新文件時一切正常。 輸出:

...input procedure... 
Press y to continue without adding new records 
y 
       Liam    James m  12.03.1987 
       Abbey    Trueman f  23.07.1943 
       Hugo    Brown m  13.05.1947 

不過,如果我再次運行它,並嘗試另一條記錄追加到現有文件的程序失敗:

...input procedure... 
Press y to continue without adding new records 
y 
       Nadia   Rachmonoff f  12.07.1934 
            O|u     
        �u      �    u 
              �   E�u 

看來,新的記錄被放在學生[0 ]並且所有其他元素都被刪除。 我在做什麼錯?可能是&學生指針有問題。我嘗試了& students [i],但它在第一次迭代後返回了「分段錯誤」。據我所知&學生地址在每次fread/fwrite後自動遞增到下一個元素。如果不是這樣,程序在第一次運行時就不能正常工作。

+0

爲什麼你寫的*生*到文件*計數*次? – Beginner

回答

0

以下寫入整個25元件陣列count倍:

for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr); 

有兩種方法來解決這個:

  1. 計算由count元件佔據的正確的大小,和用一個單獨的fwrite調用寫出來。
  2. 使用循環一次寫入條目。

試圖讀回元素的循環也是一樣的:每次迭代讀取整個25元素陣列

+0

閱讀我的評論後很容易,對吧? ;) – Beginner

+0

@RomanB .:運行代碼並查看輸出文件後很容易。 – NPE

0

你寫的代碼是不正確,儘量

fwrite(students, sizeof*students, i, fileptr); 

    rewind(fileptr); 
    for (i = 0; i < N && fread(&students[i], sizeof*students, 1, fileptr); i++); 
3

你有你如何處理的數組中的幾個問題。首先,這條線:

for (i = 0; i < count; i++) fwrite(&students, sizeof(students), 1, fileptr); 

你在這裏幹什麼運行一個循環,一個合格的每個記錄輸入的內容,並的25項全陣列寫在每個傳遞文件。因此,如果輸入了3條記錄,則會寫入,其中大部分是垃圾或冗餘。你可能想在這裏更重要的是這樣的:

for (i = 0; i < count; i++) 
    fwrite(&students[i], sizeof(students[i]), 1, fileptr); 

...這裏的大小是數組的一個元素(單個記錄)和地址的大小記錄你」的地址目前正在寫入而不是整個數組的地址。

rewind(fileptr); 
for (i = 0; (another = fgetc(fileptr)) != EOF && i < N; i++) { 
    fseek(fileptr, -1, SEEK_CUR); 
    fread(&students, sizeof(students), 1, fileptr); 
} 

首先,fread(&students, sizeof(students), 1, fileptr);應該改變很像fwrite()前,要fread(&students[i], sizeof(students[i]), 1, fileptr);

你以後讀取時的數據,以及其他有類似的問題。原因是一樣的:你一次循環讀取一條記錄,所以你需要讀入那條記錄不僅僅是每次數組的開始,你讀的數據量應該是大小爲,記錄而不是整個數組的大小。其次,雖然修復上述應該可以使其工作,但是您可以輕鬆地更改循環,以便您不需要讀取循環表達式中的單個char以檢查EOF。您應該通過檢查循環中fread()的返回而確實檢查。喜歡的東西:

rewind(fileptr); 
for (i = 0; i < N; i++) { 
    if (fread(&students[i], sizeof(students[i]), 1, fileptr) != 1) 
    break; 
} 

或者更好的是,剛讀N項目沒有環,並使用返回值來告訴你有多少人閱讀:

rewind(fileptr); 
i = fread(students, sizeof(students[0]), N, fileptr); 
+0

+1只是好奇。寫這麼長的答案的動機是什麼? – Beginner

+0

@RomanB。只是爲了增加清晰度。海報造成的錯誤可能只會由對細節有困難的人做出,所以一個簡潔的答案可能是不充分的。我寧願解釋得太多也不夠;額外的細節可以忽略不計,但缺少細節只會使答案無益。 – Dmitri

+0

@RomanB。 - 爲什麼*不*寫出冗長而詳細的答案?我根本不理解這種情緒。 Dmitri登錄到Stack Overflow來詢問和回答問題。提供簡潔的答案似乎比提供詳細的答案更無意義! –