C语言阶段的题目解析

前言

我们C语言已经学习的差不多了,但是C语言之中存在的一些问题与难点我们还不一定能够又快又好地解决,为了夯实我们的基础,我们来练习几道稍微有点难度的C语言习题吧

例题一

题目

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

题解

在开始解题之前,我们需要知道 unsigned char 类型的取值范围是 0~255

所以 i 的取值不可能是一个负数;

所以跳出循环的条件只有可能是 i=0 ;

我们来画一个图分析一下 unsigned char 类型的变量的取值范围的变化过程:

已知 i 的初始值是7,所以当 i 减到1的时候下一次执行-3操作的时候得到的值是254

因为:254 / 3 = 84……2,此时 i 在减去了84个3之后执行 -3 操作得到的值仍然不是0而是2,所以我们还需要向下执行 -3 操作,此时得到的值是255

因为:255 / 3 = 85 ,此时255是3的倍数在执行了85次 -3 操作以后i的值成功变成了0,此时也就跳出了循环;

所以 j 的值就应该是 2 + 1 + 84 + 1 + 85 = 173 次

例题二

题目

以下那个选项一定可以将flag的第二个bit位置0?

A.flag &=~2

B.flag |= 2

C.flag ^= 2

D.flag >>= 2

题解

我们发现:原题目中与flag执行操作的数都是2

因为2是一个正数,所以2的原码就是补码

所以2的二进制补码为:

00000010

而2的反码就是:

11111101

我们直接带入一个特殊的值就可以解决问题:

假设我们有一个二进制的数:

11111111

假设我们要把第二个bit位置为0,我们必须要保证与这个二进制数按位与(&)的二进制数的第二个bit位必须是0

而且其它位上的值不能改变,所以除了第二个bit位,其它位置上的数都必须是1

此时这个二进制数为:

11111101

这个二进制数的二进制形式刚好符合2的反码,所以我们知道这个题目选 A

题目三

题目

struct One
{
	double d;
	char c;
	int i;
};

struct Two
{
	char c;
	double d;
	int i;
};

计算在#pragma pack(4)和#pragma pack(8)的情况下,结构体大小分别是?

题解

该题目只需要把图画出来,就可以很轻松的解决问题

由图片可以知道:

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

16                16                16                24

例题四

题目

在上下文和头文件均正常的情况下,下列程序的输出结果是:

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

A.1

B.无任何输出

C.2

D.陷入死循环

题解

因为题目中打印的是x++,x++是先使用后+1,所以我们就可以知道先打印出的值是1打印完成以后,x执行++操作变成了2

接着我们进入while循环之中的判断,此时条件是x--,因为x是先使用后--,所以判断时x的值是2,而判断完以后x执行--操作变成了1

我们通过分析知道了,x的取值会一直在1和2之中跳动,所以循环永远不会结束

故选:D

例题五

题目

下列程序执行后c输出的结果为?(32位)

void 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 的原码、反码、补码

-3 的原码:10000000000000000000000000000011

10000000000000000000000000000011

-3 的补码:11111111111111111111111111111101

11111111111111111111111111111101

2的补码:0000000000000000000000000000010

00000000000000000000000000000010

c的二进制序列:11111111111111111111111111111111

11111111111111111111111111111111

c的补码:10000000000000000000000000000001

10000000000000000000000000000001

此时打印出来的值就是-1

所以答案选:A

例题6

题目

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

fun(21)的运行结果是?

A.10

B.5

C.3

D.8

题解

我们知道,1的补码是:

00000001

所以1向左移动5位之后为:

00100000

该二进制位-1得到的是:

00011111

因为我们传入的参数a是21,所以我们应该用21去异或这个值:

00010101
00011111

此时得到的二进制序列为:

00001010

所以打印出来的值是:10

故答案是:A

例题7

题目

下列关于C/C++的宏定义,不正确的是?

A.宏定义不检查函数正确性,会有安全隐患

B.宏定义的常量更容易理解,如果可以使用宏定义常量的话,要避免使用const常量

C.宏的嵌套定义过多会影响程序的可读性,而且很容易出错

D.相对于函数调用,宏定义可以提高程序的运行效率

题解

A、C、D三个选项正确

我们知道,定义一个常量有两种方法:

#define M 10
const int m = 10;

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

C++中const修饰的对象就是一个常量

所以在C++中能使用const定义常量就尽量使用const修饰常量,C语言中则相反

所以答案是:B

例题8

题目

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

执行 z=2*(N+Y(5+1)) 后,z的值为?

A.60

B.190

C.248

D.上述答案都不对

题解

在解决这个问题的时候,我们需要注意:不能提前把N的值和表达式的值计算出来,需要将表达式整体代入,然后按照运算的先后顺序进行运算

此时z可以转化为:z = 2 * (3+1+( (5)*5 +1)

这样计算出来的值就是60

所以答案就是:D

例题9

题目

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

则表达式 a * b + d - c 的值的类型是?

A.float

B.int

C.char

D.double

题解

我们知道:a是char类型的,b是int类型的;

所以在计算的时候,char类型的a需要整型提升为int类型

int类型的值乘一个int类型的值结果也是一个int类型的值

当a*b得到的int类型的值与double类型的d计算的时候:

int类型的值会被强制算术转换为double类型的值;

所以a*b+d得到的值就是double类型的值;

同理,float类型的c在与double类型的值计算的时候也会算术转换为double类型的值

所以 a*b+d-c 的值就是double类型的

所以答案选:D

编程题1:

题目

对于一个较大的整数N(1<=N<=2,000,000,000)

比如说489275936,我们常常需要一位一位的数这个数是几位数,但是如果在这个数每三位加上一个“,”,它就会更加易于朗读:489,275,936

请写出一个程序来完成这个内容

题解

我们先来分析一下:(以12345为例子)

1.我们需要采取从右往左处理的顺序,因为如果使用从左往右处理的顺序还需要判断

2.因为我们采取的是从右往左处理的顺序,所以我们需要先提取出数的最后一位5

我们知道,对数采取 %10可以提取出最后一个位的数字,对一个数采取 /10 操作可以去掉最后一个位上面的数字

一直采取 %10 和 /10 操作,最后n的取值就会变成0

3.当我们每次处理完3个数字的时候就加上一个“,”

4.我们可以把提取出来的数放到一个字符数组里面去,当n=0跳出循环的时候再倒着打印数组里面的内容

5.我们每次%10之后的取值是数字5,因为数组是字符数组,此时我们只需要给数字5加上一个'0',就可以变成字符'5'

6.每放三位,就添加一个“,”,此时我们需要定义一个变量k,用来判断是否处理到了3个数。注意:k == 0的时候 %3 也是0,要排除这个情况

7.当我们处理完数组的时候,此时i指向数组最后一个元素的下一个元素所以我们还要加入一个i--操作,让它指向数组里面的最后一个元素

有了这些思路,我们就可以很轻松的写出代码:

int main(void)
{
	char arr[20] = { 0 };
	int N = 0;
	scanf("%d", &N);
	int k = 0;
	int i = 0;
	while (N)
	{
		if (k != 0 && k % 3 == 0)
		{
			arr[i++] = ',';
		}
		arr[i++] = N % 10 + '0';
		N = N / 10;
		k++;
	}
	for (i--; i >= 0; i--)
	{
		printf("%c", arr[i]);
	}
	return 0;
}

编程题2

题目

题解

我们先来分析一下:

1.再输入字符串的时候最好不使用scanf函数,因为scanf函数在遇到空格的时候就不会再往后读取了,此时我们需要用到gets函数

2.我们需要逐步判断arr2字符数组里面的每一个元素,如果arr1数组里面有这个元素,就把它删除

   思路一:在删除完一个元素以后,我们要把这个元素以后的所有元素全部往前挪

   思路二:我们遍历arr1数组,看arr1数组里面的每个元素在不在arr2数组中存在,如果在arr2数组中存在,就不打印出来,反之则打印

(因为思路二的效率更高,所以我们采用思路二)

3.当arr1数组遍历到 \0 的时候,跳出循环

有了这些理论基础,我们就可以写出代码如下:

int is_exist(char ch, char arr[])
{
	int i = 0;
	while (arr[i])
	{
		if (ch == arr[i])
		{
			return 1;
		}
		i++;
	}
	return 0;
}


int main(void)
{
	char arr1[200] = { 0 };
	char arr2[200] = { 0 };
	gets(arr1);
	gets(arr2);

	int i = 0;
	while (arr1[i])
	{
		if(is_exist(arr1[i], arr2) == 0)
		{
			printf("%c", arr1[i]);
		}
		i++;
	}
	return 0;
}

上述代码中的is_exist其实可以用库函数实现,库函数中有一个函数叫做strchr

如果出现了某个字符,就返回这个字符的地址,如果没有出现这个字符,就会返回NULL

strchr的头文件是<string.h>

所以此时我们还有一种写法:

#include <stdio.h>
#include <string.h>
int main(void)
{
	char arr1[200] = { 0 };
	char arr2[200] = { 0 };
	gets(arr1);
	gets(arr2);

	int i = 0;
	while (arr1[i])
	{
		if(strchr(arr2, arr1[i]) == NULL)
		{
			printf("%c", arr1[i]);
		}
		i++;
	}
	return 0;
}

如果此时我们使用scanf也可以实现,只不过格式有点复杂:

int main(void)
{
	char arr1[200] = { 0 };
	char arr2[200] = { 0 };
	scanf("%[^\n]s", arr1);
	getchar();
	scanf("%[^\n]s", arr2);

	int i = 0;
	while (arr1[i])
	{
		if(strchr(arr2, arr1[i]) == NULL)
		{
			printf("%c", arr1[i]);
		}
		i++;
	}
	return 0;
}

此时需要用getchar清除缓冲区,会比较复杂,难以理解,所以不建议使用

结尾

本节我们练习了9个选择题和2个编程题,有助于我们夯实C语言的基础,查漏补缺,那么本节的内容就到此结束了,希望可以给您带来帮助,谢谢您的浏览!!!

  • 41
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值