实验六歧路与纠错
一、歧路
实验六的程序不算太难,因此我一下午就写完了(好像也挺久),但执行起来却不符合我的预期。
总是存在这样的问题:
输入3个及以上数据时,直接输出的是正确数据,可排序后输出总会有至少一个结构体内的数据是乱的,不是我输入进去的数据。
花费一个下午,可以说有一半时间是因为这个原因。
而且,即使我把程序看了很久,思考了很久,还是没能想到是哪里错了。
二、纠错
在不断的错误后,我暂时放弃了。
时间来到晚上,我突然想起汪老师曾多次强调过debug的重要性。
于是我想到用debug进行调试。
可是,我不会用debug呀(这也是我一下午都没想到使用debug的原因)。
在请教大佬舍友张桓溪后,我大致学会了debug的使用方法。
debug不愧是debug,你大哥还是你大哥。
debug如同摧枯拉朽般指出了我的错误(夸张手法)。
在窗口中,我发现我输入进去的数据与我希望存放的位置竟然不同!
例如,第三组数据并未存放在[2]中,而是在[3]中,第四组数据更是跑到了[6]中去!
突然间,仿佛石破天惊,我想到我在函数中使用的都是指针pt。
在排序函数中,因为会涉及排序,我写的是*(pt+i)
。
在read_information和write_information中,为图方便,我写的是pt+=i;
,循环内直接使用*pt
。
而这两者,是有区别的:
第一种方式,pt指针存放的地址不变。
第二种方式,pt指针不断变化,而且后面的变化在前面的基础之上!
正因为如此,[0] (0+0) > [1] (0+1) > [3] (1+2) > [6] (3+3),这正是我用debug得到的结果!
真相水落石出。
两个解决方法:
1.每次都重置pt,即
在循环开始pt+=i;
在循环结尾pt-=i;
2.pt每次偏移一个元素,即
在循环结尾pt++;
还有一个小插曲,就是解决问题后,有部分数据中平均数有误。
原来是在求平均数函数中,我使用的也是pt+=i
。
三、代码
使用的是解决方法2,因为更简洁美观,且更合理一些。
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student
{
long id;
char name[10];
int scoremt;
int scoreen;
int scoreph;
int total;
float ave;
} STUDENT;
void write_menu();
int read_information(STUDENT *pt);
void calculate_total_and_average(STUDENT *pt,int n);
void sort_by_score(STUDENT *pt,int n);
void sort_by_name(STUDENT *pt,int n);
void write_information(STUDENT *pt,int n);
void search_by_name(STUDENT *pt,int n);
void write_to_file(STUDENT *pt,int n);
void file_to_screen(STUDENT *pt,int n);
int main()
{
int choice,student_number;
STUDENT stu[40];
STUDENT *ps=stu;
write_menu();
do
{
printf("Please enter your choice:");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
student_number=read_information(ps);
break;
}
case 2:
{
calculate_total_and_average(ps,student_number);
break;
}
case 3:
{
sort_by_score(ps,student_number);
write_information(ps,student_number);
break;
}
case 4:
{
sort_by_name(ps,student_number);
write_information(ps,student_number);
break;
}
case 5:
{
sort_by_score(ps,student_number);
search_by_name(ps,student_number);
break;
}
case 6:
{
write_to_file(ps,student_number);
break;
}
case 7:
{
file_to_screen(ps,student_number);
write_information(ps,student_number);
break;
}
case 9:
{
write_information(ps,student_number);
break;
}
}
}
while(choice!=0);
return 0;
}
void write_menu()
{
printf("1.Append record\n");
printf("2.Caculate total and average score of every student\n");
printf("3.Sort in ascending order by total score of every student\n");
printf("4.Sort in dictionary order by name\n");
printf("5.Search by name\n");
printf("6.Write to a file\n");
printf("7.Read from a file\n");
printf("0.Exit\n");
}
int read_information(STUDENT *pt)
{
int n,i;
printf("How many students?\n");
scanf("%d",&n);
for(i=0; i<n; i++)
{
printf("For student %d\n",i+1);
printf("input id:");
scanf("%ld",&(*pt).id);
printf("input name:");
scanf("%s",&(*pt).name);
printf("input score math,English,physics:");
scanf("%d,%d,%d",&(*pt).scoremt,&(*pt).scoreen,&(*pt).scoreph);
pt++;
}
return n;
}
void calculate_total_and_average(STUDENT *pt,int n)
{
int i;
for(i=0; i<n; i++)
{
(*pt).total=(*pt).scoremt+(*pt).scoreen+(*pt).scoreph;
(*pt).ave=(*pt).total/3.0;
pt++;
}
}
void sort_by_score(STUDENT *pt,int n)
{
STUDENT temp;
int i,j,ji;
for(i=0; i<n-1; i++)
{
ji=i;
for(j=i+1; j<n; j++)
{
if((*(pt+ji)).total<(*(pt+j)).total)
ji=j;
}
temp=(*(pt+i));
(*(pt+i))=(*(pt+ji));
(*(pt+ji))=temp;
}
}
void sort_by_name(STUDENT *pt,int n)
{
STUDENT temp;
int i,j,ji;
for(i=0; i<n-1; i++)
{
ji=i;
for(j=i+1; j<n; j++)
{
if(strcmp((*(pt+ji)).name,(*(pt+j)).name)>0)
ji=j;
}
temp=(*(pt+i));
(*(pt+i))=(*(pt+ji));
(*(pt+ji))=temp;
}
}
void write_information(STUDENT *pt,int n)
{
int i;
for(i=0; i<n; i++)
{
printf("student %d:",i+1);
printf("id:%ld,name:%s,",(*pt).id,(*pt).name);
printf("math:%d,English:%d,physics:%d,",(*pt).scoremt,(*pt).scoreen,(*pt).scoreph);
printf("total:%d,average:%f\n",(*pt).total,(*pt).ave);
pt++;
}
}
void search_by_name(STUDENT *pt,int n)
{
char searchname[10];
int i,ji=-1;
printf("name:");
scanf("%s",&searchname);
for(i=0; i<n; i++)
{
if(strcmp((*(pt+i)).name,searchname)==0)
{
ji=i;
pt+=i;
printf("student %d:",i+1);
printf("id:%ld,name:%s,",(*pt).id,(*pt).name);
printf("math:%d,English:%d,physics:%d,",(*pt).scoremt,(*pt).scoreen,(*pt).scoreph);
printf("total:%d,average:%f,",(*pt).total,(*pt).ave);
printf("rank:%d\n",i+1);
}
}
if(ji==-1)
printf("NOT FOUND!\n");
}
void write_to_file(STUDENT *pt,int n)
{
FILE *fp;
if((fp=fopen("student.txt","w"))==NULL)
{
printf("Failure to open student.txt!\n");
exit(0);
}
fwrite(pt,sizeof(STUDENT),n,fp);
fclose(fp);
}
void file_to_screen(STUDENT *pt,int n)
{
int i;
FILE *fp;
if((fp=fopen("student.txt","r"))==NULL)
{
printf("Failure to open student.txt!\n");
exit(0);
}
for(i=0; i<n; i++)
{
fread(pt+i,sizeof(STUDENT),1,fp);
}
fclose(fp);
}
四、经验总结
使用指针要时刻明确指针的指向。