C中的文件,访问指针,读取和写入文件

时间:2014-12-02 21:57:30

标签: c file function pointers structure

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

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(void),它将学生添加到文件中,以及displayStudsFromFile(void),它基本上打印出文件中添加的学生。这些是我的新手功能代码:

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号时,我的程序都会停止工作。它为什么停止工作?我必须购物吗?或者我访问 scanf()错了?我遇到我的程序再次停止工作的另一种情况是我调用我的显示功能。它显示了一些东西,但外来/垃圾值。

以下是我在扫描功能中遇到问题的屏幕截图:

enter image description here

这是我的显示功能:

enter image description here

我希望有人可以帮助我。谢谢!

5 个答案:

答案 0 :(得分:3)

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

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

这是你的问题。您将 studs 定义为指向 student 结构的指针,但实际上并没有为它分配任何内存,因此您可以稍后使用引用它 - > 运营商。

您可以允许预设数量的条目,这样您就可以定义 studs

student studs[10];

允许10个条目,或者在 addStudToFile()中,您可以要求用户输入他想要提供的条目数。在这种情况下,您可以保留定义,只要您输入用户输入:

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

您发布的代码可能存在更多错误,但目前上述情况会阻碍您。

编辑:如果您遵循malloc()路线,在从 addStudToFile()返回之前,无论出于何种原因,您都应确保调用

free(myStud.studs);

或者你得到了内存泄漏...

<强>更新

好吧,进一步向下,当你fwrite()所有东西,记住,你malloc()编辑内存的螺柱。 sizeof(studlist)在编译时计算,不可能知道运行时使用的额外内存。另外,两个内存区域不能保证是连续的,所以仍然有一个fwrite不会削减它。

在你的代码结构合理的情况下,你最好首先使用studctr fwrite(),然后是你为studs编写的内存。

对于 displayStudsFromFile(),因为那里只有一个循环而且以后什么都没有存储,我只是使用

student myStud;

即,只使用学生结构的一个实例而不是一个studlist。在这种情况下,您可以使用一个fread()从磁盘文件中读取studCtr,然后使用它来一次将一个学生对象的fread()循环到 myStud 。在该循环中,您可以打印感兴趣的字段,如下所示:

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

希望这会让你顺利... C中的第一步有点难:D

答案 1 :(得分:1)

myStud.studs是指向学生的指针,但我看不到您实际分配该学生的位置。在完成&myStud.studs->idNo之类的工作之前,您需要对学生进行malloc。

答案 2 :(得分:0)

简而言之,不要编写指向文件的指针,以后它们将毫无意义。

典型的方法是首先写出项目的计数,然后循环遍历列表中的每个项目并单独写出。

在读者端:

  1. 阅读物品数量。
  2. 分配足够的内存来容纳所有项目。
  3. 阅读每个项目。

答案 3 :(得分: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

答案 4 :(得分: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