我记得当时一个晚上多一点敲了500多行,后来debug了两天。。。
以后写东西还是踏实一点,写一个功能就测试一下,不要一股脑往下写,不然一堆bug真的会de到吐魂。。。
写这篇博客主要是记录一下de最久的一部分,就是链表数据向文件中的存入和读取
1. 我这里是将整个结点存入数据 => 每次存取都要用循环一个一个存取
2. 我这里是整条链表存进去(覆盖),而非追加结点进去 => wb+(覆盖)
要注意的是:一开始我的写法是ab+ 和 rewind重定位到文件头部进行文件重写;但是,经过漫长时间的测试以及和老师的交流发现 => 如果是ab+那rewind就不起作用,必须用wb+。
更离谱的是用Dev跑和用Clion一个是追加,一个是覆盖。
// 这里文件读入的时候读入文件的链表是没有头节点的
void Write(FILE* f, List head) {
List p = head;
while(p) {
fwrite(p, SIZE, 1, f);
p = p->next;
}
printf(" Success Write!\n\n");
}
// 在从文件中读出链表数据(没有头节点)的时候自动添加上头节点
List Read(FILE* f) {
List dummy = (List)malloc(sizeof(Node));
dummy->next = NULL;
List head = dummy;
int n = getCount(f);
for(int i = 0; i < n; i++) {
List p = (List)malloc(sizeof(Node));
fread(p, SIZE, 1, f);
head->next = p;
head = p;
}
printf(" Success Read!\n\n");
return dummy;
}
最后大作业开源,仅提供思路用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct Subject {
char name[18];
double scores[100];
int count;
double sum;
double aver;
} Subject;
typedef struct Node{
char name[18];
char uuid[18];
Subject subject[5];
int FailedSubjectCount;
double aver;
struct Node* next;
} Node, Student, *List;
long SIZE;
#define FILENAME "test.txt"
int cmpD_bySubject(const void* a, const void* b);
List InitialList();
int getCount(FILE* f);
void Write(FILE* f, List head);
List Read(FILE* f);
List DSortList(List head);
List ASortList(List head);
char Menu();
void Add(FILE* f);
bool FindStudent(FILE* f);
void ListALL(FILE* f);
void Del(FILE* f);
void Update(FILE* f);
void FindFailed(FILE* f);
void FindTop(FILE* f);
void FindAverage(FILE* f);
int main() {
FILE *fp;
if((fp = fopen(FILENAME, "ab+")) == NULL) {
printf("\n can't open this file!\n\n\n\n");
exit(0);
}
char choice;
SIZE = sizeof(Node);
while(( choice = Menu()) != '0') {
switch (choice) {
case '1':
fp = fopen(FILENAME, "ab+");
Add(fp);
break;
case '2':
fp = fopen(FILENAME, "ab+");
printf("\n --------------------------Search record---------------------------\n\n");
printf(" 1.Single student 2.Average Score\n\n");
printf(" 3.Fail Exam 4.Top 5 student\n\n");
printf(" 0.Exit\n\n");
printf(" ------------------------------------------------------------------\n\n");
printf(" Please give your choice: ");
char Choice;
scanf("%c", &Choice);
getchar();
if(Choice == '3') FindFailed(fp);
else if(Choice == '4') FindTop(fp);
else if(Choice == '2') FindAverage(fp);
else if(Choice == '1') FindStudent(fp);
else if(Choice == '0') {
printf("\n\n");
break;
}
else printf("Error Input!\n\n");
break;
case '3':
fp = fopen(FILENAME, "ab+");
Del(fp);
break;
case '4':
fp = fopen(FILENAME, "rb+");
Update(fp);
break;
case '5':
fp = fopen(FILENAME, "ab+");
ListALL(fp);
break;
case '6':
system("cls");
break;
default:
printf("\n\n\n\n Error, please input again!\n\n\n\n");
break;
}
}
if(fclose(fp)) {
printf("can't close the file!\n");
exit(0);
}
return 0;
}
int cmpD_bySubject(const void* a, const void* b) {
return ((Subject*)b)->aver - ((Subject*)a)->aver;
}
List InitialList() {
List dummy = (List)malloc(sizeof(Node));
dummy->next = NULL;
dummy->FailedSubjectCount = -1;
dummy->aver = -1;
return dummy;
}
int getCount(FILE* f) {
long begin, end;
fseek(f, 0L, SEEK_SET);
begin = ftell(f);
fseek(f, SIZE, SEEK_END);
end = ftell(f);
// 在这里将文件的重定位到文件头部 不影响后续操作
rewind(f);
return (int)((end - begin) / SIZE - 1);
}
// 这里文件读入的时候读入文件的链表是没有头节点的
void Write(FILE* f, List head) {
List p = head;
while(p) {
fwrite(p, SIZE, 1, f);
p = p->next;
}
printf(" Success Write!\n\n");
}
// 在从文件中读出链表数据(没有头节点)的时候自动添加上头节点
List Read(FILE* f) {
List dummy = (List)malloc(sizeof(Node));
dummy->next = NULL;
List head = dummy;
int n = getCount(f);
for(int i = 0; i < n; i++) {
List p = (List)malloc(sizeof(Node));
fread(p, SIZE, 1, f);
head->next = p;
head = p;
}
printf(" Success Read!\n\n");
return dummy;
}
// 对链表进行插入排序(降序)
List DSortList(List head) {
if(!head || !head->next) return head;
List last = head->next;
head->next = NULL;
List dummy = (List)malloc(sizeof(Node));
dummy->aver = INT_MAX;
dummy->next = head;
List p = last;
while(p) {
last = p->next;
p->next = NULL;
List temp = dummy;
while(temp) {
if(temp->next == NULL || (temp->aver >= p->aver && temp->next->aver <= p->aver) ) {
p->next = temp->next;
temp->next = p;
break;
}
temp = temp->next;
}
p = last;
}
return dummy->next;
}
// 对链表进行插入排序(升序)
List ASortList(List head) {
if(!head || !head->next) return head;
List last = head->next;
head->next = NULL;
List dummy = (List)malloc(sizeof(Node));
dummy->aver = INT_MIN;
dummy->next = head;
List p = last;
while(p) {
last = p->next;
p->next = NULL;
List temp = dummy;
while(temp) {
if(temp->next == NULL || (temp->aver <= p->aver && temp->next->aver >= p->aver) ) {
p->next = temp->next;
temp->next = p;
break;
}
temp = temp->next;
}
p = last;
}
return dummy->next;
}
char Menu() {
char choice;
printf(" --------------------------Management for Students' Information---------------------------\n\n");
printf(" 1.Append record 2.Search record\n\n");
printf(" 3.Delete record 4.Modify record\n\n");
printf(" 5.List All Students 6.Clean the Window\n\n");
printf(" 0.Exit\n\n");
printf(" -----------------------------------------------------------------------------------------\n\n");
printf(" Please give your choice: ");
scanf("%c", &choice);
getchar();
return choice;
}
void Add(FILE* f) {
int n;
int NodeCount = getCount(f);
List tail = NULL;
List head = NULL;
// 判断文件中有没有结点 => 拿头节点
// 这里的链表都是自带头节点的
if(!NodeCount) {
tail = InitialList();
head = tail;
}else {
tail = Read(f);
head = tail;
while(tail->next) tail = tail->next;
}
printf(" please input the number of student you want to append.\n ");
scanf("%d", &n);
getchar();
while(n--) {
List stu = (List)malloc(sizeof(Node));
stu->FailedSubjectCount = 0;
stu->aver = 0;
stu->next = NULL;
printf(" Input the student's name:\n ");
scanf("%s", stu->name);
getchar();
printf(" Input the student's uuid:\n ");
scanf("%s", stu->uuid);
getchar();
// 此题限定四门课程
strcpy(stu->subject[0].name, "Calculus");
strcpy(stu->subject[1].name, "Linear Algebra");
strcpy(stu->subject[2].name, "Physics");
strcpy(stu->subject[3].name, "Programme C");
double average = 0;
for (int i = 0; i < 4; i++) {
double score = 0;
int k = 0;
stu->subject[i].sum = 0, stu->subject[i].aver = 0;
printf(" Input the scores of %s (-1 stands for stop):\n ", stu->subject[i].name);
while (~scanf("%lf", &score) && score != -1) {
getchar();
if(score < 60) (stu->FailedSubjectCount)++;
stu->subject[i].scores[k++] = score;
stu->subject[i].sum += score;
}
// 最后一个score == -1的输入不会进入while内部 => getchar()要写在外面
getchar();
stu->subject[i].count = k;
stu->subject[i].aver = stu->subject[i].sum / (k * 1.0);
average += stu->subject[i].aver;
}
stu->aver = average / 4.0;
printf(" Press any key to write the information.\n\n\n\n");
getch();
tail->next = stu;
tail = stu;
}
// 整条读入 => 每次新增都是覆盖原有文件数据
f = fopen(FILENAME, "wb+");
Write(f, head->next);
printf(" Add Over!\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}
bool FindStudent(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return false;
}
List head = Read(f)->next;
printf(" Input the student's UUID or NAME to search it's information.\n ");
char infor[18];
scanf("%s", infor);
getchar();
List p = head;
while (p) {
// 需要注意的是strcmp对于相同字符串返回0
if ((!strcmp(p->uuid, infor)) || (!strcmp(p->name, infor))) {
printf("\n Name Uuid \n\n");
printf(" %8s %8s\n\n", p->name, p->uuid);
for (int i = 0; i < 4; i++) {
printf(" %s: ", p->subject[i].name);
for (int j = 0; j < p->subject[i].count; j++) {
printf("%.2lf ", p->subject[i].scores[j]);
}
printf("\n Average: %.2lf\n\n", p->subject[i].aver);
}
break;
}
p = p->next;
}
printf(" That's the student's information in this File.\n\n\n\n");
if(p == NULL) {
printf(" Can't find this student!\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return false;
}
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return true;
}
void ListALL(FILE* f) {
int count = getCount(f);
printf("\n\n The number of the students = %d\n\n", count);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
fclose(f);
return;
}
List p = Read(f)->next;
printf("\n Name Uuid \n\n");
while (p) {
printf(" %8s %8s\n\n", p->name, p->uuid);
for (int i = 0; i < 4; i++) {
printf(" %s: ", p->subject[i].name);
for (int j = 0; j < p->subject[i].count; j++) {
printf("%.2lf ", p->subject[i].scores[j]);
}
printf("\n Average: %.2lf\n\n", p->subject[i].aver);
}
p = p->next;
printf("\n\n");
}
printf(" That's all students in this File.\n\n\n\n");
}
void Del(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if(!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return;
}
List dummy = Read(f);
printf(" Input the student's UUID or NAME to Delete it's information.\n ");
char infor[18];
scanf("%s", infor);
getchar();
List p = dummy;
while (p->next) {
List stu = p->next;
// 需要注意的是strcmp对于相同字符串返回0
if (!strcmp(stu->uuid, infor) || !strcmp(stu->name, infor)) {
printf(" Have found the student, are you sure to delete it?(Y/N)\n ");
char judge;
scanf("%c", &judge);
getchar();
// 用户选择继续修改后执行
if(judge == 'Y' || judge == 'y') {
p->next = p->next->next;
printf(" Success Delete!\n\n");
f = fopen(FILENAME, "wb+");
Write(f, dummy->next);
}
break;
}
p = p->next;
}
if(p == NULL) {
printf(" Can't find this student!\n\n\n\n");
}
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}
void Update(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return;
}
List dummy = Read(f);
printf(" Input the student's UUID or NAME to Modify it's information.\n ");
char infor[18];
scanf("%s", infor);
getchar();
List p = dummy->next;
while (p) {
// 需要注意的是strcmp对于相同字符串返回0
if (!strcmp(p->uuid, infor) || !strcmp(p->name, infor)) {
printf("\n Name Uuid \n\n");
printf(" %8s %8s\n\n", p->name, p->uuid);
for (int i = 0; i < 4; i++) {
printf(" %s: ", p->subject[i].name);
for (int j = 0; j < p->subject[i].count; j++) {
printf("%.2lf ", p->subject[i].scores[j]);
}
printf("\n");
}
printf(" Have found the student, are you sure to modify it?(Y/N)\n ");
char judge;
scanf("%c", &judge);
getchar();
// 用户选择继续修改后执行
if (judge == 'Y' || judge == 'y') {
printf("\n Input the student's name:\n ");
scanf("%s", p->name);
getchar();
printf("\n Input the student's uuid:\n ");
scanf("%s", p->uuid);
getchar();
printf("\n Input each score of this student(-1 stands for stop):\n");
for (int i = 0; i < 4; i++) {
double score = 0, sum = 0;
int k = 0;
p->subject[i].sum = 0, p->subject[i].aver = 0;
p->FailedSubjectCount = 0, p->aver = 0;
printf(" Input the scores of %s (-1 stands for stop):\n ", p->subject[i].name);
while (~scanf("%lf", &score) && score != -1) {
getchar();
if(score < 60) (p->FailedSubjectCount)++;
p->subject[i].scores[k++] = score;
p->subject[i].sum += score;
}
getchar();
p->subject[i].count = k;
p->subject[i].aver = sum / (k * 1.0);
}
printf(" Success Modification!\n\n");
f = fopen(FILENAME, "wb+");
Write(f, dummy->next);
}
break;
}
p = p->next;
}
if(p == NULL) {
printf(" Can't find this student!\n\n\n\n");
}
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}
void FindFailed(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return;
}
List dummy = Read(f);
List p = dummy->next;
int FailedPersonCount = 0, FailedSubjectCount = 0;
while(p) {
if(p->FailedSubjectCount > 0) {
FailedPersonCount++;
FailedSubjectCount += p->FailedSubjectCount;
}
p = p->next;
}
printf(" The number of Failed Person: %d\n", FailedPersonCount);
printf(" The number of Failed Subject: %d\n\n", FailedSubjectCount);
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}
void FindTop(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return;
}
List dummy = Read(f);
printf(" See Top5 or Last5(T/L)\n\n");
char choice;
scanf("%c", &choice);
getchar();
// 考虑到学生数量不足5个时,
if(count > 5) count = 5;
if(choice == 'T' || choice == 't') {
List Top = DSortList(dummy->next);
List p = Top;
for (int i = 1; i <= count; i++) {
printf(" Top%d: %s\n", i, p->name);
p = p->next;
}
}else if(choice == 'L' || choice == 'l') {
List Last = ASortList(dummy->next);
List p = Last;
for (int i = 1; i <= count; i++) {
printf(" Last%d: %s\n", i, p->name);
p = p->next;
}
}
printf("\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}
void FindAverage(FILE* f) {
int count = getCount(f);
// 考虑到代码的健壮性 当文件中没有数据的时候提示用户
if (!count) {
printf(" Empty File!\n\n\n\n");
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
return;
}
List dummy = Read(f);
List p = dummy->next;
// 对课程类进行初始化
Subject subject[5];
for(int i = 0; i < 4; i++) {
subject[i].sum = 0;
subject[i].aver = 0;
subject[i].count = 0;
}
strcpy(subject[0].name, "Calculus");
strcpy(subject[1].name, "Linear Algebra");
strcpy(subject[2].name, "Physics");
strcpy(subject[3].name, "Programme C");
// 导入所有学生的信息进行计算每门课程的平均分
while(p) {
for(int i = 0; i < 4; i++) {
subject[i].sum += p->subject[i].aver;
subject[i].count++;
}
p = p->next;
}
printf(" Name Average\n\n");
for(int i =0; i < 4; i++) {
subject[i].aver = subject[i].sum / (subject[i].count * 1.0);
printf(" %s: %.2lf\n", subject[i].name, subject[i].aver);
}
printf("\n");
long size = sizeof(Subject);
qsort(subject, 4, size, cmpD_bySubject);
printf(" The highest in average is %s\n", subject[0].name);
printf(" The lowerest in average is %s\n", subject[3].name);
printf(" Press any key to continue.\n\n");
getch();
fclose(f);
}