【C语言】进阶测试 (呕心沥血式讲解)

 

目录

一:选择题

🔒1.请问该程序输出是多少?

💡解析:

 🔒2.以下程序运行时,若输入1abcedf2df<回车>输出结果是()

💡解析:

🔒3.以下哪个选项一定可以将flag的第二个bit置0()

💡解析:

 4.下面两个结构体,在#pragma pack(4) 和 #pragma pack(8)的情况下,结构体的大小分别是()

💡解析:

5.在上下文和头文件均正常情况下,以下程序的输出结果是()

💡解析:

6.下列C程序执行后c输出结果为() (32位)

💡解析:

7.设有定义char* p[] = {"Shanghai","Beijing","Honkong"};结果 j 字符的表达式是()

💡解析:

8.执行如下函数,i的值为()

💡解析:

 9.在此句中,p[1][2]的值是()

💡解析:

10.fun(21)运行结果是()

💡解析:

11.下列关于C/C++的宏定义,不正确的是()

解析:

 12.下面关于指针的描述不正确的是()

解析:

13. 由多个源文件组成的C程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序,下面哪个阶段可以发现被调用的函数未定义()

解析:

14.有以下宏定义,则执行语句:z = 2*(N+Y(5+1))后,z的值为:()

解析:

15.有如下定义,则表达式a*b+d-c值的类型为()

解析:

二:编程题

1.添加逗号

思路:

2.删除公共字符

思路:

致谢: 


 

一:选择题

🔒1.请问该程序输出是多少?

int main()
{
	unsigned char i = 7;
	int j = 0;
	for (; i > 0; i -= 3)
	{
		++j;
	}
	printf("%d\n", j);
	return 0;
}

A:2                B: 死循环        C:173        D:172

💡解析:

本题考察的是对无符号(unsigned)理解;

字符 i 是无符号的,永远不会小于0;而循环结束的条件是i>0; 终止循环的唯一条件就是 i等于0的情况;

i -=3.  7-4-1 ;当i等于1时,再执行会变成-2;但是由于i是无符号的,所以此时 -2的补码会认为是无符号型,变成一个超大数字;

我们先复习char数据类型范围:

 char和signed类型:-128~+127;

unsigned char类型:0~255;

-2的补码是 11111110 ;这个数当作无符号数看待就是254;

所以此时 i 不是 -2 而是254,再循环-=3;循环了84后 i 等于2;然后又变成-1;

-1的补码就是:11111111;这个数当作无符号数是 255;而255循环-3,循环了85次后变成0;

所以是 7 4  1 254....5 2 255...3 0;

7~1三次,254~5有84次,2一次,255~3 85次;一共173次;选C

 🔒2.以下程序运行时,若输入1abcedf2df<回车>输出结果是()

int main()
{
	char a = 0, ch;
	while ((ch = getchar()) != '\n')
	{
		if (a % 2 != 0 && (ch >= 'a' && ch <= 'z'))
			ch = ch - 'a' + 'A';
		a++;
		putchar(ch);
	}
	printf("\n");
	return 0;
}

 A:1abcedf2df        B:1ABCEDF2DF        C:1AbCeDf2dF        D:1abceDF2DF

💡解析:

本题考察的是字符Ascii码理解

我们先看 ch = ch -'a' + 'A' ; 发现后面其实就是-32;相当于小写转大写了;思路一下明了了

第一次,0%2 等于0;0!=0 条件为假;直接输出1了;后面循环基本是满足if条件就进入,将小写转大写; 选C

🔒3.以下哪个选项一定可以将flag的第二个bit置0()

A:flag &=~2        B:flag |= 2        C:flag ^= 2        D:flag >>2

💡解析:

        本题考查是是对位操作符理解

我们先假设flag二进制为 11111111;

要保证其他位不变,第二位置0;可以按位& 上一个 11111101;

怎么得到这个数呢?我们先看2的二进制为:00000010;是不是将2取反就可以得到此数字,然后将该数字按位&上flag就可以啦!!!

知识点:

1.&: //按位与 :只有两个数的二进制同时为1,结果才为1,否则为0。

&1可以得到该二进制最后一位是0还是1

2. ~           对一个数的二进制按位取反

 🔒4.下面两个结构体,在#pragma pack(4) 和 #pragma pack(8)的情况下,结构体的大小分别是()

#pragma pack(4)	//设置默认对齐值 4
struct One
{
	double d;
	char c;
	int i;
};
struct Two
{
	char c;
	double d;
	int i;
};
#pragma pack() 恢复默认字节对齐方式

#pragma pack(8)	//设置默认对齐值 8
struct One
{
	double d;
	char c;
	int i;
};
struct Two
{
	char c;
	double d;
	int i;
};
#pragma pack() 恢复默认字节对齐方式

A:16 24,16 24        B:16 20,16 20        C:16 16 ,16 24        D:16 16 , 24 24 

💡解析:

本题考察的是内存对齐,结构对齐

知识点1:

#pragma pack(4): 表示原先VS默认的对齐值改为 4;

#pragma pc():        表示回复默认的字节对齐;

知识点2:

结构体的内存对齐:

首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

        对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

        VS中默认的值为8

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍;

所以这里直接画图计算就好啦!!! 选C

🔒5.在上下文和头文件均正常情况下,以下程序的输出结果是()

int main()
{
	int x = 1;
	do {
		printf("%2d\n", x++);
	} while (x--);
	return 0;
}

A: 1        B:无任何输出        C:2        D:陷入死循环

💡解析:

知识点:

%0.2d的意思是输出占2位,若位数不够则补0.

%2d的意思是输出占2位,若位数不够则补空格

主要区别是要用0补位,还是用空格补位。默认右对齐;左对齐加 - 

因为这里1进入后,后++也变成了2;然后while(x--)又变成1;如此往复死循环;选D

🔒6.下列C程序执行后c输出结果为() (32位)

#include<stdio.h>
#include<stdlib.h>
int  main()
{
	int a = -3;
	unsigned int b = 2; 
	long c = a + b;
	printf("%ld\n", c);
}

 A:-1        B:4294967295        C:0x7FFFFFFF        D:0xFFFFFFFF

💡解析:

本题依旧考察的是无符号类型;

-3的补码:11111111111111111111111111111101

2的补码:00000000000000000000000000010

c的补码:111111111111111111111111111111111

按照原码打印:补码->原码:取反加+;

所以为:  10000000000000000000000000001

这个数字当作有符号数看待就是 -1;选A

🔒7.设有定义char* p[] = {"Shanghai","Beijing","Honkong"};结果 j 字符的表达式是()

A:*p[1] + 3        B:*(p[1] + 3)        C:*(p[3] + 1)        D:p[3] [1] 

💡解析:

本题考查的是指针数组

数组下标 0 1 2 分别对应了三个字符串首元素地址;

A:*p[1] 这一步解引用找到的是字符B,然后+3得到acssi码值 为字符E

C和D 直接越界访问了;

B:就是找到首元素地址后+3到了j 位置,解引用就是j啦;选B

🔒8.执行如下函数,i的值为()


int f(int x)
{
	return ((x > 2) ? x * f(x - 1) : 3);
}
int i;
i = f(f(2));

 A 30        B 无限递归        C 9        D 2160

💡解析:

这里考察的是三目操作符

知识点:

考察的是三目运算符,  exp1?exp2:exp3;

exp1为真,执行exp2;

exp1为假,执行exp3;

        C语言规定:0为假,非0为真。
所以 若要求与M等价,则要满足M取0时为假,取非0数值时为真。 

2>2? 2*f(2-1):3   这里return 的是3;

3>2? 3*f(3-1): 3 这里执行 3*f(2) 也就是 3*3 选C

 

 🔒9.在此句中,p[1][2]的值是()

int p[][4] = {{1},{3,2},{4,5,6},{0}}

A 1        B 0        C 6        D 2

💡解析:

本题考查的是二维数组

没有初始化的位置为0;秒杀;选B

 

🔒10.fun(21)运行结果是()

int fun(int a)
{
	a ^= (1 << 5) - 1;
	return a;
}

A 10        B 5        C 3        D 8 

💡解析:

本题考察的是操作符;

21的二进制:00010101

1<<5:1向左移动5位:00010000;

然后-1后:00001111;

异或后:00001010; 这个数为10;选A

 

🔒11.下列关于C/C++的宏定义,不正确的是()

A:宏定义不检查参数正确性,会有安全隐患
B 宏定义的常量更容易理解,如果可以使用宏定义常量的话,要避免使用const常量
c 宏的嵌套定义过多会影响程宁的可读性,而且很容易出错
D相对于函数调用,宏定义可以提高程序的运行效率

💡解析:

因为宏定义的常量,没有类型,不够安全,严谨,

而const定义的具有类型,

C语言中const 修饰的变量叫 常变量

C++ 中 const 修饰的对象 就是 常量!! 选B

 🔒12.下面关于指针的描述不正确的是()

A 当使用free释放掉一个指针内容后,指针变量的值被置为NULL

B 32位系统下任何类型指针的长度都是4个字节

C 指针的数据类型声明的是指针实际指向内容的数据类型

D 野指针是指向未分配或者已经释放的内存地址

💡解析:

考察对free的理解

free释放指针后,并不会主动将指针变量置NULL;需要我们手动置NULL;

🔒13. 由多个源文件组成的C程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序,下面哪个阶段可以发现被调用的函数未定义()

A 预处理        B 编译        C 链接         D 执行

💡解析:

考察的是对 程序编译,翻译环境的理解

预编译阶段:
1.头文件包含

#include 预处理指令

2.define定义的符号替换

#define 预处理指令

3.注释删除

以上这些都是文本操作

编译阶段:
把c语言代码翻译成了汇编代码

1、语法分析

2、词法分析

3、语义分析

4、符号汇总 

汇编阶段:
把汇编指令翻译成了二进制的指令

形成符号表,这样就能够找到源文件外部的符号(只能汇总全局符号)

链接阶段:
1、合并段表

2、符号表的合并和重定位

选C

🔒14.有以下宏定义,则执行语句:z = 2*(N+Y(5+1))后,z的值为:()

#define N 3+1 
#define Y(n) ((N+1)*n)

 A 60         B 190        C 248        D 上述答案都不对

💡解析:

本题考察的是对宏定义的理解

宏定义的值都是直接替换的,所以我们直接数据代入即可;

#define N 3+1
#define Y(n) ((3+1+1)*5+1)则执行语句 z=2*(3+1+((5)*5+1))     等于60

选A

🔒15.有如下定义,则表达式a*b+d-c值的类型为()

char a;
int b;
float c;
double d;

 A float        B int         C char        D double 

💡解析:

考察的是整型提升,算数转换

知识点:

整型提升:

C语言中字节数少于整型字节数的数据类型在进行整型运算时,该类型的数据会被默认转为整型数据。其中,该类型的数据被转化为整型数据的过程就称为整型提升

算数转换:

当字节长度大于 int 类型的数据参与运算时,如果某个操作符的两个操作数是不同类型,其中一个操作数需要按级别(级别低的数据转换为级别高的数据)转换为另一个操作数的类型,这样的转换即为算数转换

        

算数转换的数据级别(由高到低)

long double

double

long float

float

unsigned long int

long int

unsigned int

int

        选D

二:编程题

🔒1.添加逗号

对于一个较大的整数 N(1<=N<=2.000,000,000)比如980364535,我们常常需要一位一位数这个数宁是几位数,但是如果在这 个数宁每三位加一个过号,它会变得更加易于朗读.因此,这个数字加上逗号成如下的模样: 980,364,535请写一个程序帮她完成这件申情

💡思路:

将这个输入进来的数,从低数位开始一个一个放到一个数组中,这个数组是个char类型的,因为要存放’ , ‘,所以每一位数在存放进去之前还要把它转成字符,而数组的长度是14,因为N的取值范围是(1<=N<=2,000,000,000),还要考虑逗号和’ \0 ';因为是每三位就要放一个逗号,所以用一个count来判断是否满足条件,这个判断条件就是count % 3,当这个值为0,证明就够三位了,就要添加逗号;

		int main()
		{
		    int n = 0, i = 0, count = 0;
		    scanf("%d", &n);
		    char arr[14];
		    //当n还不为0的时候循环继续
		    while (n)
		    {
		        //判断是否已经够三位数,并且不能为0
		        if (count != 0 && count % 3 == 0)
		        {
		            arr[i++] = ',';
		        }
		        //将每一位数转成字符再放进数组
		        arr[i++] = n % 10 + '0';
		        count++;
		        n /= 10;
		    }
		    //从后往前打印数组
		    for (--i; i >= 0; i--)
		    {
		        printf("%c", arr[i]);
		    }
		    return 0;
		}

🔒2.删除公共字符

输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。
例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”

💡思路:

先输入两个字符串,这里用gets输入,然后在遍历第一个字符串str1的同时,判断当前str1的字符是否在第二个字符串中出现过,所以每一个str1的字符判断都要遍历一遍str2,如果在str2中找到了这个字符,就不打印这个字符,如果没找到,就打印;

注:这里也可以用 

scanf("%[^\n]s",arr1);    //遇到\n结束
getchar();        //吸收掉\n  避免被下面的scanf吸入而结束输入
scanf("%[\n]s", arr2);    //输入
		int func(char* str, char ch)
		{
		    while (*str)
		    {
		        if (*str == ch)
		        {
		            return 0;
		        }
		        str++;
		    }
		    return 1;
		}
		
		int main()
		{
		    char str1[100];
		    char str2[100];
		    gets(str1);
		    gets(str2);
		
		    int i = 0;
		    while (str1[i])
		    {
		        //在str2中找当前str[i]的字符
		        //找到返回0,不进入if语句,不打印
		        //找不到返回1,进入if语句打印
		        if (func(str2, str1[i]))
		        {
		            printf("%c", str1[i]);
		        }
		        //无论找没找到,i遍历下一个字符
		        i++;
		    }
		    return 0;
		}

❤致谢: 

感谢你看到这里,本篇为博主呕心沥血写下,采取图文并茂,思路讲解,知识点考察和知识点讲解及拓展..保姆式介绍,在解析中,我尽量用白话去解析某些晦涩的知识点;如果你觉得此文对你在C语言综合知识点有帮助,可以点赞为博主后面发更多的博文,感谢!!!

愿我们都是优秀程序员!!。

星光照亮每一位赶路人,我们都是前行者。

 

 

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值