我正在尝试在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()错了?我遇到我的程序再次停止工作的另一种情况是我调用我的显示功能。它显示了一些东西,但外来/垃圾值。
以下是我在扫描功能中遇到问题的屏幕截图:
这是我的显示功能:
我希望有人可以帮助我。谢谢!
答案 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)
简而言之,不要编写指向文件的指针,以后它们将毫无意义。
典型的方法是首先写出项目的计数,然后循环遍历列表中的每个项目并单独写出。
在读者端:
答案 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