[有史以来最怪的题]我写了个小程序,为什么要兼容模式才能运行[搞得我想杀人]
朋友的作业,写一个小学生成绩管理系统。
我在家用的时候,释放内存到第1502条就崩溃。但是读2次数据就不崩溃了。
在朋友家有的时候,居然读不了文件。只能打开。
但是我无意中启用了windows2k兼容模式,就能用了,并且没有任何故障。
启用95兼容模式的话,能申请内存,但是只能释放掉一个数据。
这是为什么呀?
我的程序里什么都没用呀!都是C标准函数。
就用了一个system( "cls ")来清屏。
不行了! 请各位帮帮忙吧!
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MY_QUIT 2
struct std
{
char ID[11],name[21];
float cj[3];
float num;
struct std *next;
};
int myfree(struct std *head);
int myquit(struct std *head);
int myexit(struct std *head);
struct std *addstd(struct std *head);
struct std *delstd(struct std *head);
int dirall(struct std *head);
struct std *reddat(char *filen,struct std *head);
int whidat(struct std *head);
int main(void)
{
int xx,zt=1;
struct std *HEAD=NULL;
/*HEAD=reddat(NULL,HEAD);
myquit(HEAD);
*/HEAD=reddat(NULL,HEAD);
while(zt!=MY_QUIT)
{
system( "cls ");
xx=0;
puts( "[NUME]\n\n1:添加记录 \n2:删除记录 \n3:显示全部信息 \n4:读取数据库 \n5:写入数据库 \n0: 退出\n ");
printf( "请输入命令: ");
scanf( "%d ",&xx);
system( "cls ");
switch(xx)
{
case 0: zt=myquit(HEAD);break;
case 1: HEAD=addstd(HEAD);break;
case 2: HEAD=delstd(HEAD);break;
case 3: dirall(HEAD);getch();break;
case 4: HEAD=reddat(NULL,HEAD);getch();break;
case 5: whidat(HEAD);getch();break;
default : if(xx!=0) printf( "您输入的命令不存在。 ");getch();
}
if(zt==0){puts( "system error! ");getch();myexit(HEAD);}
}
return 0;
}
int myfree(struct std *head)
{
int i=0;
printf( "\n正在释放内存... ");
while(head-> ID[0]!=0 && head-> next!=NULL)
{
printf( "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%15d ",++i);
/*i++;
if(i==1052 || i==1053 || i==1054 || i==1055)
{
printf( "\n%d学号:%s 姓名:%s 分数:%.2f-%.2f-%.2f 平均分:%.2f ",i,head-> ID,head-> name,head-> cj[0],head-> cj[1],head-> cj[2],head-> num);
}*/
free(head);
head=head-> next;
}
free(head);
puts( "\tOK ");
getch();
}
int myquit(struct std *head)
{
char ch;
puts( "您确定您已经对修改过的数据库进行了保存(Y/N)?\n\n为了您的数据安全,退出时程序不会帮助您保存数库. ");
fflush(stdin);
ch=getchar();
if(ch== 'n ' || ch== 'N ')return 1;
myfree(head);
return MY_QUIT;
}
int myexit(struct std *head)
{
char ch;
system( "cls ");
puts( "程序发生了错误即将退出,无法保存当前数据. ");
myfree(head);
exit(0);
return MY_QUIT;
}
struct std *addstd(struct std *head)
{
struct std *sp,*sq,*h=head;
char ch= 'y ';
int i;
while(ch== 'y ' || ch== 'Y ')
{
head=h;
i=1;
system( "cls ");
puts( "添加新学生\n\n\n ");
sp=(struct std *)malloc(sizeof(struct std));
printf( "学生ID: ");scanf( "%s ",sp-> ID);
printf( "姓 名: ");scanf( "%s ",sp-> name);
do
{
printf( "成 绩1: ");scanf( "%f ",sp-> cj);
printf( "成 绩2: ");scanf( "%f ",sp-> cj+1);
printf( "成 绩3: ");scanf( "%f ",sp-> cj+2);
if(sp-> cj[0]> =0 && sp-> cj[1]> =0 && sp-> cj[2]> =0) break;
puts( "请仔细核对成绩. ");
}while(1);
sp-> num = (sp-> cj[0]+sp-> cj[1]+sp-> cj[2])/3;
printf( "此学生平均成绩为:%f ",sp-> num);
if(head-> ID[0] == 0 || sp-> num > = head-> num)
{
sp-> next=head;h=sp;
}
else
{
while(sp-> num <= head-> num)
{
i++;
sq=head;
head=head-> next;
}
sp-> next=head;
sq-> next=sp;
}
printf( "\t目前排名:%d ",i);
puts( "\n\n按Y键继续添加... ");
ch=getch();
}
return h;
}
struct std *delstd(struct std *head)
{
struct std *sq,*h=head;
char ch= 'y ',sid[11];
int i=0;
while(ch== 'y ' || ch== 'Y ')
{
system( "cls ");
puts( "删除学生信息\n\n\n ");
printf( "请输入要删除学生的学号: ");
fflush(stdin);
gets(sid);
head=h;
sq=head;
while(head-> ID[0] != 0)
{
if(!strcmp(sid,head-> ID))
{
i=1;
printf( "\n确认删除 学生ID:%s 姓名:%s 的记录(Y/N)?\n ",head-> ID,head-> name);
ch=getch();
if(ch== 'y ' || ch== 'Y ')
{
if(sq == head) h=h-> next;
sq-> next=head-> next;
free(head);
puts( "记录被成功删除. ");
}
}
sq=head;
head=head-> next;
}
if(!i) puts( "没有符合条件的记录. ");
i=0;
puts( "\n\n按Y键继续删除其他记录... ");
ch=getch();
}
return h;
}
int dirall(struct std *head)
{
int i=0;
char ch= 'a ';
while(head-> ID[0]!= '\0 ')
{
i++;
if(ch!= 'q ')
{
printf( "名次:%5d\n学号:%-10s 姓名:%-20s\n分数:%.2f %.2f %.2f 平均分%.2f\n\n ",i,head-> ID,head-> name,head-> cj[0],head-> cj[1],head-> cj[2],head-> num);
puts( "-------------------------------------------------- ");
if(i%4==0)
{
puts( "按任意键显示下一页,按q键退出... ");
ch=getch();
printf( "\n\n\n\n\n-第%d页-\n-------\n ",i/4+1);
}
}
head=head-> next;
}
system( "cls ");
if(i==0){puts( "\n数据库中没有记录! ");}
else{printf( "\n数据库中共有记录%d条 %d页 ",i,i/4+1);}
return 1;
}
struct std *reddat(char *filen,struct std *head)
{
FILE *fp;
struct std *sp,*sq;
int zt=0;
printf( "开始读取数据库std.dat到程序\t ");
if((fp=fopen( "std.dat ", "r "))==NULL)
{
puts( "open datefile error! ");
getch();
myexit(head);
}
head=sp=(struct std *)malloc(sizeof(struct std));
while(!feof(fp))
{
sq=(struct std *)malloc(sizeof(struct std));
zt=fscanf(fp, "%s\t%s\t%f\t%f\t%f\t%f\n ",sq-> ID,sq-> name,sq-> cj,sq-> cj+1,sq-> cj+2,&sq-> num);
/*printf( "%d ",zt);*/
if(zt!=6 && zt!=1 || (int)(sp-> num*3 - sp-> cj[0] - sp-> cj[1] - sp-> cj[2]))
{
zt=-1;
break;
}
sp-> next=sq;
sp=sq;
}
fclose(fp);
if(zt==-1 || sp-> ID[0]!= '# ')
{
puts( "ERROR.\n数据库可能被其他程序编辑过,文件损坏,无法读取. ");
getch();
myexit(head);
}
sp-> ID[0]= '\0 ';
sp-> num=-100;
sp-> next=NULL;
sp=head;
head=head-> next;
printf( "OK.\n正在清理临时变量\t ");
free(sp);
printf( "OK.\n\n数据库读取完毕,没有发生任何异常. ");
return head;
}
int whidat(struct std *head)
{
FILE *fp,*fp1;
char ch;
printf( "开始备份数据库为stdb.dat\t ");
fp1=fopen( "stdb.dat ", "w ");
if((fp=fopen( "std.dat ", "r+ "))==fp1)
{
puts( "open datefile error! ");
getch();
myexit(head);
}
while(!feof(fp))
{
ch=fgetc(fp);
fputc(ch,fp1);
}
fclose(fp1);
printf( "OK.\n开始保存新的数据到数据库\t ");
fseek(fp,0L,SEEK_SET);
while(head-> ID[0]!= '\0 ')
{
fprintf(fp, "%s\t%s\t%f\t%f\t%f\t%f\n ",head-> ID,head-> name,head-> cj[0],head-> cj[1],head-> cj[2],head-> num);
head=head-> next;
}
fputc( '# ',fp);
fclose(fp);
printf( "OK.\n\n写入数据库操作执行完毕.没有发生任何异常. ");
return 1;
}
[解决办法]
debug啊……
[解决办法]
说明可能不是标准的win32程序.
改用vc编来看一下.
[解决办法]
程序中有两处释放了堆内存又使用指针进行读操作:
free(head);
head=head-> next;
分别在myfree和delstd中。可以先把head-> next保存起来再复制给head来解决这个问题。
以下是我对这两个函数的修改:
struct std *delstd(struct std *head)
{
struct std *sq,*h=head,*temp;
char ch= 'y ',sid[11];
int i=0;
while(ch== 'y ' || ch== 'Y ')
{
system( "cls ");
puts( "删除学生信息\n\n\n ");
printf( "请输入要删除学生的学号: ");
fflush(stdin);
gets(sid);
head=h;
sq=head;
while(head-> ID[0] != 0)
{
if(!strcmp(sid,head-> ID))
{
i=1;
printf( "\n确认删除 学生ID:%s 姓名:%s 的记录(Y/N)?\n ",head-> ID,head-> name);
ch=getch();
if(ch== 'y ' || ch== 'Y ')
{
if(sq == head) h=h-> next;
sq-> next=head-> next;
temp=head-> next; /////////// <------
free(head);
puts( "记录被成功删除. ");
}
}
else temp=head-> next; //////////////////////// <-------
sq=head;
head=temp; //////////////////////////////////// <-------
}
if(!i) puts( "没有符合条件的记录. ");
i=0;
puts( "\n\n按Y键继续删除其他记录... ");
ch=getch();
}
return h;
}
int myfree(struct std *head)
{
int i=0;
struct std *temp;
printf( "\n正在释放内存... ");
while(head-> ID[0]!=0 && head-> next!=NULL)
{
printf( "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%15d ",++i);
temp=head-> next; ////////////////// <-------------
free(head);
head=temp;////////////////// <--------------
}
free(head);
puts( "\tOK ");
getch();
}
(以上代码在xp sp2+ vc 7.0和devc++4.9.9.2下测试通过)
个人认为 在win2000兼容模式下能够正常运行是因为win2000的堆管理器释放内存后并未改写原内存,而xp为了安全起见已经改写或移动了释放过的内存块,任何试图访问已经释放的内存都将引起程序崩溃。
关于兼容模式请参考:
1。关于windows程序的兼容模式
http://mazolen.spaces.live.com/blog/cns!8d71d5c962ea5113!142.entry
2。Microsoft Windows 2000 应用程序兼容性
http://blog.csdn.net/ghj1976/archive/2001/03/10/3404.aspx