C 2012年笔试题
1指出程序段中的错误:分析错误的原因,并进行修改
1.1函数 swap 将两个字符串(字符数组作实参,长度不超过 100)的内容进行交换
void swap(char *pa,char *pb) { char *temp; temp=pa; pa=pb; pb=temp; }错误原因:只是将 swap 中的局部变量 pa 和 和 pb 的值进行了交换,而作为实参的字符数组中 的内容并没有改变
改正一:
void swap (char *pa ,char *pb ) { if(strlen(pa)!=strlen(pb))exit(-1); //若长度不一致,则返回 char tmp; int i=-1; while(pa[++i]) { tmp=pa[i]; pa[i]=pb[i]; pb[i]=tmp; } }全部代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> void swap (char *pa ,char *pb ) { if(strlen(pa)!=strlen(pb))exit(-1); char tmp; int i=-1; while(pa[++i]) { tmp=pa[i]; pa[i]=pb[i]; pb[i]=tmp; } } void input(char *p) { while(p) { printf("%d\t",*p); p++; } } int main() { char a[] = "hello",b[] = "world"; swap(a,b); printf("交换后:\na=%s\nb=%s",a,b); return 0; }改正二:
void swap (char *pa ,char *pb ) { if(strlen(pa)!=strlen(pb))exit(-1); char tmp[100]; strcpy(tmp,pa); strcpy(pa,pb); strcpy(pb,tmp); }全部代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> void swap (char *pa ,char *pb ) { if(strlen(pa)!=strlen(pb))exit(-1); char tmp[100]; strcpy(tmp,pa); //strcpy(s1,s2):将字符串s2复制到s1中 strcpy(pa,pb); strcpy(pb,tmp); } void input(char *p) { while(p) { printf("%d\t",*p); p++; } } int main() { char a[] = "hello",b[] = "world"; swap(a,b); printf("交换后:\na=%s\nb=%s",a,b); return 0; }1.2程序片段:
错误点一:pb[1]=’A’, 错误原因:pb 指向一个常量字符串,不可修改其串中某个元素。
错误点二:strcpy(pa,”ABCDEFGXYZ”), 错误原因:pa 字符数组长度不够,导致溢出
2简答题(共 30 分)
2.1设 arr 为整型数组,num 和 item 为整型变量,N=数组元素个数-1。需要查找 item 是否在数组中,如果程序片段为 for(num=N;arr[num]!=item;num--); printf(“%d\n”,num); 可能导致的异常结果是什么?为什么?(8 分)【见2014 2.1】
异常结果:num 为负数,当查找的 item , 不在数组中的时候,num 会变为负数,直至找着 item,
这时查找已经越界了
2.2 设有递归函数
int value(int n) { int x; if(n==0)return0; else { scanf(“%d”,&x); return(value(n-1)+x); } }如该函数被调用时,参数 n 值为 4,输入的 x 的值依次为 11,22,33,44,函数调用结束时返回值是多少?并用图描述函数递归执行过程。(10 分)
程序段的功能是将输入的 n 个值求和,因此返回值是:11+22+33+44=110。
函数递归执行过程:2.3数组作为函数参数有三种形式: 1)实参是数组元素; 2)形参是指针,实参是数组; 3)函数的形参和实参都是数组分别是采用什么参数传递方式?(5 分)
参数传递方式分别为:传值、 传地址、传地址。
2.4采用高度抽象概念有利于程序设计,C 语言中循环语句 do s while(B);对应的显示控制结构是什么?请使用伪代码形式(通过条件转移指令)表达。(7 分)
循环控制结构
label: s; If(B) goto label;3 程序设计(共 45 分,每题的算法 50%,语法 30%,完整 20%)
3.1 利用 2 个函数对输入的两个分数进行加、减、乘、除四则运算和输出用分数表示的结果。(注:输入格式为:%ld/%ld%c%ld/%ld,输出格式为%ld/%ld),例如:输入 1/4+1/3,输出:7/12 (10 分)
#include<stdio.h> #include<stdlib.h> long fz1,fm1,fz2,fm2,fz3,fm3; char op; //求a,b的最大公约数 long gcd(long a,long b) { int r; while(b) { r=a%b; a=b; b=r; } return a; } void compute() { long zxg; switch(op) { case '+': case '-': zxg=fm1*fm2/gcd(fm1,fm2); // zxg是fm1和fm2的最小公倍数 fz1=zxg/fm1*fz1; fz2=zxg/fm2*fz2; if(op=='+') fz3=fz1+fz2; else fz3=fz1-fz2; fm3=zxg; break; case '*': fz3=fz1*fz2; fm3=fm1*fm2; break; case '/': fz3=fz1*fm2; fm3=fm1*fz2; break; default: exit(-1); } zxg=gcd(fz3,fm3); fz3=fz3/zxg; fm3=fm3/zxg; printf("%ld/%ld\n",fz3,fm3); } int main() { while(scanf("%ld/%ld %c %ld/%ld",&fz1,&fm1,&op,&fz2,&fm2)!=EOF) { compute(); system("pause"); } return 0; }3.2 编写函数,将单链表进行逆序,即表头变表尾,表尾变表头(15 分) 【见2017.24】
3.2.1方法一:头插法
代码:
// 方法一:头插法 逆序链表 void reverseslist1() { struct slist *p,*r; // p是工作指针,r是p的后继,以防断链 p = head ->next; //从第一个元素开始 head ->next = NULL; //将头节点后置null,断开 while(p != NULL) { r = p ->next; // r暂存s后继 p ->next = head ->next; // 依次将元素结点摘下 head ->next = p; p = r; } }全部代码:
#include <stdio.h> #include <stdlib.h> typedef struct slist { int data; struct slist *next; }; struct slist *head; // 尾插法建立链表 void creatslist() { int x; head = (struct slist *)malloc(sizeof(struct slist)); //头结点 struct slist *p,*node; // q为尾指针 p = head; printf("请输入元素:"); scanf("%d",&x); while(x != 9999) { node = (struct slist *)malloc(sizeof(struct slist)); node ->data = x; p ->next = node; p = node; printf("请输入元素:"); scanf("%d",&x); } p ->next = NULL; } //链表输出打印 void inputslist() { struct slist *q;//q是工作指针 q = head ->next; //头结点无元素 while(q != NULL) { printf("%d\t",q ->data); q = q ->next; } } // 方法一:头插法 逆序链表 void reverseslist1() { struct slist *p,*r; // p是工作指针,r是p的后继,以防断链 p = head ->next; //从第一个元素开始 head ->next = NULL; //将头节点后置null,断开 while(p != NULL) { r = p ->next; // r暂存s后继 p ->next = head ->next; // 依次将元素结点摘下 head ->next = p; p = r; } } void main() { creatslist(); inputslist(); printf("\n逆序后:\n"); reverseslist1(); inputslist(); }3.2.2方法二:后继指针指向前驱结点
代码:
// 方法二:后继指针指向前驱结点 void reverseslist2() { struct slist *pre,*p = head ->next,*r =p ->next; p ->next = NULL; //处理第一个结点 while(r != NULL) // r若为空,则p为最后一个节点 { pre = p; p = r; r = r ->next; p ->next = pre; } head ->next = p; //处理最后一个结点 }全部代码:
#include <stdio.h> #include <stdlib.h> typedef struct slist { int data; struct slist *next; }; struct slist *head; // 尾插法建立链表 void creatslist() { int x; head = (struct slist *)malloc(sizeof(struct slist)); //头结点 struct slist *p,*node; // q为尾指针 p = head; printf("请输入元素:"); scanf("%d",&x); while(x != 9999) { node = (struct slist *)malloc(sizeof(struct slist)); node ->data = x; p ->next = node; p = node; printf("请输入元素:"); scanf("%d",&x); } p ->next = NULL; } //链表输出打印 void inputslist() { struct slist *q;//q是工作指针 q = head ->next; //头结点无元素 while(q != NULL) { printf("%d\t",q ->data); q = q ->next; } } // 方法二:后继指针指向前驱结点 void reverseslist2() { struct slist *pre,*p = head ->next,*r =p ->next; p ->next = NULL; //处理第一个结点 while(r != NULL) // r若为空,则p为最后一个节点 { pre = p; p = r; r = r ->next; p ->next = pre; } head ->next = p; //处理最后一个结点 } void main() { creatslist(); inputslist(); printf("\n逆序后:\n"); reverseslist2(); inputslist(); }3.3编写完整程序:接收从键盘输入的仅由数字字符构成的字符串(假设字符串的最大长度为 50),统计并输出每个数字(0~9)的重复次数。(8 分)
代码:
#include<stdio.h> #include<stdlib.h> int main() { char ch; int num[10]= {0}; printf("string:\n"); //出现次数存储在数组中 while(scanf("%c",&ch)!=EOF&&ch!='q') num[ch-'0']++; int i; for(i=0; i<10; i++) printf("%d 出现%d 次\n",i,num[i]); system("pause"); return 0; }解析:
while(scanf("%c",&ch)!=EOF)C语言中,EOF常被作为文件结束的标志。还有很多文件处理函数处错误后的返回值也是EOF,因此常被用来判断调用一个函数是否成功。
当上面的程序运行时,如果不加" != EOF",那么这个程序就是个死循环,会一直运行下去;加上" != EOF"后该程序就不是死循环了,如果在终端不进行输入该程序会自动结束(while的意思就是说当当前输入缓存还有东西时就一直读取,直到输入缓存中的内容为空时停止)。
结束条件:
在终端(黑框)中手动输入时,系统并不知道什么时候到达了所谓的“文件末尾”,因此需要用<Ctrl + z>组合键然后按 Enter 键的方式来告诉系统已经到了EOF,这样系统才会结束while.
3.4 编写完整程序,采用结构数组和指向结构的指针,接收输入的 100 个学生信息(包括学号和 C 语言课程期末总成绩),输出最高、最低成绩和分别对应的学号(可能有多个同学都是最高分,可能有多个同学都是最低分)。(12 分)【见2016年4.3】
代码:
#include<stdio.h> #include<stdlib.h> struct node { int num; int cj; }; int main() { struct node stu[100]; //结构数组 int max=-1,min=200; int i; //输入数据,求最大最小分数 for(i=0; i<100; i++) { scanf("%d %d",&stu[i].num,&stu[i].cj); if(stu[i].cj>max) max=stu[i].cj; if(stu[i].cj<min) min=stu[i].cj; } //输出分数最大以及学号 printf("max=%d\n",max); for(i=0; i<100; i++) if(stu[i].cj==max) printf("%d\n",stu[i].num); //输出分数最小以及学号 printf("min=%d\n",min); for(i=0; i<100; i++) if(stu[i].cj==min) printf("%d\n",stu[i].num); system("pause"); return 0; }使用结构的指针
#include<stdio.h> typedef struct Student{ int num; int score; }Stu; int main() { /*选择排序: 假设排序表为L【1....n】,第一趟排序即从L【i...n】中选择关键字最小的元素与L(i)交换,每一趟排序可以确定一个元素的最终位置,这样经过n-1趟排序就可以使得整个排序表有序 */ Stu stu[200],temp,*p,*q,*k; //stu为结构体数组,*p,*q,*k为结构体指针 int i,j,max = 0; //max记录分数最大值 p = stu; //输出数据 for(i = 0;i < 200;i ++,p ++) scanf("%d%d",&p->num,&p->score); //选择排序,以成绩从低到高排序 p = stu; for(i = 0;i < 199;i ++,p ++) //由于题目说明要用结构体指针,所以我这使用指针操作 { k = p; //记录最小元素位置 q = p + 1; for(j = i + 1;j < 200;j ++,q ++) if(k->score > q->score) k = q; //更新最小元素的位置 //与第i个位置交换 temp = *p; *p = *k; *k = temp; } //记录最高成绩 p = stu; for(i = 0;i < 200;i ++,p ++) if(p->score > max) max = p->score; //输出打印最高分数和对应的学号 p = stu; for(i = 0;i < 200;i ++,p ++) if(p->score == max) printf("学号:%5d分数:%5d\n",p->num,p->score); return 0; }