C语言进阶⑩(数据的存储)数据类型_介绍+存储_大小端(知识点+笔试题)(中):https://developer.aliyun.com/article/1513036
4.笔试题
4.1程序的执行结果为( )
#include<stdio.h> int main() { unsigned char a = 200; unsigned char b = 100; unsigned char c = 0; c = a + b; printf("%d %d", a + b, c); return 0; }
A.300 300
B.44 44
C.300 44
D.44 300
解析:
#include<stdio.h> int main() { //二进制可以用计算机转化 unsigned char a = 200; //200的二进制00000000000000000000000011001000 //存的:11001000 unsigned char b = 100; //100的二进制00000000000000000000000001100100 //存的:01100100 unsigned char c = 0; //相加不够int 要整形提升 //00000000000000000000000011001000 + //00000000000000000000000001100100 = //00000000000000000000000100101100 c = a + b; //存到c中c为(后8位)00101100为44 //a+b不存到c中就是00000000000000000000000100101100为300 printf("%d %d", a + b, c); //300 44 return 0; }
4.2在32位大端模式处理器上变量b等于( )
#include<stdio.h> int main() { unsigned int a = 0x1234; unsigned char b = *(unsigned char*)&a; return 0; }
A.0x00
B.0x12
C.0x34
D.0x1234
解析:
#include<stdio.h> int main() { unsigned int a = 0x1234; //int a是4个字节,存的是0x 00 00 12 34 //假设左边是低地址右边是高地址 //大端里存的就是 00 00 12 34 //小端里存的就是 34 12 00 00 unsigned char b = *(unsigned char*)&a; //题目说大端,unsigned char*取出的是第一个字节的地址,为00 选A return 0; }
4.3在屏幕上打印杨辉三角。
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
……
输入n,表示n行
解析:
由于此题要打印整个杨辉三角的数据而非取出某一项,所以不可避免的一定是要填出每一项,没有偷懒的余地,那就老老实实的根据规律填空即可。按照题设的场景,能发现数字规律为:d[i][j] = d[i - 1][j] + d[i - 1][j - 1]。所以只要按照这个方法填表即可。
法一:
#include<stdio.h> void yang_hui_triangle(int n) { int data[30][30] = { 1 }; //第一行直接填好,播下种子 int i = 0, j = 0; for (i = 1; i < n; i++) //从第二行开始填 { data[i][0] = 1; //每行的第一列都没有区别,直接给1,保证不会越界。 for (j = 1; j <= i; j++) //从第二列开始填 { data[i][j] = data[i - 1][j] + data[i - 1][j - 1]; //递推方程 } } for (i = 0; i < n; i++) //填完打印 { for (j = 0; j <= i; j++) { printf("%d ", data[i][j]); } printf("\n"); } } int main() { int n = 0; scanf("%d", &n); yang_hui_triangle(n); return 0; }
法二:
由于在填第n行的杨辉三角时,只跟第n-1行的杨辉三角产生联系,不会跟之前的有联系,
所以没必要保存每一行的杨辉三角,填一行打一行就行了,这样能让空间复杂度从n^2降低到n。
(空间复杂度是数据结构的内容,现在可以先理解为数组开的空间)
但是在填数据的时候不能对之前的数据覆盖,所以需要从后向前填。
而填杨辉三角顺序对结果是没有影响的,所以可以实现。
#include<stdio.h> void yang_hui_triangle(int n) { int data[30] = { 1 }; int i = 0, j = 0; printf("1\n"); //第一行就直接打印了 for (i = 1; i < n; i++) //从第二行开始 { for (j = i; j > 0; j--) //从后向前填,避免上一行的数据在使用前就被覆盖 { data[j] += data[j - 1]; //公式同上,由于变成了一维,公式也变简单了。 } for (j = 0; j <= i; j++) //这一行填完就直接打印了。 { printf("%d ", data[j]); } printf("\n"); } } int main() { int n = 0; scanf("%d", &n); yang_hui_triangle(n); return 0; }
※这种方法虽然降低了空间复杂度,但只能保存最后一行的数据,
不利于反复查询,两个填法各有各的适用场景。就本题而言,改进后的胜出。
4.4代码题猜凶手
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以下为4个嫌疑犯的供词:
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。
直接在代码注释里写解析:
//分析: //k表示凶手(killer),0表示假话,1表示真话 //if k==A,a==0,b==0,c==0,d==1; //if k==B,a==1,b==0,c==0,d==1; //if k==C,a==1,b==1,c==0,d==1; //if k==D,a==1,b==0,c==1,d==0; //所以c是凶手,怎么用代码求出呢? #include<stdio.h> int main() { char k = 0; for (k = 'A';k <= 'D';k++) { //把四句话用表达式表示出来,真为1,假为0 if ((k != 'A') + (k == 'C') + (k == 'D') + (k != 'D') == 3) { printf("%c是凶手\n", k); } } return 0; }
4.5代码题猜名次
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
直接在代码注释里写解析:
//考虑到一共五个人,直接模拟推理有些太难,计算机最擅长的遍历此时就会派上用场, //将每个人从第1到第5来一遍,则一共会产生5 ^ 5种可能性,这个只需要一个5层循环即可搞定。 //但是这样会导致一些不期望出现的结果出现,因为我并没有查重,所以会出现两个人抢名次的情况, //也就是两个人或者更多的人名次相同的情况,例如两个第二,三个第三这样的, //所以即使满足了条件,也要查看一下五个人的名次是否重复, //这个交给一个函数来执行,只要五个人名次并列,那就返回0,否则返回1即可。 //有了这个思路,就能完成以下代码。 //往后面学习还会有更好的方法 #include <stdio.h> int checkData(int* p) { int tmp[7] = { 0 }; //标记表,实际是哈希表的思路。一开始每个元素都是0。 for (int i = 0; i < 5; i++) { if (tmp[p[i]]) //如果这个位置的标记已经是1,则代表重复,直接返回0。 { return 0; } tmp[p[i]] = 1; //如果不是,则给这个位置标记为1。 } return 1; //全部标记完毕也没有出现重复的情况,代表OK。 } int main() { int p[5] = { 0 }; //0 1 2 3 4分别代表A B C D E for (p[0] = 1; p[0] <= 5; p[0]++) { for (p[1] = 1; p[1] <= 5; p[1]++) { for (p[2] = 1; p[2] <= 5; p[2]++) { for (p[3] = 1; p[3] <= 5; p[3]++) { for (p[4] = 1; p[4] <= 5; p[4]++) //五层循环遍历 { //这里是五个人的描述,由于比较表达式只有0和1两个结果, //如果要两个条件有且只有一个为真, //则可以用比较表达式的值总和为1的方式直接判定。 //别忘了还要判定不能并列。 if ( (p[1] == 2) + (p[0] == 3) == 1 && //B第二,我第三 (p[1] == 2) + (p[4] == 4) == 1 && //我第二,E第四 (p[2] == 1) + (p[3] == 2) == 1 && //我第一,D第二 (p[2] == 5) + (p[3] == 3) == 1 && //C最后,我第三 (p[4] == 4) + (p[0] == 1) == 1 && //我第四,A第一 checkData(p) //不能并列 ) { for (int i = 0; i < 5; i++) { printf("%d ", p[i]); } printf("\n"); } } } } } } return 0; }
本章完(留一张关于智力题的图)
本篇完。