期末复习练习解析01
1、选择题(20分)
1.1 C语言unsigned char类型数据能表示的最大数值是:( )
A、65535 B、128 C、127 D、255
答案:D
解析:
char为1字节(byte),8位(bit),unsigned char为无符号,因此8位中不需要预留符号位,8位都表示数据(二进制:1111 1111):28 - 1 = 255。
char:1字节(8位)
int:4字节 (32位,取值范围 -2^31 ~ 2^31-1)
unsigned int:4字节 (32位,取值范围 0 ~ 2^32-1)
long:4字节 (32位,取值范围 -2^31 ~ 2^31-1)
unsigned long:4字节 (32位,取值范围 0 ~ 2^32-1)
long long:8字节(64位,取值范围 -2^63 ~ 2^63-1)
1.2 执行下列int i = 0, for(;i<5;)i++; 程序段后,i值为:( )
A、0 B、6 C、5 D、4
答案:C
解析:
i = 0时,满足循环条件(i<5),进入循环执行i++,i变成1;
i = 1时,满足循环条件(i<5),进入循环执行i++,i变成2;
i = 2时,满足循环条件(i<5),进入循环执行i++,i变成3;
i = 3时,满足循环条件(i<5),进入循环执行i++,i变成4;
i = 4时,满足循环条件(i<5),进入循环执行i++,i变成5;
i = 5时,不满足循环条件(i<5),退出循环。
1.3 关于C的整型常量说法正确的是:( )
A、0812 B、’\128’ C、-0xfadu D、2e2
答案:C
解析:
A选项中,以0开头的数字为八进制,可以使用0-7的数字,但八进制中没有8。
B选项中,\为反斜杠,表示转义符,后面可以接一个特殊字符(譬如’\n’为换行)、可以接一个三位的八进制数(譬如’\127’表示ASCII表中的字符'W',十进制值为87)、可以接一个两位的十六进制数(譬如'\x57'表示ASCII表中的字符'W',十进制值为87)。B中’\128’八进制中没有8。
C选项中,以0x开头的数字为十六进制,可以使用0-9, A-F。最前面的是负号,负数以补码形式保存,符号位取1。末尾的u ,告诉编译器该常数的属性,作为无符号类型的数据进行处理。
D选项中,2e2,为科学计数法,即2*102 = 200。
1.4 C语言中的关键字是:( )
A、sort B、char C、function D、=
答案:B
解析:char表示字符数据类型
1.5 执行double a, d = 3.4; int b; a = (b=d/2.0)/2; printf(“%.2f,%d”, a,b);代码段后的结果是:
A、0.00, 2 B、0.85, 1 C、0.85, 2 D、0.00, 1
答案:D
解析:
执行语句a = (b=d/2.0)/2;
- 先执行d/2.0,由于d= 3.4两个浮点数相除,得到1.7
- 再执行1.7赋值给b,由于b为整型数,因此1.7会去掉小数部分,b = 1
- 执行1/2,由于两个都是整型数,因此商0.5会去掉小数部分变成0,再赋值给a,由于a为double类型,所以a=0.000000。
- 输出a与b,输出a的格式符为%.2f,即保留2位小数精度,输出0.00。b的格式符为%d,输出1。
1.6 代码void f() {static int x = 1; }中关于变量x作用域说法正确的是:
A、块作用域 B、函数作用域 C、文件作用域 D、函数原型作用域
答案:B
解析:
作用域:描述了程序中可以访问一个标识符的一个或多个区域,即变量的可见性。
静态(static)局部变量作用域是在定义的函数内有效。static局部变量的生命周期和程序运行周期一样,同时staitc局部变量的值只初始化一次,但可以赋值多次。static局部变量若未赋以初值,则由系统自动赋值:数值型变量自动赋初值0,字符型变量赋空字符。
静态(static)全局变量:在函数外定义,作用范围被限制在所定义的文件中。不同文件静态全局变量可以重名,但作用域不冲突。static全局变量的生命周期和程序运行周期一样,同时staitc全局变量的值只初始化一次。
块作用域:譬如if(){}、while(){}、switch(){ case 1:{}} 等各种情况的{}即块作用域,在{}中定义的变量,作用域仅限定在{}中。
文件作用域:任何在代码块之外声明的标识符都具有文件作用域。
1.7 对于二维数组int a[3][5],下列表达式说法正确的是:
A. *++a是元素啊[1][0]的地址
B. a[0]是元素a[0][0]的地址
C. a[0]是首行的行地址
D. *a++是元素a[0][0]的地址
答案:B
解析:
a为数组名,是constant pointer,它的指向不能被修改,++a与a++都不能指向,A与D都不对。
a[0]等价于*a,即*(a+0)+0,取到了一次间访,表示某个元素的地址(二维数组中,取一次间访,取到某个元素地址,取两次间访,表示某个元素的内容)
行地址表示a+1表示第二行行地址,a+3表示第四行行地址。
1.8 关于函数,表达正确的是:
A. 执行语句return;函数返回值为0
B. 无return语句函数返回值为0
C. 函数参数传递本质上均是值传递
D. 函数可以嵌套定义
答案:C
解析:
A选项中,return; 退出函数,无返回值;
B选项中,如果函数中无return语句,该函数不返回值。
C选项,函数参数传递包括:传值和传地址。传值传递了原值的一个拷贝,原值不会被修改;传地址,传递了一个地址的拷贝,通过该地址,可以修改原值。
D选项:函数不可以在另一函数中进行定义,不能嵌套定义,但可以嵌套调用。
1.9 定义#define s(r) 3.14*r*r计算圆面积,则printf(“%6.2f”, s(s(1)+2))的值:
A. 18.14 B. 28.26 C.7.14 D. 82.96
答案:A
解析:
宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。宏替换只是单纯的替换,因此对s(s(1)+2)替换时,先替换s(1),变成s(3.14*1*1+2),再进一步替换:3.14*3.14*1*1+2*3.14*1*1+2 = 18.14。
注意,第二步替换的结果并不是3.14*(3.14*1*1+2)*(3.14*1*1+2)+2 = 82.96,如果希望这样,宏定义时,表达式要加上小括号:#define s(r) (2.14*r*r)
1.10 若声明int year表示年份,则判断闰年的表达式是:
A. year%4==0 && year%100!=0
B. Year%400==0
C. Year%4==0 && !(year%100) || year%400 == 0
D. Year%4==0 && year%100 || year%400 == 0
答案:D
解析:
闰年判断条件:能被4整除,但不能被400整除;或者能被400整除。
year%4 == 0 表示能被4整除
year%100!=0表示不能被100整除
year%100为真,表示不能被100整除
- 程序阅读题(28分)
2.1
#include<stdio.h>
void main(){
int i, n = 30;
long a = 1, b = 1, tmp;
for(i = 0; i< n; i++)
tmp = a, a = b, b +=tmp;
printf("%.3f %.3f\n", (double)a/tmp, (double)tmp/a);
}
答案: 1.618 0.618
解析:列举多次循环下,tmp, a, b的不同取值,可以发现,tmp和a满足斐波那数列,即
tmp: 1 1 2 3 5 8 13 21 34 55 89 ......
a: 1 2 3 5 8 13 21 34 55 89 144 ......
并不需要计算出i=29时的a与b值,再进行除法运算。
分析可得,a/tmp为数列中后项与前项的比值
tmp/a为数列中前项与后项的比值
可以发现,这个比值,随着项数的增加,会趋向一个常数(黄金比)。
取144/89和89/144计算即可。
自己可以编码验证一下:
#include <stdio.h>
int fac(int n){
if(n == 0 || n ==1)
return 1;
return fac(n-1)+ fac(n -2);
}
int main() {
printf("%.3f %.3f", (double)fac(30)/fac(29),
(double)fac(29)/fac(30));
return 0;
}
2.2
#include<stdio.h>
void main(){
int i, j, s, x[4][4]={1,2,3,4,3,4,5,6,5,6,7,8,7,8,9,10};
for(i = 0; i< 4; i++) {
s = 0;
for(j = 0; j< 4; j++) {
if(i>=j) continue;
s+=*(x[i]+j);
}
printf("%d\t",s);
}
}
答案: 9 11 8 0
解析:
if(i>=j) continue; 表示当左下角的数字不进行累计求和。右上角(不包括对角线上的数)的数,每一行的数据分别累计求和。
第一行:2+3+4==9
第二行:5+6=11
第三行:8
第四行:0
2.3
#include<stdio.h>
void f1(float x, float y){
float tmp;
tmp = x, x = y, y = tmp;
}
void f2(float *x, float*y){
float * tmp;
tmp = x, x = y, y = tmp;
}
void f3(float *x, float * y){
float tmp;
tmp = *x, *x = *y, *y = tmp;
}
void main(){
float x = 3.14, y = 6.28, *p1 = &x, *p2= &y;
f1(*p1, *p2), printf("%5.2f %5.2f\n", x,y);
f2(p1, p2), printf("%5.2f %5.2f\n", x,y);
f3(&x, &y), printf("%5.2f %5.2f\n", x,y);
}
答案:
3.14 6.28
3.14 6.28
6.28 3.14
解析:
函数f1传值方式,不能实现交换功能
函数f2传指针方式,但函数的实现逻辑不能实现交换功能
函数f3传指针方式,能实现交换功能。
f1(*p1, *p2)函数调用时,实参为间访,函数f1为传值方式,不能实现交换功能
f2(p1, p2)函数调用时,实参为两个指针,但f2函数的实现逻辑不能实现交换功能
f3(&x, &y)实参为两个地址,能实现交换功能
2.4
#include<stdio.h>
char n = 65;
void f(){
static char a = 'A';
char b = 'B';
a+=2, b+=5, n+=3;
printf("%c\t%c\t%c\n", a,b,n);
}
void main(){
char a = 'A', b = 'B';
printf("%c\t%c\t%c\n", a,b,n);
f();
printf("%c\t%c\t%c\n", a,b,n);
}
答案:
A B A
C G D
A B D
解析:
常用字母的ASCII值:A-->65, Z-->90, a-->97, z-->122, 0-->48, 9-->57
char n = 65; n为全局变量,ASCII码值65对应字符’A’。函数f()中n+=3,n被修改为’D’
函数f()中,a为静态局部变量,b为局部变量,a与b的作用域为函数f(),a+=2, b+=5,修改a,b的值只在f()函数中起作用。
main函数中,
a与b为局部变量,作用域为main函数中。
第一句printf("%c\t%c\t%c\n", a,b,n); a = 'A', b = 'B,n= ’A’。
执行f()函数,输出f()函数中的a,b,n值,分别为a = 'C', b = 'G,n= ’D’。
第二句printf("%c\t%c\t%c\n", a,b,n); ,a = 'A', b = 'B,由于n已经在f()函数中被修改n= ’D’
2.5
#include<stdio.h>
#include<string.h>
void main(){
char tmp[81], a[6][81] = {"chemical", "biotech", "materials",
"computer", "information", "public admin"};
int i,j,k;
for(i=0; i<5; i++){
k = i;
for(j = i+1; j<6; j++)
if(strcmp(*(a+j), *(a+k))>0) k = j;
strcpy(tmp, *(a+i));
strcpy(a[i], a[k]);
strcpy(*(a+k),tmp);
}
for(i = 0; i<3; i++) puts(a[i]);
}
答案:
public admin
materials
information
解析:
二维数组a为字符串数组;字符数组tmp为字符串。
代码中采用了选择排序方法,对字符串数组进行降序排序。排序中字符串的比较与交换需要使用strcmp和strcpy函数。间访*(a+j),也可以表示为a[j],表示第j+1个字符串。
puts函数用于输出字符串,代码中输出了前三个字符串。
- 程序填空题(12分)
- 【程序说明】下列函数用于在升序排列的数组v中找出x的位置。
int binSearch(int x, int v[], int n){
int low =0, high = n-1, mid;
while (low <= high){
mid = (1) ;
if(x <v[mid])
high = (2) ;
else if (x > v[mid])
low = (3) ;
else
return mid;
}
return -1;
}
答案:
(1) (low + high) / 2 (2) mid – 1 (3) mid + 1
解析:
本函数为二分法查找算法。x为待搜索的数字,v为已经排好序的数组,n为数组元素个数。
二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法。
二分法查找的思路如下:
(1)首先,从数组的中间元素(下标为:mid = (low+high)/2)开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
(2)如果目标元素小于中间元素,则在数组小于中间元素的那一半区域查找(修改high = mid - 1),然后重复步骤(1)的操作。
(3)如果目标元素大于中间元素,则在数组大于中间元素的那一半区域查找(修改low = mid + 1),然后重复步骤(1)的操作。
(4)如果某一步数组为空(low > high),则表示找不到目标元素,返回-1值。
可以执行下面代码验证:
#include<stdio.h>
int binSearch(int x, int v[], int n){
int low =0, high = n-1, mid;
while (low <= high){
mid = (low + high)/2;
if(x <v[mid])
high = mid -1;
else if (x > v[mid])
low = mid+1;
else
return mid;
}
return -1;
}
void main(){
int a[10] = {1,2,7,8,9,10,11,90,98,109};
int result = binSearch(90, a, 10);
printf("%d", result);
}
-
- 【程序说明】校区信息保存在新飞行对象中,要求找出学生最多的校园,请根据代码中上下文信息补充所缺内容。
#include <stdio.h>
struct campus {float area; int students; char name[50];};
void main() {
struct campus univ[4] ={{414, 3000, "朝晖"},{2150, 15000, "屏峰"},
{990, 5000, "莫干山"},{222, 7500, "之江"}};
struct campus *p = univ;
int num = univ->students;
for(int i = 1; i< sizeof(univ)/sizeof(struct campus);i++) {
if( (1) ){
(2) ;
(3) ;
}
}
printf("%s %d %.0f\n", (4) , (5) , (6) );
}
答案:
(1) univ[i].students > num (2) p = univ+i (3) num = p->students
(4) p->name (5) p->students (6) p->area
解析:
题目中定义了结构体类型campus,在main函数中定义了结构体类型数组univ、结构体类型指针p。指针p用于保存找到的学生最多的校园,num用于保存最大学生数目。
for循环对数组里面的每一个校区进行遍历,if语句需要判断当前遍历到的校区,它的人数是不是大于num ,如果大于num,就用p记录该校区,它的学生人数也赋值给num。
当for循环执行结束后,p指向了数组中学生最多的校园。通过printf函数,输出该校区的相关信息。
由于p是指针,它的成员运算符要使用->。
- 程序设计题(40分)
4.1 已知某公司员工的保底薪水为800元,某月所接工程的利润profit(整数)与利润提成的关系如下(计量单位:元):
profit <= 1000 没有提成
1000 < profit <= 2000 提成10%
2000 < profit <= 5000 提成15%
5000 < profit <= 10000 提成20%
profit > 10000 提成25%
编写程序计算该公司员工该月的薪水。(10分)
答案:
#include <stdio.h>
void main() {
int profit, grade;
double salary = 800;
printf("请输入本月利润:");
scanf("%d", &profit);
grade = (profit-1) / 1000;
switch(grade) {
case 0: break;
case 1: salary += profit*0.1; break;
case 2:
case 3:
case 4: salary += profit*0.15; break;
case 5:
case 6:
case 7:
case 8:
case 9: salary += profit*0.2; break;
default: salary += profit*0.25; }
printf("本月薪水:%.2f", salary);
}
答案:
#include <stdio.h>
#include <math.h>
void main() {
double x, fx, gx;
scanf("%lf", &x);
gx = x*x - 2;
if (x >= gx)
fx = gx - sin(x) - x;
else
fx = gx + sin(x) + x + 4;
printf("%8.2f\n", fx);
}
4.3 现有数列 1,1/(1+2),1/(1+2+3),1/(1+2+3+4),…,编写程序计算并输出误差小于给定ε(如0.00001,要求从标准输入设备输入)的数列和。(10分)
#include <stdio.h>
void main() {
int i, j, t;
double s=0, delta, epsilon;
scanf("%lf", &epsilon);
for (i=1;;i++) {
t = 0;
for (j=1; j<=i; j++) t += j;
delta = 1.0 / t;
if (delta < epsilon) break;
s += delta; }
printf("误差小于%.2e的数列和: %8.6f\n", epsilon, s);
}
4.4 编写函数进行数据读取,左右反转和输出操作,函数原型为:
void scanArray(float [], int); void myReverse (float*, int);
void printArray(float *, int);
在main函数中分别调用上述函数输入10个实数,执行左右翻转并输出。(10分)
答案:
#include <stdio.h>
void scanArray(float [], int);
void printArray(float *, int);
void myReverse(float *, int);
void main() {
float a[10];
scanArray(a, 10);
myReverse(a, 10);
printArray(a, 10);
}
void scanArray(float x[], int n) {
int i;
for (i=0; i<n; i++) scanf("%f", x+i);
}
void printArray(float *p, int n) {
int i;
for (i=0; i<n; i++) printf("%.2f ", *p++);
printf("\n");
}
void myReverse(float *p, int n) {
int i;
float temp;
for (i=0; i<n/2; i++) temp = p[i], p[i] = p[n-1-i], p[n-1-i] = temp;
}