2011-12-03 68 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来询问和回答问题。提供简洁的答案似乎比提供详细的答案更无意义! –