FZU《C语言程序综合设计》
一年前的玩意。
老是有人找我要。。一年前写得这么搓都不敢拿出来。。。。
但是好多人要啊。。。。。直接发blog,省得下次还要发压缩文件。。
就不要吐槽我代码烂了,我也觉得很烂,至少现在看来确实很烂。。我又懒得改 - -||||||||||||||||||||||||
代码仅供参考。给学弟学妹们谋福利~
(一)
实验目的:
学习用指针构造链表,操作链表
实验内容:
输入两个非降序列,转换成两个非升序列,合并成一个非升序列。
基本要求:
用链表实现。
完成解题报告。
分析(解题思路及流程图):
题目要求使用链表来解题,对于一些不熟练链表操作的同学可能会比较困难。在建立两个链表后,我进行了合并,然后对每一个进行比较大小,最后输出结果。个人认为此题挺简单的。
心得:做关于指针的题目,需要耐心和细心。本题对链表的熟悉度要求较高,熟悉链表后,这题就是一道水题了。
测试方案:输入两个非降序列,转换成两个非升序列,验证结果。
输入:5 8 7 6 5 4
4 5 4 3 2
输出:8 7 6 5 5 4 4 3 2
输入:5 8 7 6 5 4
5 6 5 4 3 2
输出:8 7 6 6 5 5 4 4 3 2
#include<Stdio.h> #include<stdlib.h> #define LEN sizeof(struct sequence) struct sequence{ int a; struct sequence *next; }; struct sequence *creat(int m) { struct sequence *head,*p1,*p2; int n=0; p1=p2=(struct sequence *)malloc (LEN); scanf("%d",&p1->a); head=NULL; while(n<m){ n++; if(n==1) head=p1; else p2->next=p1; p2=p1; p1=(struct sequence *)malloc (LEN); if(m==n)break; scanf("%d",&p1->a); } p2->next=NULL; return head; free (p1);free (p2);free (head); } void print(struct sequence *head){ //输出结果 struct sequence *p; p=head; while(p!=NULL){ printf("%d ",p->a); p=p->next; } } void compare(struct sequence *head)//比较大小 { struct sequence *i,*j,*max;//i指向下一个链表,j链接下一个的地址进行比较排序,flag进行标记j的地址,max最大值查找 int temp; for(i=head;i!=NULL;i=i->next) { max=i; for(j=i->next;j!=NULL;j=j->next) { if((j->a)>(max->a)) max=j; } if(max!=i) { temp=i->a; i->a=max->a; max->a=temp; } } print (head); } void connect(struct sequence *heada,struct sequence *headb)//合并链表 { struct sequence *p; p=heada; while(p->next!=NULL){ p=p->next; } p->next=headb; compare(heada); } void main() { int n,m; struct sequence *heada,*headb; scanf("%d",&n); heada=creat(n); scanf("%d",&m); headb=creat(m); connect(heada,headb); }
(二)
实验目的:
学习数组的应用。
实验内容:
高精度四则运算(200位以内)
基本要求:
对于给定的大整数,做相关运算。
必做+(加法) -(减法) *(乘法)
选做: /(除法)% ( 求余 ) gcd(最大公约数) lcm(最小公倍数)
完成解题报告。
分析(解题思路及流程图):
由于此题要求的是200位数,所以要用数组。
首先,我进行判断两个数的大小,由于我输入的是字符串,所以比较位数和用strcmp是很简单的一件事情。然后将大的数倒序存进数组a,小的数存进数组b。由于是倒着存的,直接实现了末位对齐。加法减法就十分容易实现了。
加法主要是一个大于10,下一位+1的操作。
减法则需要用到前面的比较大小的结果,如果输入的第一个数较小,则需要输出个“-”。然后进行减法操作。如果正在想减的两个数第二个数大的话,则需要让结果的下一位减一。同时也要考虑连续小于的情况,如1000-2.故需要用个循环,保证连续减。保证结果准确。
乘法我也觉得比较简单。需要个临时的数组进行乘完后相加操作。进行乘法时候,就像是进行打草稿计算一样,第二个数的每一个数分别乘以第一个数,然后相加即可。相乘后若一个数>=10,则需进行%10操作,下一位数则加上这位数/10操作
除法就比较坑爹了。在排除除数为0的情况后,也需要用到前面的比较大小的结果,如果输入的第一个数较小,商为0.余数为第二个数。排除掉这种情况后,开始进行除法。除法操作我是正序的引入新的数组。
毕竟用前面的a和b数组时逆序的不好操作。
除法解决了之后,最大公约数和最小公倍数就迎刃而解了。
最大公约数直接调用除法函数使用辗转相除法很快就解决了。
最小公倍数直接用乘法的结果除以最大公约数即可。
同时最大公约数和最小公倍数都不讨论0的情况。
心得:做这种题目需要认真。。。。耐心。。有时候找个BUG要老半天的。大数的运算确实不易。我认为这题是一种锻炼编程技能的好题目。通过这题我也练习了函数调用,比如说输出加减乘都可以用同一函数,大大减少了代码量。上面的第三组数据在复制粘贴由于word换行问题,(我把换行去掉了)可能会不小心删掉一位数。。。。
测试方案:输入两个数(不含非法字符且除数不能为0)
2
100
输出:
两数之和为:102
两数之差为:-98
两数之积为:200
两数的商为0……100
最大公约数为:2
最小公倍数为:100
2输入
27216
15750
输出
两数之和为:42966
两数之差为:11466
两数之积为:428652000
两数之商为:1……11466
最大公约数为:126
最小公倍数为:3402000
3输入:
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
输出:
两数之和为:199999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998
两数之差为:0
两数之积为:9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
两数之商为:1……0
最大公约数为:99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
最小公倍数为:99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
4.输入:
12345
0
输出:
两数之和为:12345
两数之差为:12345
两数之积为:0
除数不能为0
在这里不讨论0的最大公约数和最小公倍数问题
#include <stdio.h> #include <string.h> #define N 500 void add(int a[],int b[],int sum[],int lensum); //定义加法运算函数 void minus(int a[],int b[],int diff[],int lena); //定义减法运算函数 void print_result(int a[],int len); //输出加、减、乘 void chu(char a[],char b[],char result_chu[],char yu[]); //除法 void add_cheng(int tempcheng[],int chengfa[],int j) ; void main() { int a[N]={0},b[N]={0},sum[N]={0},diff[N]={0},chengfa[N*2]={0},tempcheng[N]={0}; char temp[N],temp2[N],yu[N],result_chu[N],result_gcd[N],gcd_yu[N],result_lcm[N]; int i,j,lena,lenb,lensum,lendiff,flag=1,flagda=1,lencheng; printf("请输入第一个数"); //输入数并且倒序存入数组 gets(temp); printf("请输入第二个数"); gets(temp2); lena=strlen(temp); lenb=strlen(temp2); int compare(char yu[],char b[]); if(compare(temp,temp2)!=-1) { for(i=0;i<lena;i++) a[i]=temp[lena-1-i]-48; for(i=0;i<lenb;i++) b[i]=temp2[lenb-1-i]-48; } else{ flagda=0; lena=strlen(temp2); for(i=0;i<lena;i++) a[i]=temp2[lena-1-i]-48; lenb=strlen(temp); for(i=0;i<lenb;i++) b[i]=temp[lenb-1-i]-48; } lendiff=lensum=lena; add(a,b,sum,lensum); //引用加法运算函数 printf("两数之和为:"); print_result(sum,lensum); //引用输出加法结果函数 minus(a,b,diff,lena); //引用减法运算函数 printf("两数之差为:"); if(!flagda) printf("-"); print_result(diff,lendiff); //引用输出减法结果函 数 for(i=0;i<lenb;i++) //乘法 { for(j=0;j<lena;j++) { tempcheng[j+i]+=b[i]*a[j]; if(tempcheng[j+i]>=10) { tempcheng[j+i+1]+=tempcheng[j+i]/10; tempcheng[j+i]= tempcheng[j+i]%10; } } j+=i; if(temp[j+1]!=0) j+=1; j++; add_cheng(tempcheng,chengfa,j); int k; for(k=0;k<=j;k++) tempcheng[k]=0; //清空处理 } lencheng=j; printf("两数之积为:"); print_result(chengfa,lencheng); //输出乘法结果 if(!flagda) //除法 { printf("两数的商为0……"); i=lena; while(!a[i]) i--; for(;i>=0;i--) printf("%d",a[i]); printf("\n"); } else { if(!strcmp(temp2,"0")) printf("除数不能为0\n"); else { chu(temp,temp2,result_chu,yu); printf("两数之商为:%s……%s\n",result_chu,yu); } } if(!strcmp(temp2,"0")||!strcmp(temp,"0")) { printf("在这里不讨论0的最大公约数和最小公倍数问题\n"); return; } char gcd_xiangchu1[N],gcd_xiangchu2[N]; //最大公约数 if(compare(temp,temp2)==1) { strcpy(gcd_xiangchu1,temp); strcpy(gcd_xiangchu2,temp2); } else { strcpy(gcd_xiangchu2,temp); strcpy(gcd_xiangchu1,temp2); } chu(gcd_xiangchu1,gcd_xiangchu2,result_gcd,gcd_yu); while(gcd_yu[0]!=48) { if(compare(gcd_xiangchu2,gcd_yu)==1) { strcpy(gcd_xiangchu1,gcd_xiangchu2); strcpy(gcd_xiangchu2,gcd_yu); chu(gcd_xiangchu1,gcd_xiangchu2,result_gcd,gcd_yu); } else //if (compare(gcd_xiangchu2,gcd_yu)==-1) { strcpy(gcd_xiangchu1,gcd_yu); strcpy(gcd_xiangchu2,gcd_xiangchu2); chu(gcd_xiangchu1,gcd_xiangchu2,result_gcd,gcd_yu); } } printf("最大公约数为:%s\n",gcd_xiangchu2); char temp3[N*2]; //最小公倍数 for(i=lencheng-1,j=0;i>=0;i--,j++) temp3[j]=chengfa[i]+48; temp3[j]='\0'; chu(temp3,gcd_xiangchu2,result_lcm,gcd_yu); printf("最小公倍数为:%s\n",result_lcm); } void del_zero(char a[]) //删除0 { int i,len=strlen(a); for(i=0;a[i];i++) if(a[i]!='0') break; if(i==len) strcpy(a,"0"); else strcpy(a,&a[i]); } int compare(char yu[],char b[])//比较大小 { int len1,len2; len1=strlen(yu);len2=strlen(b); if(len1>len2) return 1; else if(len1<len2) return -1; else return strcmp(yu,b); } void chu_sub(char yu[],char b[]){//除法里面的减法 int i,j,k,lena,lenb; lena=strlen(yu); lenb=strlen(b); for(i=lena-1,k=lenb-1;i>=0&&k>=0;i--,k--) { if(yu[i]-b[k]>=0) yu[i]=yu[i]-b[k]+48; else{ j=1; yu[i]=yu[i]+10-b[k]+48; yu[i-j]--; while(yu[i-j]==47) { yu[i-j]+=10; j++; yu[i-j]--; } } } del_zero(yu); } void chu(char a[],char b[],char result_chu[],char yu[]) // 除法 { int i,k,m,len1,len2; len1=strlen(a);len2=strlen(b); strcpy(yu,a); yu[len2]='\0'; m=0; for(i=len2-1;i<len1;){ del_zero(yu); if(compare(yu,b)==-1) { int len=strlen(yu); yu[len]=a[++i]; yu[len+1]='\0'; result_chu[m++]='0'; } else{ k=0; while(compare(yu,b)>=0){ //把b和余数进行比较,如果余数不小于b就进入循环 chu_sub(yu,b); //数和b相减 k++; } int len=strlen(yu); yu[len]=a[++i];//取a的下一个值作为余数 yu[len+1]='\0'; result_chu[m++]=k+'0'; } } result_chu[m]='\0';//商 del_zero(result_chu); } void add_cheng(int tempcheng[],int chengfa[],int len) // 乘法相加运算 { int i; for(i=0;i<len;i++) { chengfa[i]+=tempcheng[i]; if(chengfa[i]>=10) { chengfa[i]-=10; chengfa[i+1]++; } } } void print_result(int a[],int len)// 输出加法、减法、乘法结果 { int i,flag=1; while(!a[len]){ len--; if(len<0) {printf("0");flag=0;break;} } if(flag) { for(i=len;i>=0;i--) printf("%d",a[i]); } printf("\n"); } void minus(int a[],int b[],int diff[],int lena) //减法运算 { int i,j; for(i=0;i<lena;i++) diff[i]=a[i]; for(i=0;i<lena;i++) { if(diff[i]-b[i]>=0) diff[i]-=b[i]; else{ j=1; diff[i]=diff[i]+10-b[i]; diff[i+j]--; while(diff[i+j]==-1) { diff[i+j]+=10; j++; diff[i+j]--; } } } } void add(int a[],int b[],int sum[],int lensum) //加法运算 { int i; for(i=0;i<lensum;i++) { sum[i]+=a[i]+b[i]; if(sum[i]>=10){ sum[i]-=10; sum[i+1]++; } } }
(三)
实验目的:
学习递归的使用
实验内容:
8皇后问题(在一个8×8国际象棋盘上,有8个皇后,每个皇后占一格;要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。问共有多少种不同的方法。)
基本要求:
输入一个整数8,输出所有可行的解法。
完成解题报告。
分析(解题思路及流程图):一开始看到这题就蒙了。后来参考资料,慢慢懂了。我们可以采用一个一维数组用site存放皇后的行数,把第column列的皇后放进第i行。在递归调用的时候判断行、列、对角线是否冲突。
心得:通过这题让我复习了函数的递归调用,也学会了怎么输出一个程序的运行时间。还有就是把n皇后的结果输进文件中速度快很多。原来15皇后直接在黑白框输出需要240多秒,现在输进文件只需要82秒。大大提高了效率。当然,测试的CPU是core i5 3210M,目测比学校机房速度快4倍左右。当然,我也知道,这个算法并不是最好的。还有待我学习提高进一步改进。
测试方案:输入一个n,求解并在文件中输出结果
输入:
5
输出:
10
计算时间0秒
文件中输出结果为:
1,1 3,2 5,3 2,4 4,5
1,1 4,2 2,3 5,4 3,5
2,1 4,2 1,3 3,4 5,5
2,1 5,2 3,3 1,4 4,5
3,1 1,2 4,3 2,4 5,5
3,1 5,2 2,3 4,4 1,5
4,1 1,2 3,3 5,4 2,5
4,1 2,2 5,3 3,4 1,5
5,1 2,2 4,3 1,4 3,5
5,1 3,2 1,3 4,4 2,5
#include <stdio.h> #include <time.h> int n,num; int site[16]; FILE*fin=fopen("result.txt","w"); void search(int column) { if(column==n+1) { num++; for(int x=1;x<=n;x++) { fprintf(fin,"%d,%d ",site[x],x); } fprintf(fin,"\n"); } else { for(int i=1;i<=n;i++) { int flag=1; site[column]=i; //把第column列的皇后放进第i行,site存放的是皇后的行数 for(int k=1;k<column;k++) { if(i==site[k] //同行 ||column-k==i-site[k] //主对角线 ||column-k==site[k]-i //副对角线 ) { flag = 0; break; } } if(flag!=0) search(column+1); // 如果合法,继续 } } } void main() { scanf("%d",&n); if(fin==NULL) printf("文件打开失败\n"); time_t tm; tm = time(0); search(1); printf("%d\n",num); fclose(fin); printf("\n计算时间%d秒\n", (int) (time(0) - tm)); }
(四)
实验目的:
学习文件的使用
实验内容:
解N元一次方程。
基本要求:
从文件读入整数 N, 然后读入N*( N+1)矩阵,得到解并输出到文件中。
完成解题报告。
从文件中读入矩阵阶数和矩阵。
求解线性方程组,无非就是进行初等行变换,使其变成行阶梯型矩阵。然后计算方程的行列式|A|,|A|很简单,主对角元素直接相乘即可。如果|A|不为0,由于第N行可以直接读出结果,所以把第N行的结果带入n-1行,再把第n-1行的带入n-2行……如此即可求出全部的解。
如果|A|=0,那么需要判断是否有矛盾方程,有矛盾方程则无解,否则有无穷解。
心得:看来学好数学还是十分必要的。此题除了高斯消元法外,还有其他的方法,如《算法导论》中介绍的LUP分解法。但我还没有深入研究。
测试方案:输入一个数N,在输入增广矩阵。
1.文件中读入:
2
2 3 8
2 2.99999 8.00003
输出:
x[0]=8.500
x[1]=-3.000
2.文件中读入:
3
1 1 -1 -1
2 -5 3 2
7 -7 3 1
输出:
方程无唯一解,即有无穷解
3.文件中读入:
3
1 1 1 0
1 1 1 3
1 1 1 0
输出:
方程无解
#include <stdio.h> void main() { FILE* fin; int n,i,j,k,flag,flag2; double a[31][31],temp,x[31]={0}; fin=fopen("question.txt","r"); if(fin==NULL) printf("文件打开失败\n"); else { fscanf(fin,"%d",&n); //读入矩阵阶数 for(i=0;i<n;i++) //输入n*(n+1)矩阵 { for(j=0;j<n+1;j++) { fscanf(fin,"%lf",&a[i][j]); } } fclose(fin); fin=fopen("result.txt","w"); for(i=0;i<n;i++) //主对角线为0的情况先换行 { if(a[i][i]==0) for(k=i+1;k<n;k++) { if(a[k][i]) { for(j=0;j<n+1;j++) { temp=a[k][j]; a[k][j]=a[i][j]; a[i][j]=temp; } break; } } } for(i=0;i<n;i++) //进行初等行变换 { for(j=i+1;j<n;j++) { temp=a[j][i]/a[i][i]; for(k=0;k<n+1;k++) { a[j][k]-=temp*a[i][k]; } } } /* for(i=0;i<n;i++) //输出初等变换后结果 { for(j=0;j<n+1;j++) { printf("%lf\t ",a[i][j]); if(j==n) printf("\n"); } } */ for(i=0,temp=1;i<n;i++) //计算行列式|A| temp*=a[i][i]; // printf("|A|=%lf\n",temp); if(temp!=0) { flag=1; //求解根 x[n-1]=a[n-1][n]/a[n-1][n-1]; for(i=n-2;i>=0;i--) { for(j=0,temp=0;j<n;j++) { temp=temp+a[i][j]*x[j]; } x[i]=(a[i][n]-temp)/a[i][i]; } for(i=0;i<n;i++) //输出根 fprintf(fin,"x[%d]=%.3lf\n",i,x[i]); } else { flag=1; flag2=1; for(i=0;i<n;i++) //判断是否有解 { if(a[i][n]!=0) { for(j=0;j<n;j++) { if(a[i][j]!=0) { flag=1; break; } else flag=0; } if(flag==0){ flag2=0;break;} } } if(temp==0&&flag2==0) fprintf(fin,"方程无解\n"); //判断无穷解或无解情况 else if(temp==0&&flag2==1) fprintf(fin,"方程无唯一解,即有无穷解\n"); fclose(fin); } } }
(五)
实验目的:
综合练习
实验内容:
判断C语言算术表达式的合法性。
基本要求:
从文件读入整数 N, 后跟2*N行字符串,两行一组。
每组第一行是预定义的变量(可以多个)。第二行字符串为一个预期的C语言算术表达式。
程序分别判断每个字符串,如果是正确的C语言算术表达式,输出OK;否则,输出其错误类型。如果一个表达式有多个错误,输出一个即可。
用N-S流程图表示处理逻辑(算法)。
设计10个测试数据。
完成解题报告。
分析(解题思路及流程图):
再输入字符串数据之后,我首先进行了删除变量定义的类型操作,便于今后的判断。但需要主要 abintc这种类型的变量不能删除int。
1之后我进行搜索变量括号的合法性。(括号不配对的判断方法:总数一样,右边的括号数目总是小于左边的,右括号左边不与运算符直接相连,左括号的右边不与运算符直接相连,左括号左边不能直接a,括号为空的情况)括号判断完毕后,我进行去括号操作。
2接下来进行符号的搜索和查询。(数组开头不能为运算符号,除数不能为0,** // ++ --错误 ,非法符号判断,数组结束不能为运算符号)
3 判断是否定义(我是讲第一个数列封装进一个二维数组,然后把第二个数中每个数轮流装进一个数组,进行比较。)
4.其他BUG修正主要是数字不能与变量相连接。因为我定义时候没有判断合法性,所以我这个程序就认为定义时候只能存字母、数字,但不能有下划线。但不能以数字开头
心得:这道题说简单也简单,说难也难。简单的是逻辑思维很简单,难的是要考虑的东西较多。这道题我怎么觉得是在写一个编译器。如果要做一个完美的编译器,现在还不能够做到。
括号的判断也可以用堆栈的方式进行判断。一开始我就设定定义时只能有一个字符,这样就简单了。后来,由于我做完作业较早,大概第4周把。就闲着没事做,开始弄支持一长串变量类型名的。但是由于偷懒,一位一位判断,导致BUG层出不穷,导致后来我重写,采用现在的方法。就没有BUG了。我从中体会到,作为一个程序员,不能闲麻烦,要做就要做最好。
测试方案:输入两行字符串,并检查结果是否符合预期
int a;char b,float c;double doublec;
a/(10+134)+c*b+(doublec)
OK
int a;char b,float c;double doublec;
a/(10+134)+c*b+doublec+double
有变量名未定义
double afintc,charfloat;
afintc/charfloat
OK
int a,b,c;
a+b*(-c)
左括号的右边不能与运算符直接相连
double aintc,charfloat;
afintc/charfloat
有变量名未定义
int a,b;
a+(b
括号不成对
int a,b,c;
a~b+c
有非法符号出现
int chara,bfloat;
1chara+bfloat
数字不能与变量直接相连
float charc,af;
charc/0+af
除数不能为0
int chara,bfloat;
chara**bfloat;
运算符不能连续出现
#include <stdio.h> #include <string.h> #include <stdlib.h> void shift(char first[],char temp[],int x,int n)//移位操作 X代表第几位开始而N代表偏移几位 { for(int i=x;first[i+n]!='\0';i++) { temp[i]=first[i+n]; } temp[i]='\0'; for(i=x;temp[i]!='\0';i++) { first[i]=temp[i]; } first[i]='\0'; } void DelType(char first[],char temp[]) //删除int char float double类型方便判断 { int i; for(i=0;first[i]!='\0';i++) { if(first[i]=='i'&&first[i+1]=='n'&&first[i+2]=='t'&&first[i+3]==' ')//int { if(i) { if(first[i-1]==' '||first[i-1]==';') shift(first,temp,i,3); } else shift(first,temp,i,3); } if(first[i]=='c'&&first[i+1]=='h'&&first[i+2]=='a'&&first[i+3]=='r'&&first[i+4]==' ')//char { if(i) { if(first[i-1]==' '||first[i-1]==';') shift(first,temp,i,4); } else shift(first,temp,i,4); } if(first[i]=='f'&&first[i+1]=='l'&&first[i+2]=='o'&&first[i+3]=='a'&&first[i+4]=='t'&&first[i+5]==' ')//float { if(i) { if(first[i-1]==' '||first[i-1]==';') shift(first,temp,i,5); } else shift(first,temp,i,5); } if(first[i]=='d'&&first[i+1]=='o'&&first[i+2]=='u'&&first[i+3]=='b'&&first[i+4]=='l'&&first[i+5]=='e'&&first[i+6]==' ')//double { if(i) { if(first[i-1]==' '||first[i-1]==';') shift(first,temp,i,6); } else shift(first,temp,i,6); } } for(i=0;first[i]!='\0';i++) //用空格代替分号逗号 { if(first[i]==','||first[i]==';') first[i]=' '; } if( first[i-1]==' ') first[i-1]='\0'; } int SearchDefine(char first[],char second[]) { char cmp[50][100],cmp2[100]; int j,num,k,flag,flag2=0; for(j=0,num=0;first[j]!='\0';j++) { if(first[j]>='a'&&first[j]<='z'||first[j]>='A'&&first[j]<='Z') { for(k=0;first[j]!=' '&&first[j]!='\0';j++,k++) { cmp[num][k]=first[j]; } cmp[num][k]='\0'; num++; } } // for(j=0;j<num;j++) // printf("%s\n\n",cmp[j]); // printf("******************\n"); int len=strlen(second); for(j=0,flag=1;j<len;j++) { if(second[j]>='a'&&second[j]<='z'||second[j]>='A'&&second[j]<='Z') { if(j>0) if(second[j-1]=='+'||second[j-1]=='-'||second[j-1]=='*'||second[j-1]=='/') flag=1; else flag=0; if(flag) { for(k=0;second[j]!='+'&&second[j]!='-'&&second[j]!='*'&&second[j]!='/'&&second[j]!='\0';j++,k++) { cmp2[k]=second[j]; } cmp2[k]='\0'; // printf("!!!!!\n%s\n!!!\n",cmp2); for(k=0,flag2=0;k<=num;k++) { if(strcmp(cmp[k],cmp2)==0) { flag2=1; break; } else flag2=0; } // printf("#############\n%d\n#########\n",flag2); if(flag2==0) {return 0;} } } } return 1; } int searchBracket(char a[]) { int left=0,right=0; for(int i=0;a[i]!='\0';i++)//括号正确与否判断 { if(a[i]=='(') { left++; if(a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/') { printf("左括号的右边不能与运算符直接相连\n\n"); return 0; } if(a[i+1]==')') { printf("括号不能为空\n"); return 0; } if(a[i-1]>=48&&a[i-1]<=57) { printf("左括号的左边不能与数字直接相连\n\n"); return 0; } if(a[i-1]>='a'&&a[i-1]<='z'||a[i-1]>='A'&&a[i-1]<='Z') { printf("左括号的左边不能与变量直接相连\n\n"); return 0; } } if(a[i]==')') { right++; if(a[i-1]=='+'||a[i-1]=='-'||a[i-1]=='*'||a[i-1]=='/') { printf("右括号的左边不能与运算符直接相连\n\n"); return 0; } if(a[i+1]>=48&&a[i+1]<=57) { printf("右括号的右边不能与数字直接相连\n\n"); return 0; } if(a[i+1]>='a'&&a[i+1]<='z'||a[i+1]>='A'&&a[i+1]<='Z') { printf("右括号的右边不能与变量直接相连\n\n"); return 0; } if(left<right) { printf("括号有误\n\n"); return 0; } } } if(left!=right) { printf("括号不成对\n\n"); return 0; } for(i=0;a[i]!='\0';i++) //去除括号 { if(a[i]=='('||a[i]==')') { char temp[100]; shift(a,temp,i,1); } } return 1; } int searchSign(char a[]) { int i=0,num=0; if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/') { printf("不能以运算符开头\n\n"); return 0; } for(i=1;a[i]!='\0';i++) { if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/') { if(a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/') { printf("运算符不能连续出现\n\n"); return 0; } } if(a[i]=='/'&&a[i+1]==48) { printf("除数不能为0\n\n"); return 0; } if(a[i]<'0'||a[i]>'9') if(a[i]<'a'||a[i]>'z') if(a[i]<'A'||a[i]>'Z') if(a[i]!='+'&&a[i]!='-'&&a[i]!='*'&&a[i]!='/') { printf("有非法符号出现\n\n"); return 0; } } i--; if(a[i]=='+'||a[i]=='-'||a[i]=='*'||a[i]=='/') { printf("不能以运算符结尾\n\n"); return 0; } return 1; } int searchOthers(char a[]) { int j,len=strlen(a); for(j=0;j<len;j++) { if(a[j]>='a'&&a[j]<='z'||a[j]>='A'&&a[j]<='Z') if(a[j-1]>='0'&&a[j-1]<='9') { printf("数字不能与变量直接相连\n\n"); return 0; } } return 1; } void main() { int flag,n,i; char first[100],second[100],temp[100]; scanf("%d\n",&n); for(i=0;i<n;i++) { gets(first); gets(second); DelType(first,temp);//首先删除变量类型 // printf("!!!!!\n%s\n",first); if(searchBracket(second))//搜索括号 if(searchSign(second))//判断非法符号 { flag= SearchDefine(first,second);//判断是否定义 if(!flag) printf("有变量名未定义\n\n"); else if(searchOthers(second)) printf("OK\n\n"); } } }