【问题标题】:Files in C, accessing pointers, reading and writing in filesC中的文件,访问指针,在文件中读写
【发布时间】:2015-01-31 07:28:36
【问题描述】:

我正在尝试用 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 号时,我的程序都会停止工作。为什么它停止工作?我必须 malloc 一些东西吗?还是我在 scanf() 中的访问有误?我遇到我的程序再次停止工作的另一种情况是当我调用我的显示函数时。它显示了一些东西,但是外星人/垃圾值。

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

这是我的显示功能:

我希望有人可以帮助我解决这个问题。谢谢!

【问题讨论】:

  • 不要因为不发布图片而感到难过——这是一个纯文本程序,对吧?图片会添加什么?
  • 截图。对不起,我已经编辑过了。谢谢! @Jongware
  • 这一行:while (fread(&myStud, sizeof(studList), 1, fp)){ 到达文件末尾时不一定会停止。因为它可以返回除 '1' 之外的其他数字,例如在某些错误条件下不为 0。建议:while (1 == fread(&myStud, sizeof(studList), 1, fp)) ) {

标签: c file function pointers structure


【解决方案1】:

你的预感是对的,你确实需要 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() 将内存用于 studs。 sizeof(studlist) 在编译时计算,不可能知道运行时使用的额外内存。另外,这两个内存区域不保证是连续的,所以一个fwrite也不会切。

按照你的代码结构,你最好先 fwrite() studCtr,然后是你为 studs 分配的内存。

对于 displayStudsFromFile(),因为那里只有一个循环,并且没有真正存储供以后使用,所以我只使用

student myStud;

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

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

希望这能让你继续前进...... C 的第一步有点困难:D

【讨论】:

  • 我尝试过使用 malloc,但在尝试编译程序时出现错误。它说“从'void'到'student'的无效转换。我什至没有得到那个错误。
  • 对学生*无效*也许?您是否在 malloc() 之前将演员表添加到 (student*) 中?我后来编辑了它。
  • 我的 malloc 工作了,哈!谢谢!你能告诉我我的显示功能吗?这也是我卡住的地方。每次我调用显示函数时它都会停止我的程序。
  • 我还有一个问题! @kostas,在我放置了 malloc 函数后,我尝试查看我的文件,但里面什么都没有:/ 只是这些垃圾值ဨY〘@。
  • 我再次修改了我的答案,希望这能让您更好地了解代码失败的地方。
【解决方案2】:

myStud.studs 是一个指向学生的指针,但我看不出您实际分配该学生的位置。您需要先 malloc 一个学生,然后才能执行 &myStud.studs->idNo 之类的操作。

【讨论】:

  • 我的 malloc 应该如何处理? myStud = (studList)malloc(sizeof(?))
  • 有几个原因,在 C 中,不强制转换任何 malloc 系列函数的返回值。所以建议删除它。
【解决方案3】:

总之,不要写指向文件的指针,以后就没有意义了。

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

在阅读器端:

  1. 读取项目数。
  2. 分配足够的内存来容纳所有项目。
  3. 读入每一项。

【讨论】:

  • 我明白了,但是我们的导师告诉我们现在在使用文件时要使用这种方法。
【解决方案4】:
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

【讨论】:

    【解决方案5】:
    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
    

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 2014-05-09
      • 2013-05-28
      • 1970-01-01
      • 2023-04-04
      相关资源
      最近更新 更多