1 单项选择题(15⼩题,每⼩题2分,共30分)
1.1
解析:【传值调用】,实参和形参之间传递的是“地址”
1.2
解析:【优先级】:算术运算符 > 关系运算符 > 赋值运算符
【结核性】:赋值运算符(从右至左) 算数运算符和关系运算符(从左至右)
相当于: ( k > i ) < j , ( i < j ) == ( j < k )
1.3
解析:指针数组是指数组的每一个元素都是一个指针变量的数组
相当于: point[2] 一样
此题不合适之处:
#include <stdio.h> #include <stdlib.h> int main() { char *point[] = {"one","two","three","fourth"}; point[2] = point [3]; point[2] += 2; printf("%s",point[2]++); // 输出的是字符串,不用point[2]++ return 0; }例如:
1.4
解析:数组定义时,常量表达式中不允许包含变量
1.5
解析:【函数递归】,相当于 fib (2) + fib (1)
1.6
解析:【do 循环】
1.7
1.8
解析:【数组传参】:传过去的是地址,实参和虚参都改变
1.9
题目有错!!!
解析:【运算优先级】:“ * ”和“ ++ ” 高于 " = ",“ * ”和“ ++ ”优先级相同,结合性:从右往左
*p1 += *p2++ 相当于: *p1 = *p1 + *(p2++)
*p2 = p1++ 相当于: *p1 = (p1++)
1.10
解析:【运算优先级】+ 【结合性】
i = 3 / 2 + 7 / 2 == 5 相当于: i = ( ( (3 / 2) + (7 / 2) ) == 5 )
j = 45 % 11 + (((7 > 8) ? 15: 14) == 14 相当于:j = (45 % 11) + ((((7 > 8) ? 15: 14) == 14 )
1.11
解析:!x是逻辑非操作,当x为0时,值为真,否则值为假。 在这里x = 8,即!x = 0,故while (!x) 为假,退出循环
例如:
1.12
解析:(i * j) / k + 6 - 15 % k 相当于 ((i * j) / k) + 6 - (15 % k) : “+”和“-” 结合性从左向右
1.13
解析: while()是循环语句。while(expr)表示当逻辑表达式expr为真时,循环运行循环体,直到expr值为假或遇到break语句时退出
由 316 = 13 * i + 11 * j 得:k 一定得是11的倍数
例:
1.14
解析:【字符数组的定义】:
char cc[ ] = {'1','2','3','4','5'}, 数组长度为5,字符串长度为5
char cc[ ] =”12345“,数组长度为6,字符串长度为5,自动在字符串结尾加上一个终止符 ,
[strlen()]函数:测试字符串长度,不包括
1.15
解析: 【指针与结构数组】:指向结构 的 指针 要先定义,后赋值
p 指向结构第一个字节,*p 相当于 stu
第一种方式:(*p).num 【由于结构成员引用符 "."的优先级比间接运算符 “ *” 高,故必须加括号】
第二种方式:p->num
第二种方式:stu.num 三种方式等价!!!
2 指出程序段中的错误:分析原因并修改。(每题15分,共30分)
2.1
改正后:
int main() { char *src = "HELLO,UESTC"; //指向字符串常量的指针 char *dest = NULL; int len = strlen(src); dest = (char *)malloc(len + 1); char *d = dest; char *s = &src[len - 1]; while ( len-- != 0 ) *d++ = *s--; *d = ' '; printf("%s ", dest); // 使用printf()输出时,%s 表示输出一个字符串,src指向字符串的第一个字符,然后src自动加1 free(dest); return 0; }
知识点:
【指向字符串常量的指针】:不是将字符串存放在指针src中,而是将指向字符串的指针赋给指针变量,src指针指向字符串的首地址
2.2
改正后:
int func() {
//函数功能:复制字符数组data到array中 char data[50] = "welcome to CHENGDU and UESTC"; char *point; char array[200]=""; //初始化为空传 int i = 0, length = 0; point = array; while (data[length] != ' ') //1处 length++; for (; i < length; i++) { *point = data[i]; //2处 point++; } puts(array); //3处 }
3 问答题(共70分)
3.1 C语⾔的单词符号除关键字外,还包括其他哪四类?存储类型关键字是哪4个?(每个1分,共8分)
答: 标识符【只能由字母、常量、下划线、数字组成,且第一个字符必须是字母或者下划线】、运算符、常量和分隔符【空格、制表符、换行符】。
存储类型关键字:anto、extern、register、staticC语言变量有四种存储类型:
自动型(auto)
外部型(extern)
静态型(static)
寄存器型(register)
3.2 函数中,如何使⽤与局部变量同名的全局变量?(3分)
答:使⽤::(作⽤域区分符)(3分)
如何将一个内部变量或者是在函数后定义的外部变量,在该函数中使用:extern 变量名 (进行引用声明,这时是不分配存储空间的)
3.3 如何使⽤1个表达式将float类型变量f的值四舍五⼊ 转换为long类型的值?(3分)
答:(long)(f + 0.5) (3分)
3.4 参数传递的⽅式分别是什么?(6分)
数组作为函数参数有三种形式:
1. 实参是数组元素; 传(数据)值(2分)
2. 形参是指针,实参是数组; 传地址值(2分)
3. 函数的形参和实参都是数组。 传地址(2分)3.5 C程序运⾏时,不对数组进⾏越界检查,可能导致什么问题?(5分)
答:编译通过,但可能导致运⾏出错(访问不可访问的存储单元)(3分)或访问和修改
其他⾮数组元素的数据。(2分)3.6 C语⾔的隐式类型转换发⽣在哪4种情况下?转换规则分别是什么?(6分)
混合运算: 级别低的类型向级别⾼的类型值转换。 1分
将表达式的值赋给变量: 表达式的值向变量类型的值转换。 1分
实参向函数形参传值: 实参的值向形参的值进⾏转换。 2分
函数返回值: 返回值向函数返回类型的值进⾏转换。 2分3.7 程序⽚段为: (14分)
当程序执⾏进⼊fun函数时,请列出各个数据(包括常量、变量)在内存中对应存储区的名称和数据的存储顺序以及所占⽤的存储空间的字节数。
假设整数占2个字节,字符占2个字节,指针占4个字节;⽽内存按2个字节进⾏编址。存储区名称1分,其他每3个1分
int n = 2018; void main() { char * p=”COMPUTER”, *q; int mm, arr[2018]; char ch2; ... fun(mm); ... } void fun(int nn) { int mm = 10; static int snum; ... }
3.8 下⾯的程序的功能是什么?(5分)
void main () { int d, i, j, k, flag1, flag2; scanf("%d", &d); for (i = 1; i <= 100; i++) { j = i; flag1 = 0;
// 该数是否含有 d while ((j > 0) && (!flag1)) { k = j % 10; j = j / 10; if (k == d) flag1 = 1; }
// 该数的平方是否含有 d if (flag1) { j = i * i; flag2 = 0; while ((j > 0) && (!flag2)) { k = j % 10; j /= 10; if (k == d) flag2 = 1; } if(flag2) printf("%-5d %-5d ", i, i * i); } } }功能:输⼊数字d=0~9,找1~100中满⾜条件的数:该数的本⾝及它的平⽅中都含有数字d。
3.9 采⽤Eratasthenes筛选法求2-200之间的素数
链接:https://www.cnblogs.com/pam-sh/p/12384776.html 请对第6、7、8、9⾏的代码进⾏修改,使得程序执⾏效率得到提⾼。(8分)
void main() { int prime[201] = {0}; //用于存储200以内的数是否已筛去 int d, i,k; for (d = 2; d < 200; d++) if (prime[d] == 0) for (k = d + 1; k <= 200; k++) if (k % d == 0)
prime[k] = 1; for (i = 2; i <= 200; i++) if(prime[i]==0) printf("%d ", i); }// 改为: for (d=2; d < sqrt(200); d++) if (prime[d] == 0) for (k = 2*d; k<=200; k = k+d) //筛去d的所有倍数 prime[k]=1;
要点:
为提高筛选效率:
一个合数n必有一个不大于sqrt(n)的正因子,故一个数若是没有小于sqrt(n)的正因子,则说明它是一个素数
3.10 为提⾼程序执⾏效率,C语⾔除了提供指针、宏定义、位运算、不检查数组下标外,简述C语⾔还采取了其他哪些措施及原因(12分)
4 程序填空(每空2.5分,共50分)
4.1 快排找第K⼩
low = 0; // 该空为填空 high = n - 1; // 该空为填空 do { do { i = low; j = high; // 该空为填空 t = a[i]; // 该空为填空 }while(i < j); // 该空为填空 a[i] = t; // 该空为填空 if(i == k) return t; // 该空为填空 if(i > k) high = i - 1; // 该空为填空 if(i < k) low = i + 1; // 该空为填空 }while(low < high); return a[low]; // 该空为填空
此题错误!!!
改正后:还是有错!!!
low = 0; high = n - 1; do { i = low; j = high; t = a[i]; do { while (a[j--] > t) ; while (a[i++] < t) ; if(i < j) swap(a[j], a[i]); }while(i < j);
// 折半查找 if(i == k) return t; if(i > k) high = i - 1; if(i < k) low = i + 1; }while(low < high); return a[low];参考:215
4.2 ⼀个包含9个数的⾮降序【升序】数列存储在数组中,现在插⼊⼀个数到合适位置,使序列保持⾮降序(插⼊的数⼤于第⼀个数,⼩于第九个数)。
#define N 10 void main() { int a[N] = {1,2,4,8,16,32,64,128,256}; int m,i,d; scanf("%d",&d);
//找到插入点 for(i = 0; i < 9 ; i++) //这里填N-1也行 if( d < a[i] ) { m = i ; // m记录插入点 break ; }
// m之后的往后移 for(i = 8; i >= m; i--) //这里填N-2也行 a[i + 1] = a[i];
// 插入 a[m] = d;
// 打印 for(i = 0;i < N;i++) printf("%d ",a[i]); }补充:把一个整数按从大到小顺序插入到已经排好序的数组中
代码:
#include <stdio.h> #include <stdlib.h> void insert(int a[],int n) { int i,s; // 类似于 “直接查找排序” for(i = 0; i < 10; i++) { // 找插入位置 if(n > a[i]) { for(s = 9; s >= i; s--) { a[s + 1] = a[s]; // 将插入位置后的元素后移 break; } } } a[i] = n; // 插入数字 }
void main() { int i,j,temp = 0,n,p,q,s,a[10] = {127,3,6,28,54,68,87,105,162,18}; //排序(从大到小) //1.1 冒泡排序 ,从后向前 for(i = 0;i < 9;i++) // n - 1趟 { for(j = 9;j > i;j--) // n - i 次交换 { if(a[j] > a[j - 1]) { temp = a[j - 1]; a[j - 1] = a[j]; a[j] = temp; } } } //1.2冒泡排序 ,从前向后 for(i = 0;i < 9;i++) // n - 1趟 { for(j = 0;j < 9 - i ;j++) // n - i 次交换 { if(a[j] < a[j + 1]) { temp = a[j + 1]; a[j + 1] = a[j]; a[j] = temp; } } } // 从大到小输出: printf("排好序的数: "); for(i = 0;i < 10;i++) { printf("%d ",a[i]); } printf(" "); // 2、简单选择排序:假设排序表为L[1....n-1],第i趟排序即从L[1....n-1]中选择一个最大的元素与L[i]交换,每趟可以确定一个元素,经过n - 1趟就ok了 for(i = 0; i < 10; i++) { p = i; q = a[i]; for(j = i + 1; j < 10; j++) { if(q <a[j]) { p = j; q = a[j]; } } if(p != i) { s = a[i]; a[i] = a[p]; a[p] = s; } printf("%d ",a[i]); } printf(" "); printf("请输入数字: "); scanf("%d",&n); insert(a,n); // 插入后从大到小输出: for(i = 0; i <=10; i++) { printf("%d ",a[i]); } printf(" "); }4.3 凯撒密码
这道题是⼀道加密解密问题,⼤致的意思就是通过主函数输⼊两个字符串,第⼀个字符串作为加密解密的⽬标
字符串,第⼆个字符串通过函数转换为整型数据作为解密加密的key,这道题也不难推导,以上是我在⽹络上找到
的⼀个相似版本。
凯撒加密(Caesarcipher)是⼀种简单的消息编码⽅式:它根据字母表将消息中的每个字母移动常量位k。
举个例⼦如果k等于3,则在编码后的消息中,每个字母都会向前移动3位:
a会被替换为d;b会被替换成e;依此类推。字母表末尾将回卷到字母表开头。
于是,w会被替换为z,x会被替换为a。代码:
#include <stdio.h> #include <stdlib.h> int main () { char small_letter[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; char big_letter[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; char text[1000], result[1000]; int c, count = 0, k, p,i; char function; printf("Insert Text:"); c = getchar(); while (1) // 读取字符串 { if (c == ' ') break; text[count] = c; printf("%c", text[count]); count++; c = getchar(); //读取下一个字符 } printf(" "); printf("Encrypt or Decrypt? E or D :"); scanf("%c", &function); // 解密 if (function == 'D') { printf("Insert Key :" ); scanf("%d", &k); for (i = 0; i < count; i++) { if (text[i] >= 'A' && text[i] <= 'Z') { result[i] = big_letter[((text[i] - 'A') + k) % 26]; // 向后挪k位 } //找出加密后字符在字符数组里的对应位置 else if (text[i] >= 'a' && text[i] <= 'z') { result[i] = small_letter[((text[i] - 'a') + k) % 26]; // 向后挪k位 } else result[i] = text[i]; printf("%c", result[i]); } } // 加密 else { printf("Insert Key :" ); scanf("%d", &k); for (i = 0; i < count; i++) { if (text[i] >= 'A' && text[i] <= 'Z') { p = ((text[i] - 'A') - k); // 解码涉及 字母表末尾将回卷到字母表开头 while (p < 0) p += 26; result[i] = big_letter[p]; // 向前挪k位 } //找出解密后字符在字符数组⾥里里的对应位置 //这里要注意不要让它超出范围(下表位置为负数) else if (text[i] >= 'a' && text[i] <= 'z') { p = ((text[i] - 'a') - k); while (p < 0) p += 26; result[i] = small_letter[p]; // 向前挪k位 } else result[i] = text[i]; printf("%c", result[i]); } printf(" "); } return 0; }
5 程序设计(共20分)
5.1 输⼊若⼲个整数(以0结束)如何逆序构建双向链表
代码:
#include <stdio.h> #include <stdlib.h> //双链表结构定义 typedef struct DNode { int data; struct DNode *pre; struct DNode *next; } DNode; int main() { DNode *head, *s; int t; // 定义头节点 head = (DNode*)malloc(sizeof(DNode)); head->pre = NULL; head->next = NULL; // 输入 scanf("%d", &t); while (t != 0) { s = (DNode*)malloc(sizeof(DNode)); s->data = t; s->next = NULL; s->pre = NULL; if (head->next == NULL) { head->next = s; s->pre = head; } else { // 头插法【逆序】 s->next = head->next; head->next->pre = s; head->next = s; s->pre = head; } scanf("%d", &t); } s = head->next; while (s) { printf("%d ", s->data); s = s->next; } return 0; }