当梦拓了,想 push 我的 xdx 们学 C 语言,遂有此文(不过大家好像也没好好学 QAQ )

C语言quiz(二)

by 西门蒸馍

考点

  • for 循环、循环控制
  • 数据类型
  • 整数补码
  • 整数范围
  • 字符类型
  • 类型转化
  • 位运算
  • 自定义函数
  • 生存周期 & 作用域
  • 数组

题目


    1. 以下哪个循环应用场景适合使用 for 循环

    ( )

    A. 计算从 1 到 n 的倒数和

    B. 使用 scanf 循环输入整数,直到读到文件末尾 EOF

    C. 构建一个死循环(循环条件值为 1 ),并在合适的时候 break

    D. 在进入循环前需要首先执行一次循环体

答案&解析

A【解析】

A. for 循环适合做遍历操作

B. 一般的写法是 while( scanf("%d",&n)!= EOF )

C. 一般的写法是 while(1){ if(...) break; }

D. 最适合使用 do{}while(...); 循环

PS: 本题没有绝对化,只讨论符合大众逻辑的代码风格,whilefor 两种循环实际上完全互通,如何选择全看个人习惯


    1. 以下关于整数数据类型的说法正确的有[多选]

    众所周知,计算机是以二进制的方式存储数据的,最小的单元为比特(bit),一个比特只能代表 01,做此题前,请先简要了解一下“字节”和“比特”

    ( )

    A. 常见的整数数据类型有 charshortintlonglong long

    B. 一个 char 类型的整数大小为一个字节(byte),一个字节占 6 个比特(bit)

    C. 在计算机上一个 int 类型的整数固定占 4 个字节

    D. 计算机中 int 类型默认为 signed int 有符号整数,char 类型默认为 unsigned char 无符号整数

    E. unsigned int 表示无符号的整数数据,只能表示非负数,但表示正数的最高上限约是signed int 的二倍

    F. C 语言中可以用 sizeof() 查看变量或数据类型的比特数

答案&解析

AE【解析】

B. 一个字节占 8 bit

C. 在不同类型的计算机上,int 的大小不同:目前可以简单认为,在 16 位的编译器上,int 占 2 字节;在 32 位的编译器上,int 占 4 个字节。

D. C 语言中并没有规定 char 是有符号整数还是无符号整数,不同计算机或编译器上可能不同。

F. sizeof() 查看的是字节数


    1. 以下关于计算机对整数的编码方式的说法中正确的有[多选]

    ( )

    A. 计算机对整数的编码方法有原码、反码、补码,目前计算机采用的是补码

    B. 采用补码的优点在于可以让计算机只通过二进制下的”加”,就可以完成整数范围内的加减运算

    C. 若一个 unsigned char 类型的整数的补码为 10100010,则该整数为 $2^2 + 2^6 + 2^8 = 324$

    D. 对于 signed char 的类型的数据,其能表示的最大的数的补码为 01111111 ,最小的数的补码为 10000000

    E. 有符号整数的最高比特位为0 则说明表示的是正数,最高比特位为1 表示的是负数

答案&解析

ABD【解析】

C. 二进制最小位是第 0 位 ,代表 $2^0$ ,该整数的值应为 $2^1 + 2^5 + 2^7 = 162$

E. 有符号整数的最高比特位为0 表示非负数


    1. 以下关于整数范围的说法正确的有[多选]

    本题中的 “a ~ b”,表示闭区间 [a,b]

    ( )

    A. 通常来讲,整数类型占用的字节越多,可表示的数据范围就越大

    B. 4 字节的 int 类型可表示 $-2^{32}$ ~ $2^{32}-1$ 之间的数据

    C. unsigned char 类型可以表示 $0$ ~ $2^{8}$

    D. 若int 类型的变量爆了 int 范围(即超过int 可表示的数的上限),例如,int a = 0; while(1) a++; 则当 a 超过了int 的上限时,a 会变为最小负数,继续自增

答案&解析

AD【解析】

B. 4 字节的 int 类型可表示 $-2^{31}$ ~ $2^{31}-1$ 之间的数据

C. unsigned char 类型可以表示 $0$ ~ $2^{8}-1$

D. 如第 3 题 C 选项所述,char 类型的数最大为 01111111 ,再自增后就变成了 10000000 ,从最大正数变为了最小负数,int 类型也一样


    1. 在控制台中输入 c d ,以下代码的输出结果为

    如有需要,请自行查询 ASCII 码表

    题目中的 [space] 表示字符空格

    ( )

    1
    2
    3
    4
    5
    6
    7
    8
    #include <stdio.h>

    int main(){
    char ch1,ch2;
    scanf("%c%c",&ch1,&ch2);
    printf("%c%d",ch1,ch2);
    return 0;
    }

    A. cd

    B. c100

    C. c[space]

    D. c32

答案&解析

D【解析】

  • 输入c[空格]d 实际上输入了 3 个字符,分别是 'c''[space]''d'scanf 函数会按输入顺序读取字符'c' 和字符'[space]' ,字符d 被丢弃了,所以实际上ch1 存储了字符'c'ch2存储了字符'[space]'printf函数先输出ch1 的字符,再输出ch2 的 字符的ASCII 码,所以最后输出结果为c32
  • 这也是大家常犯的错误,用scanf 读取数据时,一定考虑到输入数据的格式格式化字符串(就是scanf引号中的内容)。对于本题来说,如果要读入字符'c'和字符'd'的话,可以这样写:scanf("%c %c",&ch1,&ch2);,也就是让scanf 把输入进来的空格先读走,再读取字符d 。除了空格符以外,换行符'\n',也很容易造成 IO 问题(input 和 output,也就是输入输出问题),大家以后会学到更多 C 语言的 IO 知识,处理更复杂的 IO 问题。

    1. 下列代码语句执行过后,c 的值是 5546261880000 的选项有[多选]

    已知数学中乘法式 237324 * 23370000 = 5546261880000

    平时出现在源代码中的整数都默认为int 类型的, 1LL 表示 long long 类型的 1 ,等价于 (long long)1

    ( )

    A.

    1
    2
    int a = 237324, b = 23370000;
    long long c = a * b;

    B.

    1
    2
    int a = 237324, b = 23370000;
    long long c = 1LL * a * b;

    C.

    1
    2
    int a = 237324, b = 23370000;
    long long c = a * 1LL * b;

    D.

    1
    2
    int a = 237324, b = 23370000;
    long long c = a * b * 1LL;

    E.

    1
    2
    int a = 237324, b = 23370000;
    long long c = (long long)(a * b);

    F.

    1
    2
    int a = 237324, b = 23370000;
    long long c = (long long)(a) * b;

    G.

    1
    2
    int a = 237324, b = 23370000;
    long long c = a * (long long)(b);
答案&解析

BCFG【解析】

  • A 选项首先是错的。我们知道赋值运算实际上是先计算右值(等号右边的表达式),再赋给左值。在本题中,右值为 a*bab 均为 int 类型, 右值计算的结果也是一个int 类型的数据,其值本应该为 5546261880000 。但很显然,这个数值超过了 int 的上限 (爆了 int),出现这种情况时,程序会保留 5546261880000 二进制编码的前 32 位(int 类型占据的比特数,假设int 占 4 字节),将其作为 a*b 的值,并丢弃之后的比特位(long long类型的值占 64 比特位,所以丢弃后 32 个比特),实际得到的值为 1459100864。如下图所示。

    int爆炸后二进制转换示意图

  • 首先给大家回忆一下默认的类型转换。我们之前知道 double 类型的数与int 类型的数参与运算时,int 会被默认转为double 进行运算 ,例如我们把int 类型的整数 a 转为 double 类型的值, 既可以直接(double)a,又可以 a*1.0 。而 long long类型与int 类型同样满足这样的方法,所以一个int 的数* 1LL 后就成为一个long long类型的数,不存在 A 选项的情况,这样选项 B、C 就是正确的

  • 至于 D 选项,由于同优先级满足从左向右的计算规律,所以本质上是 (a*b)*1LLa*b 先计算,出现了类似 A 选项中的情况,所以 a*b*1LL 的结果为 long long 类型的1459100864
  • E 选项与 D 类似,F、G很好理解

    1. 填空题

      0x000000FF 代表一个前 8 比特位全为1 ,后 24 比特位全为 0int 类型的整数

      (1)0x000000FF & 256 的值为 0

      (2)n&1 的值为 0 ,说明整数n 偶数 (填 “奇数” 或 “偶数” )

      (3)想让整数n 第 0 比特位的值为1 ,应该可以使用某位运算符 ? 。若n?1 可以实现该效果,则位运算符? 应该为 | (填 &|^>><<~

      (4)对于任意有符号整数nn + ~n 的值为 -1

      (5)想要一个整数乘以 $2^n$ ,假设不超出数据范围,比较快的方法是进行 左移 运算(填 “左移” 或 “右移” )

      (6)负整数进行右移运算时,最高位会补上比特 1 (填 “ 0 ” 或 “ 1 ” )

答案&解析

0 偶数 | -1 左移 1

【解析】

(1)256 的二进制码只有第 8 个比特位为 1 ,其余都是 0 (比特位从 0 开始计数),而0x000000FF 第 0 ~ 7 比特位为 1 ,其余为 0 ,按位与 之后得到 0

(2)较好理解,记住就行

(3)按位或 可以进行置 1 操作

(4)举个例子:二进制码 01010101 按位异或 后得到 10101010 ,相加为 11111111 ,即为数 -1

(5)举个例子:无符号整数二进制码 01010101 的数值为 ,左移后得到 10101010 ,其数值为 ,变为了 2 倍。

(6)记住就行,右移运算时,若最高位为 1 则补 1 ;最高位为 0 则补 0


    1. 下列代码可以正常编译的有[多选]

    ( )

    A.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>

    int isEven(int x){
    if( x % 2 == 0 ) return 1;
    else return 0;
    }
    int main(){
    int x;
    scanf("%d",&x);
    if( isEven(x) ) printf("This is an even number\n");
    else printf("This is an odd number\n");
    return 0;
    }

    B.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>

    int main(){
    int x;
    scanf("%d",&x);
    if( isEven(x) ) printf("This is an even number\n");
    else printf("This is an odd number\n");
    return 0;
    }
    int isEven(int x){
    if( x % 2 == 0 ) return 1;
    else return 0;
    }

    C.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>

    int isEven(int x);
    int main(){
    int x;
    scanf("%d",&x);
    if( isEven(x) ) printf("This is an even number\n");
    else printf("This is an odd number\n");
    return 0;
    }
    int isEven(int x){
    if( x % 2 == 0 ) return 1;
    else return 0;
    }

    D.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>

    int isEven(int);
    int main(){
    int x;
    scanf("%d",&x);
    if( isEven(x) ) printf("This is an even number\n");
    else printf("This is an odd number\n");
    return 0;
    }
    int isEven(int x){
    if( x % 2 == 0 ) return 1;
    else return 0;
    }
答案&解析

ACD【解析】

  • 代码编译是从前往后编译的,main 中调用的自定义函数需要提前定义函数体(如选项 A )或 事先声明函数的返回值、函数名、参数表(如选项C、D),函数声明时可以舍去参数名(如选项 D),但必须保留参数类型和正确的传参顺序
  • C 语言中不是特别强调函数及变量的定义( definition )与声明( declaration ),但最好自我查询并理解二者的区别

    1. 下列有关变量的生存周期和作用域的说法正确的有[多选]

    ( )

    A. 全局变量的生存周期从程序执行开始到程序运行结束,且可以被所在文件中的所有函数访问到

    B. 自定义函数传入的形参只在函数被调用的过程中存在

    C. 在本层作用域中定义变量时,不可选用外层作用域中出现过的变量名

    D. 下列代码可正常编译

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>
    int main(){
    int a;
    scanf("%d",&a);
    switch (a){
    case 1:
    printf("a euqals 1");
    int b = a;
    break;
    case 2:
    printf("a equals 2");
    int b = a;
    break;
    default:
    printf("none of 1 or 2");
    break;
    }
    return 0;
    }
答案&解析

AB【解析】

C. 可以选择外层出现过的变量名。在本层中,定义的变量名会覆盖外层的同名变量,且不会对外层变量产生影响。但是,理论是理论,实践中写代码极其不推荐这么干,不然自己都搞不清。

D. 编译不会通过,是因为本质上两次int b = a;都是在同一作用域中,会出现重复定义的错误。其实以后你们还会遇到许多在 switch 语句中定义变量报错的情况,实在解决不了,就改用if...else if...


    1. 下列关于数组的说法正确的有[多选]

    ( )

    A. 遍历一个长度为 10 的数组 a[10],可以 for(int i = 0; i <= 10; i++) // do something

    B. 定义一个数组时必须指明数组的长度,定义之后数组长度无法改变

    C. c99 标准以后,变量可以作为数组长度用来定义一个数组

    D. 数组作为参数传入自定义函数中,函数内对数组的操作也会影响到函数外部的数组

答案&解析

BCD【解析】

A. 新手常犯的错误, for(int i = 0; i <= 10; i++) // do something 这样实际上循环了 11 次,会出现数组越界,应该把 <=改成<

C. 虽然是对的,但是不建议用变量作为数组长度

D. 学习到指针之后,大家会了解到数组的本质,就可以理解了

是不是不会做?不会做就对了!如果你能把 quiz2 的知识完全掌握,说保守一点,你在开学时就把大概90%的同学甩在身后了。如果不会做也没关系,慢慢学习就可以了,让一年前的我做这些题,我根本无从下手(QAQ)。quiz2 不需要正确率有多高,只要看完答案解析能够大致懂一点就可以了。

quiz1 和 quiz2 虽然都是选填题,但是其中出现了好多你们以后会写出来的 bug ,如果以后 debug 实在 de 不出来,不妨翻翻这两个 quiz ,说不定会有思路。暑期的程设预习就帮助到这里了,希望大家开学以后天天 AC 没有 WA 、TLE、MLE … 捏。