2014-12-02 113 views
4

我试图在C中制作一个程序,用于跟踪学生借阅的书籍。我很难在访问文件指针。当我使用文件时,我通常不会使用fscanf(),而是使用通常的scanf。我有这样的数据结构:C中的文件,访问指针,读取和写入文件

typedef struct{ 
    char fName[24], mInitial, lName[16]; 
}nameType; 

typedef struct{ 
    unsigned long idNo; 
    nameType studName; 
    char course[8]; 
    int yrLevel; 
    books borrowedBooks; 
    int bksCtr; 
}student; 

typedef struct{ 
    student *studs; 
    int studCtr; 
}studList; 

我已经创建了两个功能,截至目前,这是addStudToFile(无效),增加了学生的文件,displayStudsFromFile(无效),基本打印出在文件中添加的学生。这是我的新手功能代码:

void addStudToFile(void) 
{ 

    FILE *fp; 
    studList myStud; 


    fp = fopen("students.db", "w"); 
    if(fp!=NULL){ 
     /* ask for student details and adds these to the file */ 
     printf("Enter ID number: "); 
     fflush(stdin); 
     scanf(,"%lu", &myStud.studs->idNo); 
     printf("Enter First Name: "); 
     fflush(stdin); 
     gets(myStud.studs->studName.fName); 
     printf("Enter Last Name: "); 
     fflush(stdin); 
     gets(myStud.studs->studName.lName); 
     printf("Enter Middle Initial: "); 
     fflush(stdin); 
     scanf("%c", &(myStud.studs->studName.mInitial)); 
     printf("Enter Course: "); 
     fflush(stdin); 
     gets(myStud.studs->course); 
     printf("Enter Year: "); 
     fflush(stdin); 
     scanf("%d", &(myStud.studs->yrLevel)); 
     fwrite(&myStud, sizeof(studList),1,fp); 
     fclose(fp); 
    } 
} 

void displayStudsFromFile(void) 
{ 

    FILE *fp; 
    studList myStud; 

    fp = fopen("students.db", "r"); 
    if(fp!=NULL){ 
     while (fread(&myStud, sizeof(studList), 1, fp)){ 
      printf("%lu\t %s, %s %s\t %s-%d", myStud.studs->idNo, myStud.studs->studName.lName, 
              myStud.studs->studName.fName, myStud.studs->studName.mInitial, 
              myStud.studs->course, myStud.studs->yrLevel); 
      printf("borrowed %d books", myStud.studs->bksCtr); 
     } 
     fclose(fp); 
    } 
} 

现在,我在这里的问题是,在我的访问列表是myStud。在我的addStudToFile()函数,每次我输入我的ID号,我的程序停止工作。为什么它停止工作?我需要malloc吗?或者是我在访问scanf()错?我遇到我的程序停止再次工作的另一种情况是当我打电话给我的显示功能时。它显示的东西,但外星人/垃圾值。

这是在哪里我在扫描功能遇到我的问题的屏幕截图:

enter image description here

这里是我的显示功能:

enter image description here

我希望有人能够帮助我与此。谢谢!

+0

不要对发布图片感觉不好 - 这是一个纯文本程序,对吧?图像会添加什么? – usr2564301 2014-12-02 22:02:26

+0

宁可截图。我很抱歉,我已经编辑过了。谢谢! @Jongware – 2014-12-02 22:04:24

+0

这一行:while(fread(&myStud,sizeof(studList),1,fp)){在到达文件结束时不一定会停止。因为它可以返回除'1'之外的其他数字,例如在某些错误情况下不为0。建议:while(1 == fread(&myStud,sizeof(studList),1,fp))){ – user3629249 2014-12-03 04:09:42

回答

3

你的预感是正确的,你需要的malloc的东西:)

typedef struct{ 
    student *studs; 
    int studCtr; 
}studList; 

这是你的问题。您将螺柱定义为指向学生结构的指针,但实际上并未为其分配任何内存,因此您可以稍后使用运算符来引用它。

您可以允许项目的预设号码,这样的话你可以定义一样,

student studs[10]; 

允许10个条目,或在addStudToFile()你可以要求用户输入他想要输入的条目数量。在这种情况下,你会离开的定义,因为它是,一旦你有用户输入做:

myStud.studs = (student *) malloc(sizeof(student) * how_many); 

有可能是沿着你已经发布的代码更多的错误,但暂时上面是什么让你回来。

编辑:如果你遵循的malloc()的路线,从返回addStudToFile()无论出于何种原因之前,你应该确保你叫

free(myStud.studs); 

,或者你得到一个内存泄漏...

更新

好吧,去进一步下降,当你使用fwrite()的一切,记住,你的malloc()的双头螺栓的内存。 sizeof(studlist)在编译时计算,不可能知道运行时使用的额外内存。另外,这两个内存区域不保证连续,所以仍然有一个fwrite不会削减它。如果你的代码是按照它的结构构建的,那么你最好先fwrite()首先使用studCtr,然后再使用你为鼠标设计的内存。

对于displayStudsFromFile()因为仅仅是一个循环那里并没有什么真正的存储,用于以后,我只用

student myStud; 

即使用学生结构只是一个实例,而不是studlist。在这种情况下,你需要做一个fread()读取磁盘文件中的studCtr,然后使用它来一次循环fread()一个学生对象到myStud。在这一循环中,您打印感兴趣的领域,像这样:

printf("borrowed %d books", myStud.bksCtr); 

希望这将让你去...用C第一步是有点困难:d

+0

我试过使用malloc,但是当我尝试编译我的程序时发生错误。它说:“从'空'无效转换为'学生',我甚至没有得到这个错误。 – 2014-12-02 22:26:46

+0

无效*给学生*可能吗?你是否在malloc()之前添加了演员给(student *)? 。 – kostas 2014-12-02 22:32:58

+0

我的malloc工作过,哈!谢谢!你能告诉我关于我的显示功能吗?这就是我被卡住的原因。每当我打电话给我的显示功能时,它就会停止我的程序 – 2014-12-02 22:34:38

1

myStud.studs是一个指向学生的指针,但我没有看到你实际分配给那个学生的位置。你需要malloc一个学生之前,你可以做一些事情,如&myStud.studs->idNo

+0

我的malloc应该如何处理这个? myStud =(studList)malloc(sizeof(?)) – 2014-12-02 22:16:16

+1

在C中,有几个原因不能从任何malloc系列函数中强制返回值。所以建议删除它。 – user3629249 2014-12-03 04:46:20

0

总之,不要写指向文件的指针,它们以后会变得毫无意义。

典型的方法是首先写出物品的数量,然后遍历列表中的每个物品并单独写出它们。

在读者结尾:

  1. 读项目的数量。
  2. 分配足够的内存来保存所有项目。
  3. 阅读每个项目。
+0

我明白了,但我们的老师告诉我们现在使用这种方法来使用文件。 – 2014-12-02 22:22:43

0
along with the problems mentioned already, 
this function has its' own set of troubles. 
I have inserted '<--' and a comment at each problem 

fflush(stdin) though works on some implementations, it's still undefined behaviour. 
According to the standard, fflush only works with output/update streams 
(for your code, since the printf format strings do not end in '\n' 
( which would have forced the actual output to occur 
( change these lines to 'fflush(stdout)' 

A ' ' in a scanf() format string will consume any white space found at that 
point in the input. Therefore, for almost all cases, the first char in 
the format string should be: ' '. Then newlines, spaces, etc 
will be consumed, as if they were never there. It is even correct to 
use the leading ' ' when there is no white space to consume. 

gets() is depreciated and will corrupt/overrun a input buffer, so NEVER 
use gets, rather, use fgets(), where the amount of input can be limited 
and similar good things. 

void addStudToFile(void) 
{ 

    FILE *fp; 
    studList myStud; 


    fp = fopen("students.db", "w"); 
    if(fp!=NULL) 
    { 
     /* ask for student details and adds these to the file */ 

     printf("Enter ID number: "); 
     fflush(stdin); <-- change to stdout 
     scanf(,"%lu", &myStud.studs->idNo); 
     <-- change format string to: " %lu" 
     <-- add check of returned value to assure operation successful 

     printf("Enter First Name: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->studName.fName); 
     <-- replace gets with fgets() +appropriate parms) 
     <-- add check of returned value to assure operation successful 

     printf("Enter Last Name: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->studName.lName); 
     <-- replace gets with fgets() +appropriate parms) 
     <-- add check of returned value to assure operation successful 

     printf("Enter Middle Initial: "); 
     fflush(stdin); <-- change to stdout 
     scanf("%c", &(myStud.studs->studName.mInitial)); 
     <-- replace format string with " %c" 
     <-- add check of returned value to assure operation successful 

     printf("Enter Course: "); 
     fflush(stdin); <-- change to stdout 
     gets(myStud.studs->course); 
     <-- replace gets with fgets() +appropriate parms 
     <-- add check of returned value to assure operation successful 

     printf("Enter Year: "); 
     fflush(stdin); <-- change to stdout 
     scanf("%d", &(myStud.studs->yrLevel)); 
     <-- change format string to: " %d" 
     <-- add check of returned value to assure operation successful 

     fwrite(&myStud, sizeof(studList),1,fp); 
     <-- add check of returned value to assure operation successful 

     fclose(fp); 
    <-- add else clause so use knows what happened. I.E. 
     } else { perror("fopen failed for write"); exit(EXIT_FAILURE); 
    } // end if 
} // end function: addStudToFile 
0
Here are my comments, prefixed by '<--' 



void displayStudsFromFile(void) 
{ 

    FILE *fp; 
    studList myStud; 

    fp = fopen("students.db", "r"); 
    if(fp!=NULL) 
    { 
     while (fread(&myStud, sizeof(studList), 1, fp)) 
     <-- add check of returned value to assure operation successful 

     { 
      printf("%lu\t %s, %s %s\t %s-%d", 
        myStud.studs->idNo, 
        myStud.studs->studName.lName, 
        myStud.studs->studName.fName, 
        myStud.studs->studName.mInitial, 
        myStud.studs->course, 
        myStud.studs->yrLevel); 
      printf("borrowed %d books", myStud.studs->bksCtr); 
     } 
     fclose(fp); 
    <-- to let user know about error 
    <-- insert: }else{ perror("fopen failed for read"); exit(EXIT_FAILURE); 
    } // end if 
} // end function: displayStudsFromFile