user-0 提问: 求大神帮忙啊，文件的读取与链表

回复:
user: user-0
content: 引用 7 楼 cfjtaishan 的回复:#include <stdio.h> #include <stdlib.h> #include <string.h> //#include <conio.h>  typedef struct exams {     int num;     char question[30];     char a[10];     char b[10];     char c[10];     char d[10];     char ans[30]; }exams_obj, *exams_handle;  typedef struct test {     exams_obj exam;     struct test *next; }tests;  tests *add_exams_list(tests **pphead) {     int choice;     tests *pnew, *prev, *pcur;     pnew = (tests *)malloc(sizeof(tests));     if (!pnew) {         fprintf(stderr, "malloc error!\n");         exit(0);     }     printf("请开始添加试题!\n");      prev = *pphead;     if (prev) {         pcur = prev->next;         while (pcur) {             prev = pcur;             pcur = pcur->next;         }     }      while(1) {         printf("请输入题号:\n");         scanf("%d", &pnew->exam.num);         printf("第%d题题干为:\n", pnew->exam.num);         scanf("%s", pnew->exam.question);         printf("请输入A:\n");         scanf("%s", pnew->exam.a);         printf("请输入B:\n");         scanf("%s", pnew->exam.b);         printf("请输入C:\n");         scanf("%s", pnew->exam.c);         printf("请输入D:\n");         scanf("%s", pnew->exam.d);         printf("请输入答案(a,b,c,d)\n");         scanf("%s", pnew->exam.ans);         if (!(*pphead)) {             *pphead = pnew;             prev = *pphead;         } else {             prev->next = pnew;             prev = pnew;         }         pnew = (tests *)malloc(sizeof(tests));         if (!pnew) {             fprintf(stderr, "malloc error!\n");             exit(0);         }         printf("是否继续添加题目(0/1)(0退出，1继续)\n");         scanf("%d", &choice);         if (choice == 0)             break;     }      prev->next = NULL;     free(pnew);      printf("添加成功!\n");      return (*pphead); }  tests *remove_exams_list(tests **pphead) {     test *pcur, *prev;     int num;     printf("请输入你想删除的题目的序号:\n");     scanf("%d",&num);     prev = *pphead;     if(num == 1) {         prev = *pphead;         *pphead = (*pphead)->next;         free(prev);         printf("删除成功!");         return(*pphead);     }     pcur = prev->next;     while (pcur) {         if (pcur->exam.num == num) {             prev->next = pcur->next;             free(pcur);             break;         }         pcur = pcur->next;     }     printf("删除成功!");     return(*pphead); }  tests *modify_exams_list(tests **pphead)//更改题目 {     int num;     tests *pcur = *pphead;;     printf("请输入你想更改的题目的题号:\n");     scanf("%d", &num);      while (pcur) {         if(pcur->exam.num == num)             break;         pcur = pcur->next;     }     if (!pcur) {         fprintf(stdout, "Can't find the number!\n");         return *pphead;     }     printf("请输入第%d题的题干:\n",num);     scanf("%s",pcur->exam.question);     printf("请输入A:\n");     scanf("%s",pcur->exam.a);     printf("请输入B:\n");     scanf("%s",pcur->exam.b);     printf("请输入C:\n");     scanf("%s",pcur->exam.c);     printf("请输入D:\n");     scanf("%s",pcur->exam.d);     printf("请输入答案(a,b,c,d)\n");     scanf("%s",pcur->exam.ans);     printf("更改成功!\n");      return(*pphead); }  void load_exams_list(tests **pphead) {     FILE *fp;     tests *pnew, *prev = *pphead;      if (!(fp = fopen("tests2.txt","r"))) {         printf("can not open file\n");         return;     }     pnew = (tests *)malloc(sizeof(tests));     if (!pnew) {         fprintf(stderr, "malloc error!\n");         exit(0);     }     if (1 != fread(&pnew->exam, sizeof(exams_obj), 1, fp)) {         free(pnew);         return;     }     if (!(*pphead)) {         *pphead = pnew;         prev = *pphead;     } else {         prev->next = pnew;         prev = pnew;     }      while (!feof(fp)) {         pnew = (tests *)malloc(sizeof(tests));         if (!pnew) {             fprintf(stderr, "malloc error!\n");             exit(0);         }         if (1 != fread(&pnew->exam, sizeof(exams_obj), 1, fp))             break;         prev->next = pnew;         prev = pnew;     }      prev->next = NULL; }  void show_exams_list(tests *phead) {     tests *pcur = phead;      while (pcur) {         printf("第%d题\nquestion:%s\nA.%s\nB.%s\nC.%s\nD.%s\nanswer:%s\n",                 pcur->exam.num, pcur->exam.question, pcur->exam.a,                 pcur->exam.b, pcur->exam.c, pcur->exam.d, pcur->exam.ans);         pcur = pcur->next;     } }  void save_exams_list(tests *phead) {     FILE *fp;     tests *pcur;      fp = fopen("tests2.txt","w");     if (!fp) {         fprintf(stderr, "open file error!\n");         return;     }      pcur = phead;     while (pcur) {         if (fwrite(&pcur->exam, sizeof(exams_obj), 1, fp) != 1)             printf("file write error!\n");         pcur = pcur->next;     }     printf("保存成功!\n按回车键返回!\n");     fclose(fp); }  void menu(void) {     printf("                            ^^^^^^^***^^^^^^^\n");     printf("                    ------- 欢迎进入考试系统 -------\n");     printf("                         ^^^^^ 1:题目管理 ^^^^^\n");     printf("                           *** 2:开始考试 ***\n");     printf("                             ~ 3:退出系统 ~\n");     printf("                           ^^^^^^^***^^^^^^^\n"); }  void submenu(void) {     printf("                        *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");     printf("                        *          1:添加题目         *\n");     printf("                        *          2:修改题目         *\n");     printf("                        *          3:删除题目         *\n");     printf("                        *          4:显示题目         *\n");     printf("                        *          5:保存题目         *\n");     printf("                        *          6:返回主菜单       *\n");     printf("                        *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n"); }  void manage_exams(tests **pphead) {     int choice;      while (1) {         submenu();         printf("Please input your choice: ");         scanf("%d", &choice);          switch (choice) {             case 1:                 add_exams_list(pphead);                 break;              case 2:                 modify_exams_list(pphead);                 break;              case 3:                 remove_exams_list(pphead);                 break;              case 4:                 show_exams_list(*pphead);                 break;              case 5:                 save_exams_list(*pphead);                 break;              case 6:                 return;              default:                 printf("Input error!\n");         }     } }  int main() {     tests *phead = NULL;      load_exams_list(&phead);      int choice;     while (1) {         menu();         printf("Please input your choice: ");         scanf("%d", &choice);         switch (choice) {             case 1:                 manage_exams(&phead);                 break;              case 2:                 break;              case 3:                 exit(0);                 break;              default:                 printf("Input error!\n");                 break;         }     }     return 0; }  如果让我去做这个题目，我会考虑这样实现；还有很多地方需要优化，包括数据结构的定义，函数的调用等等；  参考一下吧 如果想继续做编程，建议还是要学好基础知识  谢谢大神

user: user-1
content: #include <stdio.h> #include <stdlib.h> #include <string.h> //#include <conio.h>  typedef struct exams {     int num;     char question[30];     char a[10];     char b[10];     char c[10];     char d[10];     char ans[30]; }exams_obj, *exams_handle;  typedef struct test {     exams_obj exam;     struct test *next; }tests;  tests *add_exams_list(tests **pphead) {     int choice;     tests *pnew, *prev, *pcur;     pnew = (tests *)malloc(sizeof(tests));     if (!pnew) {         fprintf(stderr, "malloc error!\n");         exit(0);     }     printf("请开始添加试题!\n");      prev = *pphead;     if (prev) {         pcur = prev->next;         while (pcur) {             prev = pcur;             pcur = pcur->next;         }     }      while(1) {         printf("请输入题号:\n");         scanf("%d", &pnew->exam.num);         printf("第%d题题干为:\n", pnew->exam.num);         scanf("%s", pnew->exam.question);         printf("请输入A:\n");         scanf("%s", pnew->exam.a);         printf("请输入B:\n");         scanf("%s", pnew->exam.b);         printf("请输入C:\n");         scanf("%s", pnew->exam.c);         printf("请输入D:\n");         scanf("%s", pnew->exam.d);         printf("请输入答案(a,b,c,d)\n");         scanf("%s", pnew->exam.ans);         if (!(*pphead)) {             *pphead = pnew;             prev = *pphead;         } else {             prev->next = pnew;             prev = pnew;         }         pnew = (tests *)malloc(sizeof(tests));         if (!pnew) {             fprintf(stderr, "malloc error!\n");             exit(0);         }         printf("是否继续添加题目(0/1)(0退出，1继续)\n");         scanf("%d", &choice);         if (choice == 0)             break;     }      prev->next = NULL;     free(pnew);      printf("添加成功!\n");      return (*pphead); }  tests *remove_exams_list(tests **pphead) {     test *pcur, *prev;     int num;     printf("请输入你想删除的题目的序号:\n");     scanf("%d",&num);     prev = *pphead;     if(num == 1) {         prev = *pphead;         *pphead = (*pphead)->next;         free(prev);         printf("删除成功!");         return(*pphead);     }     pcur = prev->next;     while (pcur) {         if (pcur->exam.num == num) {             prev->next = pcur->next;             free(pcur);             break;         }         pcur = pcur->next;     }     printf("删除成功!");     return(*pphead); }  tests *modify_exams_list(tests **pphead)//更改题目 {     int num;     tests *pcur = *pphead;;     printf("请输入你想更改的题目的题号:\n");     scanf("%d", &num);      while (pcur) {         if(pcur->exam.num == num)             break;         pcur = pcur->next;     }     if (!pcur) {         fprintf(stdout, "Can't find the number!\n");         return *pphead;     }     printf("请输入第%d题的题干:\n",num);     scanf("%s",pcur->exam.question);     printf("请输入A:\n");     scanf("%s",pcur->exam.a);     printf("请输入B:\n");     scanf("%s",pcur->exam.b);     printf("请输入C:\n");     scanf("%s",pcur->exam.c);     printf("请输入D:\n");     scanf("%s",pcur->exam.d);     printf("请输入答案(a,b,c,d)\n");     scanf("%s",pcur->exam.ans);     printf("更改成功!\n");      return(*pphead); }  void load_exams_list(tests **pphead) {     FILE *fp;     tests *pnew, *prev = *pphead;      if (!(fp = fopen("tests2.txt","r"))) {         printf("can not open file\n");         return;     }     pnew = (tests *)malloc(sizeof(tests));     if (!pnew) {         fprintf(stderr, "malloc error!\n");         exit(0);     }     if (1 != fread(&pnew->exam, sizeof(exams_obj), 1, fp)) {         free(pnew);         return;     }     if (!(*pphead)) {         *pphead = pnew;         prev = *pphead;     } else {         prev->next = pnew;         prev = pnew;     }      while (!feof(fp)) {         pnew = (tests *)malloc(sizeof(tests));         if (!pnew) {             fprintf(stderr, "malloc error!\n");             exit(0);         }         if (1 != fread(&pnew->exam, sizeof(exams_obj), 1, fp))             break;         prev->next = pnew;         prev = pnew;     }      prev->next = NULL; }  void show_exams_list(tests *phead) {     tests *pcur = phead;      while (pcur) {         printf("第%d题\nquestion:%s\nA.%s\nB.%s\nC.%s\nD.%s\nanswer:%s\n",                 pcur->exam.num, pcur->exam.question, pcur->exam.a,                 pcur->exam.b, pcur->exam.c, pcur->exam.d, pcur->exam.ans);         pcur = pcur->next;     } }  void save_exams_list(tests *phead) {     FILE *fp;     tests *pcur;      fp = fopen("tests2.txt","w");     if (!fp) {         fprintf(stderr, "open file error!\n");         return;     }      pcur = phead;     while (pcur) {         if (fwrite(&pcur->exam, sizeof(exams_obj), 1, fp) != 1)             printf("file write error!\n");         pcur = pcur->next;     }     printf("保存成功!\n按回车键返回!\n");     fclose(fp); }  void menu(void) {     printf("                            ^^^^^^^***^^^^^^^\n");     printf("                    ------- 欢迎进入考试系统 -------\n");     printf("                         ^^^^^ 1:题目管理 ^^^^^\n");     printf("                           *** 2:开始考试 ***\n");     printf("                             ~ 3:退出系统 ~\n");     printf("                           ^^^^^^^***^^^^^^^\n"); }  void submenu(void) {     printf("                        *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");     printf("                        *          1:添加题目         *\n");     printf("                        *          2:修改题目         *\n");     printf("                        *          3:删除题目         *\n");     printf("                        *          4:显示题目         *\n");     printf("                        *          5:保存题目         *\n");     printf("                        *          6:返回主菜单       *\n");     printf("                        *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n"); }  void manage_exams(tests **pphead) {     int choice;      while (1) {         submenu();         printf("Please input your choice: ");         scanf("%d", &choice);          switch (choice) {             case 1:                 add_exams_list(pphead);                 break;              case 2:                 modify_exams_list(pphead);                 break;              case 3:                 remove_exams_list(pphead);                 break;              case 4:                 show_exams_list(*pphead);                 break;              case 5:                 save_exams_list(*pphead);                 break;              case 6:                 return;              default:                 printf("Input error!\n");         }     } }  int main() {     tests *phead = NULL;      load_exams_list(&phead);      int choice;     while (1) {         menu();         printf("Please input your choice: ");         scanf("%d", &choice);         switch (choice) {             case 1:                 manage_exams(&phead);                 break;              case 2:                 break;              case 3:                 exit(0);                 break;              default:                 printf("Input error!\n");                 break;         }     }     return 0; }  如果让我去做这个题目，我会考虑这样实现；还有很多地方需要优化，包括数据结构的定义，函数的调用等等；  参考一下吧 如果想继续做编程，建议还是要学好基础知识

user: user-2
content: 推荐使用WinHex软件查看硬盘或文件或内存中的原始字节内容。  不要把 fopen("...","...");fscanf,fprintf,fgets,fgetc,fclose //读时把\r\n替换成\n，写时把\n替换成\r\n;读到\x1a就设置EOF;读写的内容当字符看待 和 fopen("...","...b");fseek,ftell,fread,fwrite,fgetc,fclose //不作以上替换，遇到\x1a仍继续读;读写的内容当字节看待 弄混了

user: user-0
content: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h>  #define LEN sizeof(struct Test)  struct Test { 	int num; 	char que[100]; 	char a[30]; 	char b[30]; 	char c[30]; 	char d[30]; 	char ans[30]; 	struct Test *next; }; typedef struct Test Test; Test *head=NULL; //保存试题  void save(Test *head) { 	system("cls"); 	FILE *fp; 	Test *p; 	p=head; 	if(p==NULL)  	{ 		printf("无法保存文件!\n"); 		printf("输入任意键返回上一级\n");          getch();         Mmenu2();		 	} 	fp=fopen("Test.dat","wb"); 	while(p!=NULL) 	{ 		fwrite(&p,LEN,1,fp); 		p=(*p).next; 	} 	fclose(fp); 	printf("保存成功！\n") ; 	printf("输入任意键返回上一级\n");      getch();     Mmenu2();		 } //查看题目  void print() {        system("cls");     FILE *fp;     Test *p;     if((fp=fopen("Test.dat","rb"))==NULL) 	{ 		printf("无法打开文件!\n"); 		printf("输入任意键返回上一级\n");          getch();         Mmenu2();		 	} 	else 	{    	    fp=fopen("Test.dat","rb"); 		rewind(fp); 	    printf("数据加载成功!\n"); 	    fread(&p,LEN,1,fp); 		while(p!=NULL)         {            	printf("题号：");             printf("%d\n",(*p).num);             printf("问题：");             printf("%s\n",(*p).que);             printf("A选项：");             printf("%s\n",(*p).a);             printf("B选项：");             printf("%s\n",(*p).b);             printf("C选项：");             printf("%s\n",(*p).c);             printf("D选项：");             printf("%s\n",(*p).d);             printf("答案：");             printf("%s\n",(*p).ans);             p=(*p).next;         } 	} 	fclose(fp);  	printf("输入任意键返回上一级\n");      getch();     Mmenu2();      } //新增题目  Test *add(Test *head) { 	system("cls"); 	int i; 	head=NULL; 	Test *p1,*p2; 	p1=p2=(Test *)malloc(LEN); 	printf("请输入题号："); 	scanf("%d",&(*p1).num); 	printf("请输入问题："); 	scanf("%s",(*p1).que); 	printf("请输入A选项："); 	scanf("%s",(*p1).a); 	printf("请输入B选项："); 	scanf("%s",(*p1).b); 	printf("请输入C选项："); 	scanf("%s",(*p1).c); 	printf("请输入D选项："); 	scanf("%s",(*p1).d); 	printf("请输入答案："); 	scanf("%s",(*p1).ans); 	printf("添加成功！\n\n");  	while(1) 	{ 		if((*p1).num==1) 		{ 			head=p1; 		} 		else 		{ 			(*p2).next=p1; 			p2=p1; 		} 		printf("是否继续添加？ 1.是 2.退出\n"); 		scanf("%d",&i);		 		if(i==2) break; 		p1=(Test *)malloc(LEN); 		printf("请输入题号："); 	    scanf("%d",&(*p1).num); 	    printf("请输入问题："); 	    scanf("%s",(*p1).que); 	    printf("请输入A选项："); 	    scanf("%s",(*p1).a); 	    printf("请输入B选项："); 	    scanf("%s",(*p1).b); 	    printf("请输入C选项："); 	    scanf("%s",(*p1).c); 	    printf("请输入D选项："); 	    scanf("%s",(*p1).d); 	    printf("请输入答案："); 	    scanf("%s",(*p1).ans); 	    printf("添加成功！\n\n");  	} 	(*p2).next=NULL;     return(head); } //删除题目 Test *del(Test *head) { 	system("cls");  	int num; 	Test *p1,*p2; 	p1=head; 	if(p1==NULL) 	{ 		printf("没有已添加题目!\n"); 		printf("输入任意键返回上一级\n");          getch();         Mmenu2();		 	} 	printf("输入需要删除的题号:"); 	scanf("%d",&num); 	if(num==1) 	{ 		head=(*p1).next; 		free(p1); 		printf("删除成功!\n"); 		return(head); 	} 	while(1) 	{ 	 	if(p1->next->num==num) break; 		else p1=(*p1).next;     } 	if((*p1).next!=NULL) 	{ 		p2=(*p1).next; 		(*p1).next=(*p2).next; 		free(p2); 		printf("删除成功!\n"); 	}      return(head); } //修改题目  Test *cha(Test *head)  { 	system("cls");  	int num; 	Test *p1; 	p1=head; 	if(p1==NULL) 	{ 		printf("没有已添加题目!\n"); 		printf("输入任意键返回上一级\n");          getch();         Mmenu2();		 	} 	printf("输入需要更改的题号:"); 	scanf("%d",&num); 	while(1) 	{ 		if((*p1).num==num) break; 		p1=(*p1).next; 	} 	printf("请输入问题：",num); 	scanf("%s",(*p1).que); 	printf("请输入A选项："); 	scanf("%s",(*p1).a); 	printf("请输入B选项："); 	scanf("%s",(*p1).b); 	printf("请输入C选项："); 	scanf("%s",(*p1).c); 	printf("请输入D选项："); 	scanf("%s",(*p1).d); 	printf("请输入答案："); 	scanf("%s",(*p1).ans); 	printf("更改成功!\n");     return(head); } //主菜单 void Mmenu1() { 	    system("cls"); 	    int n; 		printf("************************************************\n"); 	    printf("\t\t欢迎进入考试系统!\n");  	    printf("\t\t1.题目管理\n"); 	    printf("\t\t2.开始考试\n"); 	    printf("\t\t3.退出\n");  	    printf("************************************************\n"); 	    printf("请输入你的选择：");  	    scanf("%d",&n); 	    switch(n)         { 		    case 1:Mmenu2();break; 		    case 2:Mmenu3();break; 		    case 3:system("cls");printf("感谢您的使用！\n");exit(0); 		    default:system("cls");printf("输入错误，输入任意键返回上一级！\n");getch();Mmenu1(); 	      } } //题目管理菜单  void Mmenu2() { 	    system("cls"); 	    int n; 		printf("************************************************\n"); 	    printf("\t\t1.新增题目\n");  	    printf("\t\t2.删除题目\n"); 	    printf("\t\t3.修改题目\n"); 	    printf("\t\t4.查看题目\n"); 	    printf("\t\t5.保存题目\n"); 	    printf("\t\t6.返回上一级\n"); 	    printf("************************************************\n"); 	    printf("请输入你的选择："); 		scanf("%d",&n); 	    switch(n) 	    { 		    case 1:head=add(head);Mmenu2();break; 		    case 2:head=del(head);printf("输入任意键返回上一级\n");getch();Mmenu2();break; 		    case 3:head=cha(head);printf("输入任意键返回上一级\n");getch();Mmenu2();break; 		    case 4:print();break;  		    case 5:save(head);break;  		    case 6:Mmenu1();break;  		    default:system("cls");printf("输入错误，输入任意键返回上一级！\n");getch();Mmenu2();  	      } } //开始考试菜单 void Mmenu3() { 	 }  int main() { 	Mmenu1(); 	 	return 0; }

user: user-1
content: 引用 3 楼 ck823718831 的回复:[quote=引用 2 楼 cfjtaishan 的回复:] 删除上一个帖子，然后重新发帖，那么别人回复的内容有没有思考和尝试呢。 还是建议好好学习吧，不要等到期末考试或要编程做项目时再来临时抱佛脚； 本来链表就是比较难理解和使用的地方，对指针要求比较高。 不好意思，上一个帖子的回复还没看到就被删除了。 项目要求添加完题目后要保存到文件，关闭程序后，重新打开可直接读取文件数据。[/quote] 但是从这个需求上没说，要在显示的时候去读文件，因此，显示就是显示，通过遍历链表输出即可，加载文件内容，可以在main函数第一件事情去做，不论文件有没有，存不存在。

user: user-0
content: 引用 2 楼 cfjtaishan 的回复:删除上一个帖子，然后重新发帖，那么别人回复的内容有没有思考和尝试呢。 还是建议好好学习吧，不要等到期末考试或要编程做项目时再来临时抱佛脚； 本来链表就是比较难理解和使用的地方，对指针要求比较高。 不好意思，上一个帖子的回复还没看到就被删除了。 项目要求添加完题目后要保存到文件，关闭程序后，重新打开可直接读取文件数据。

user: user-1
content: 删除上一个帖子，然后重新发帖，那么别人回复的内容有没有思考和尝试呢。 还是建议好好学习吧，不要等到期末考试或要编程做项目时再来临时抱佛脚； 本来链表就是比较难理解和使用的地方，对指针要求比较高。

user: user-1
content: void look(test*head)//显示题目 { system("cls"); FILE *fp;     test*p;     if((fp=fopen("tests2.txt","r"))==NULL)     {      printf("can not open file\n");      fclose(fp); } while(p!=NULL) { fread(p,sizeof(tests),1,fp); printf("第%d题\nquestion:%s\nA.%s\nB.%s\nC.%s\nD.%s\nanswer:%s\n",p->num,p->question,p->a,p->b,p->c,p->d,p->ans); p=p->next; } fclose(fp); printf("试题显示完成!\n按回车键返回!\n"); getch(); menu2(); }  问题出在p是野指针，没有分配空间呢。我记得在另一个帖子里已经回复这个问题了。 再说你定义形参head做什么？定义了，没有用。 个人认为，程序启动时，就要先从文件里去读（若文件存在并有数据，否则链表头为NULL）；显示题目功能，只需要遍历链表输出即可，没必要从文件里读，因为最新数据应该是在内存里，而非文件里。