C 2015年笔试题
1、写出程序输出结果
void main() { char p[10]="abc"; char q[]="xyz"; int i,j; i=0; while(*(p+i)!='\0') i++; //此时i=3 j=0; i++; // i= 4 while(*(q+j)!='\0') { *(p+i)=*(q+j); j++; i++; } printf("%s", p); }
解答:经过代码运行,p所指向的字符串内容为{a,b,c,\0,x,y,z,\0},所以最后运行的结果为输出abc。
或者
void main() { char p[10]="abc"; char q[]="xyz"; int i,j; i=0; while(*(p+i)!='\0') i++; //此时i=3 j=0; i++; // i= 4 while(*(q+j)!='\0') { *(p+i)=*(q+j); j++; } printf("%s", p); }
解答:经过代码运行,p所指向的字符串内容为{a,b,c,\0,z,\0},所以最后运行的结果为输出abc。
2、 写出该代码的功能,并给出改进之处
void main() { int n, x, j, i = 1; float sum = 1, k = -1; printf("Input n and x:\n"); scanf("%d %d", &n, &x); while (i <= n) { k = -1; for (j = 1; j <= i; j++) { k = -1*k*x; } for (j = 1; j <= i; j++) { k = k/ j; } sum += k; i++; } printf("%f\n", sum); }
解答,该代码的功能为求解1+x+x^2/2! +x^3/3! + ... + x^n/n!
该代码可以通过动态规划进行改进,使得时间复杂度下降至O(n),代码如下:
void main() { int n,x,i=1; float sum = 1,k = -1; printf("Input n and x:\n"); scanf("%d %d", &n, &x); while (i <= n) { k = -1 * k*x / i; sum += k; i++; } printf("%f", sum); }
3、代码for(int i=1;i<n;i++) S;是什么结构?该代码如何使用显示结构表示?
解答:该代码是循环判断选择结构。该代码的显示结构如下:
int i = 1; FOR: if (i<n) goto S0; goto S1; S0: S; i = i+1; goto FOR; S1: ...
4、根据下面的代码,填写表格。内存按2字节编址,整数占2字节,字符占1字节,指针占4字节。每个区域的相对地址都从0开始。
int num=2;//2存储在常量区,num存储在全局区,两个都是整形占2字节。 void main() { char str1[10]={"UESTC"};//"UESTC"和10存储在常量区,各占6和2个字节 char *str2="CHENGDU";//"CHENGDU"存储在常量区,占8各字节,注意’\0’。 char p;//p存储在main区,占1字节。str1和str2存储在main区,str1占10字节,str2占4字节 } void func(int m)//m存储在func区,占2字节 { int n=10;//n存储在func区,10存储在常量区,各占2字节。 }
根据出现的顺序,就可以知道相对地址为多少了。每占用两个字节,内存向后偏移一位。
5 填空题
5.1 给定一个数,给出质数分解结果,例如90=2*3*3*5。
int main() { int n, i=2; printf("\nInput:"); scanf("%d", &n); printf("="); i = 2; while (n > 1) { if (n%i == 0) { printf("%d", i); n = n / i; if (n > 1) printf("*"); } else i++; // 如果不能整除时,说明不是其素数 } return 0; }
5.2 若100个人围成圈,从第一个人开始,1~3报数,数到3的人退出,求剩下来的人编号是几号
代码:
//求最后剩下的编号 int main( { int n = 100, num[100]; int m /*m为已退出人数*/,f = 3, i, *p; p = num; for (i = 0; i < n; i++) //将1~n存入num { *(p + i) = i + 1; } i = 0; m = 0; int k = 0; // k是工作指针 printf("杀死顺序为:\n"); while (m < n - 1) { if (*(p + i) != 0) //碰到元素为0的跳过,说明已经杀死,不再参与计数 { k++; } if (k == f) //正好到第f个时,将第f个元素置0 { printf("%d\t",*(p + i)); //输出满足条件的元素 *(p + i) = 0; k = 0; //重新开始计数 m++; } i++; if (i == n) //当i = 6时,将i置0,循环操作 i = 0; } while (*p == 0) { p++; } printf("\n最后一个是:%d",*p); return 0; }
扩展:约瑟夫环问题:【 N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1】
代码:
//求最后剩下的号 int main() { int n, num[100]; int m/*注:m为已退出人数*/,f, i, *p; printf("n= "); scanf("%d", &n); //n是总人数 printf("f= "); scanf("%d", &f); //f是第f个杀掉的人 p = num; for (i = 0; i < n; i++) //将1~n存入num { *(p + i) = i + 1; } i = 0; m = 0; int k = 0; // k是工作指针 printf("杀死顺序为:\n"); while (m < n - 1) { if (*(p + i) != 0) //碰到元素为0的跳过,说明已经杀死,不再参与计数 { k++; } if (k == f) //正好到第f个时,将第f个元素置0 { printf("%d\t",*(p + i)); //输出满足条件的元素 *(p + i) = 0; k = 0; //重新开始计数 m++; } i++; if (i == n) //当i = 6时,将i置0,循环操作 i = 0; } while (*p == 0) { p++; } printf("\n最后一个是:%d",*p); return 0; }
5.3 带头结点链表逆序 【同2017年24题】
方法1:取下头结点,然后按照头插法即可实现链表逆序
方法2:后继指针指向前驱结点
6 编程题
6.1 将给定字符串例如”aaa111bbb222#”中的数字全部提取出来,放到给定的数组中。字符串以#结尾。
函数形式为void int_find(int arr[], char *pc);溢出以-1作为标志
分析:该题目有一处表述不清,即溢出以-1做为标志。已知C语言无法求出这种情况下的数组长度,所以无法判断数组溢出。综上,该溢出标志可能为数组的最后一个元素,即所有数字查找完毕时以-1结尾。
代码:
#include <stdlib.h> void int_find(char *pc) { int arr[50] = {0}; char *p = pc; // p 是工作指针 int i = 0; while (*p != '\0') { if (*p >'0'&&*p <'9') { arr[i]=atoi(p); /* int atoi(const char *str): 把参数str所指向的字符串转换为一个整数(类型为 int 型),该函数返回转换后的长整数,如果没有执行有效的转换,则返回零,标准库:<stdlib.h> */ i++; //遇到数字后继续进行直到遇到非数字元素 while (*p >'0'&&*p <'9') { p++; } } //如果不是数字,则跳过 else p++; } arr[i] = -1; //最后以-1结尾 //输出arr的值 int *q = arr; for(i = 0;*(q + i) != -1;i++) { printf("%d\t",arr[i]); } } int main() { char ch[] ="aaa111bbb222dsadas2ew2ewq213rf32342r53433#"; char *c = ch; int_find(c); return 0; }
6.2 随机输入最多100个整数和浮点数,将整数按从大到小排列,浮点数按从小到大排列(浮点数排序可省略),并输出。
如:输入10 12.3 12 5 52.1 3.65 88.6 1.0 输出:12 10 5 1.0 3.65 12.3 52.1 88.6
分析:这道题目在不借助库函数编程非常困难,也是当年的一道难题。若忽略1.0这样的数字,可以将输入全部视为浮点数,然后判断浮点数可以使用if(int(num)==num)这种方法判断。要实现完美解答,并以最少的时间完成本题,需要借助strstr、atoi、atof三个函数
代码:
#include <stdio.h> #include <stdlib.h> //整数降序排序 void sort_int(int num[], int n) { int i, j; for (i = 0; i<n - 1; i++) { for (j = i + 1; j <= n - 1; j++) { if (num[j]>num[i]) { int temp = num[i]; num[i] = num[j]; num[j] = temp; } } } //输出整型 for(i = 0;i < n;i++) { printf("%d\t",num[i]); } } //浮点数升序排序 void sort_float(float num[],int n) { int i,j; //冒泡排序 for(i = 0;i < n-1;i++) { for(j = i+1;j <= n-1;j++) { if (num[j]<num[i]) { int temp = num[i]; num[i] = num[j]; num[j] = temp; } } } //输出浮点数 for(i = 0;i < n;i++) { printf("%f\t",num[i]); } } int main() { int intarr[100]; float fltarr[100]; int m=0,n,i=0,j=0; char buff[100]; printf("input n:\n"); //n是几个数 scanf("%d", &n); while (m < n) { scanf("%s", buff); //如果是浮点型数 if (strstr(buff, ".")) /* strstr(str1,str2)函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL */ fltarr[j++]=atof(buff); //浮点数存入fltarr数组 /* float atof(const char *str)把参数str所指向的字符串转换为一个浮点数(类型为 float型,函数返回转换后的单精度浮点数,如果没有执行有效的转换,则返回零(0.0),标准库:<stdlib.h> */ else //若为整型 intarr[i++] = atoi(buff);//整型存入intarr数组中 m++; } printf("排序后:\n"); sort_int(intarr, i); sort_float(fltarr,j); return 0; }
6.3 编写完整的程序,构造整数集合,并实现对该集合操作的若干功能:查找集合内的某元素;集合中加入一个新元素;删除集合中某一元素;求两个集合的并集;求两个集合的交集;并给出main函数调用的例子
分析:该代码等价于构造一个链表,判断某元素是否在链表内,当加入一个元素时,判断该元素是否在链表内,如果不在则插入链表;当删除一个元素时,找到这个元素并删除该节点;输出两个链表的交集,输出两个链表的并集。该题目代码量非常大
代码:
#include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node *next; }; //判断某元素是否在集合内 int isexist(struct node *L, int num) { struct node *p = L->next; while (p != NULL) { if (p->data == num)return 1; p = p->next; } return 0; } //增加一个元素 void add(struct node *L, int num) { //头插法,逆序 if (isexist(L,num) == 0) { struct node *p = (struct node *)malloc(sizeof(struct node)); p->data = num; p->next = L->next; L->next = p; } } //删除集合中某一元素 void del(struct node *a, int num) { if (isexist(a,num) == 0) { printf("没有此元素,删除失败!\n"); } struct node *p = a->next, *pre = a; while (p != NULL) { if (p->data == num) { pre->next = p->next; free(p); break; } pre = p; p = p->next; } } //输出链表 void inputnode(struct node *a) { struct node *l = a ->next; while(l != NULL) { printf("%d\t",l ->data); l = l ->next; } } //输出两个集合并集 void intersection(struct node *a, struct node *b) { struct node *p = a->next; int flag = 0; while (p != NULL) { printf("%d ", p->data); p = p->next; } struct node *q = b->next; while (q != NULL) { p = a->next; flag = 0; while (p != NULL) { if (q->data == p->data) { flag = 1; break; } p = p->next; } if (!flag) printf("%d ", q->data); q = q->next; } } //输出两个集合交集 void Union(struct node *a, struct node *b) { struct node *p = a->next, *q = b->next; while (p != NULL) { q = b->next; while (q != NULL) { if (p->data == q->data) { printf("%d ", q->data); break; } q = q->next; } p = p->next; } } void main() { struct node *L = (struct node *)malloc(sizeof(struct node)); //L的头结点 struct node *S = (struct node *)malloc(sizeof(struct node)); //S的头结点 L->next = NULL; S->next = NULL; printf("输入L:\n"); int temp; scanf("%d", &temp); while (temp != -1) { add(L, temp); scanf("%d", &temp); } printf("输入S:\n"); scanf("%d", &temp); while (temp != -1) { add(S, temp); scanf("%d", &temp); } printf("输出L:"); inputnode(L); printf("\n输出S:"); inputnode(S); printf("\n删除L中的元素2:\n"); del(L,2); inputnode(L); printf("\n并集:"); intersection(L, S); printf("\n交集:"); Union(L, S); }