目录
前言
🎒选择题【全面深度剖析】
📗考点一:无符号数unsigned的理解与应用
📕考点二:字符ASCII计算与转换的理解和应用
📙考点三:对位操作符的理解与应用
📘考点四:结构体对齐的原则与应用
📒考点五:while判断条件的理解的和应用
📗考点六:整形在内存中的存储
📕考点七:指针数组的理解和应用
📙考点八:递归与判断条件的理解与应用
📒考点九:二维数组的理解与应用
📘考点十:位操作符的理解与计算
📗考点十一:宏定义的理解
📕考点十二:指针的概念及理解
📙考点十三:宏替换的理解与运算
📒考点十四:源文件各个阶段的理解
📗考点十五:整形提升的计算
📖编程题【全面深度解析】
🏷️[编程题]Fibonacci数列
🏷️[编程题]替换空格
前言
同学们,C语言学习之路已经结束😚~相信大家都想在接下来的学习中偷偷地卷”死“同学吧😇大学里可以做的事情有很多哦,我们一定要好好地利用好这段时间,努力地提升自己,大胆放手一搏吧!✊
只要我们以深深地谦卑去忍耐 “暗无天日” 的日子,定会迎来属于我们豁然开朗地一刻!让我们一起为心中所想,去奋斗吧!!
🎒选择题【全面深度剖析】
📗考点一:无符号数unsigned的理解与应用
请问该程序的输出是多少( )
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
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.172 D.173
🙈大家觉得答案是什么呢
🙉答案是 D 啦~
💡本题的解题关键:
- 清楚无符号char(unsigned char)的取值范围,并且无符号数是没有负数
➡️回到题目:这个代码的结果是只有i == 0 的时候,循环才能停止
➡️ 让我们一起来解题吧~
🈵无符号char(unsigned char)的取值范围:0~255
1️⃣开始执行for循环:i = 7 ——> i = 4 ——> i = 1 继续循环,此时已经循环3次
2️⃣对于一个无符号数是不会出现负数的(本来下一个循环 i = -2),从而使得下一个 i = 254(char的字节为8个,存进i的补码是11111110
——>即为254)————254/3=84余2,则一共循环85次;
3️⃣下一次循环(i = -1)由于为无符号,则下一次i = 255(255 / 3 = 85)
👉综上:
一共循环3+85+85=173
✨这也就是这题为什么选D啦~
📕考点二:字符ASCII计算与转换的理解和应用
以下程序运行时,若输入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");
}
A .1abcedf2df B.1ABCEDF2DF C.1AbCeDf2dF D.1abceDF2DF
👉同学们做这些题目的时候一定要仔细哦~
🙈同学们觉得答案是什么呢
🙉答案是 C 啦~
💡本题的解题关键:
- 理解大小写字母所对应的
ASCII
值的转换
❗特别注意:
十进制 | 八进制 | 十六进制 | 二进制 | 字符 |
---|---|---|---|---|
65 | 101 | 41 | 01000001 | A |
97 | 141 | 61 | 01100001 | a |
-
⬆️由上表中可得知:大小写字母所对应的
ASCII
的差值为32
- 即
'a' - 'A' = 32
- 即
➡️ 让我们一起来解题吧~
📍经过上述的理解,我们便可得知:由大写字母转换为小写字母需要在原有ASCII
上加32
(
小
写字母转换为大写字母需要在原有ASCII
上减32
)
1️⃣当a=0;ch=1,判断if语句不满足条件,出循环,输出1,且a=1
2️⃣当a=1;ch=a;进入循环,a—>A。
3️⃣我们发现转变字符是跳着读的:同理b不变,c转变成C,以此类推算出来的答案是:1AbCeDf2dF
👉综上:
➡️循环本质上:就是在奇数位的时候想让小写字母转换为大写字母
✨这也就是为什么这道题选 C 啦~
📙考点三:对位操作符的理解与应用
以下哪个选项一定可以将 flag 的第二个 bit 置 0 ( )
A.flag&=~2 B.flag|=2 C.flag^=2 D.flag>>=2
🙈大家觉得答案是什么呢
🙉答案是 A 啦~
💡本题的解题关键:
- 灵活运用位操作符的功能
❗特别注意
按位与&:只有对应的两个二进位全1才1,全0为0
按位或|:只要对应的二个二进位有一个为1时,结果位就为1。
按位异或^:两数各对应的二进位相异或,当两对应的二进位相异为1,相同为0
➡️ 让我们一起来解题吧~
想让第二个bit置为0,则需在第二位与0,即可把第二位置为0
👉综上:
✨这也就是为什么这道题选 A啦~
📘考点四:结构体对齐的原则与应用
下面两个结构体
struct One {
double d;
char c;
int i;
};
struct Two {
char c;
double d;
int i;
};
在 #pragma pack(4) 和 #pragma pack(8) 的情况下,结构体的大小分别是( )?
A 16 24,16 24 B 16 20,16 20 C 16 16,16 24 D 16 16,24 24
🙈大家觉得答案是什么呢
🙉答案是 C 啦~
💡本题的解题关键:
- 结构体对齐原则不要忘记(很重要!!!)
❗特别注意
首先得掌握结构体的对齐规则:
1. 结构体的第一个成员直接对齐到相对于结构体变量起始位置为0的偏移处。
2. 从第二个成员开始,要对齐到某个对齐数的整数倍的偏移处 对齐数 :结构体成员自身大小和默认对齐数的较小值VS:8Linux环境默认不设置对齐数(对齐数是结构体成员的自身大小)
3. 结构体总大小必须是最大对齐数的整数倍。每个成员变量都有一个对齐数,其中最大的对齐数就是最大对齐数
4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
➡️ 让我们一起来解题吧~
👉在#pragma pack(4)下:(默认对齐数为4)
结构体大小分别为 16 16
👉在#pragma pack(8)下:(默认对齐数为8)
则最大对齐数变为8,与上述分析情况一样
如果还是不懂如何分析结构体大小,📌结构体文章推荐:结构体(结构体内存对齐)
此时结构体大小为 16 24
👉综上:
✨这也就是为什么选 C 啦~
📒考点五:while判断条件的理解的和应用
在上下文和头文件均正常的情况下,以下程序的输出结果是( )
int x = 1;
do {
printf("%2d\n", x++);
} while (x--);
A. 1 B.无任何输出 C. 2 D.陷入死循环
🙈大家觉得答案是什么呢
🙉答案是 D 啦~
💡本题的解题关键:
- do{ }while()循环------------先循环,后判断
- 会用前置++:先++后使用
- 后置++:先使用后++
特别注意:
- 本题的循环判断条件为
x
的返回值(先判断x后--)
➡️回到题目:
💥首先x=1进入循环得到x=2;再使用while条件判断(x=2为真),执行x--得到x=1,继续进入循环最终陷入死循环。
✨这也就是为什么选 D
啦~
📗考点六:整形在内存中的存储
下列 C 程序执行后 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
🙈大家觉得答案是什么呢
🙉答案是 A 啦~
💡本题的解题关键:
- 整形在内存中的存储是以补码的形式存储
❗特别注意
💬正数的原、反、补码相同;负数的补码为:原码取反(符号位不变)+1
➡️回到题目:
👉综上:
整形在内存中使用时,必须用补码计算,计算完成之后还要把补码变为原码
✨这也就是为什么选 A
啦~
📕考点七:指针数组的理解和应用
设有定义char *p[]={"Shanghai","Beijing","Honkong"};则结果为j字符的表达式是()
A *p[1] +3 B *(p[1] +3) C *(p[3] +1) D p[3] [1]
🙈大家觉得答案是什么呢
🙉答案是 B 啦~
💡本题的解题关键:
- 对指针数组的解引用
➡️回到题目:
此数组如图所示:
🉐p数组有三个元素,里放的都是首字符的地址:S 、 H、 B
A选项:*p[1]+3 可以理解为找到了B的地址解引用再加3=E;
B选项:*(p[1] +3)可以理解为先找到了B的地址再+3再解引用;+1指向e;+2指向i;+3指向j。
C和D的p[ 3 ]都已经超过了p数组,不存在,所排除。
✨这也就是为什么选 B
啦~
📙考点八:递归与判断条件的理解与应用
int f(int x) {
return ((x > 2) ? x * f(x - 1) : 3);
}
int i;
i = f(f(2));
执行如上函数后. i的值为()
A 30 B 无限递归 C 9 D 2160
🙈大家觉得答案是什么呢
🙉答案是 C 啦~
💡本题的解题关键:
- 对递归函数的计算
➡️回到题目:
1️⃣f(2)-----------进入函数,则x=2,通过判断得出返回3;
2️⃣f(3)-----------x=3,通过判断返回x*f(x-1),此时的f(x-1)为f(2)
💯f(f(2)) = 3 * 3 = 9
✨这也就是为什么选 C
啦~
📒考点九:二维数组的理解与应用
在int p[][4] = { {1},{3,2},{4,5,6},{0} }; 中,p[1][2]的值是( )
A 1 B 0 C 6 D 2
🙈大家觉得答案是什么呢
🙉答案是 B 啦~
💡本题的解题关键:
- 本题为一个简单题,要清楚二维数组元素存放的位置
- 对于一个二维数组,行数可以省略,但列数绝对不可以省略。
➡️回到题目:
💯此时的二维数组存放的位置
✨这也就是为什么选 B
啦~
📘考点十:位操作符的理解与计算
int fun(int a) {
a ^= (1 << 5) - 1;
return a;
}
fun(21)的运行结果是( )
A 10 B 5 C 3 D 8
🙈大家觉得答案是什么呢
🙉答案是 A 啦~
💡本题的解题关键:
- 对位操作符号要能知道其性质
- 异或等(^=):赋值操作符(赋值操作符的优先级很低)
- 左移操作符(<<):左边抛弃、右边补0
➡️回到题目:
这个代码的关键在于(1<<5)
➡️ 让我们一起来解题吧~
💯异或(^):相同为0,不同为1
✨这也就是为什么选 A
啦~
📗考点十一:宏定义的理解
下列关于C / C++的宏定义,不正确的是( )
A 宏定义不检查参数正确性,会有安全隐患
B 宏定义的常量更容易理解,如果可以使用宏定义常量的话,要避免使用const常量
C 宏的嵌套定义过多会影响程序的可读性,而且很容易出错
D 相对于函数调用,宏定义可以提高程序的运行效率
🙈大家觉得答案是什么呢
🙉答案是 B 啦~
💡本题的解题关键:
- 在C中const修饰的是常量,而在C++中const修饰的是常变量
➡️ 让我们一起来解题吧~
C语言中num是常变量,C++中的num是常量,而且const 修饰的num是有类型的,有类型检查;宏没有类型检查,所以不够严格。
✨这也就是为什么选 B
啦~
📕考点十二:指针的概念及理解
下面关于"指针"的描述不正确的是( )
A 当使用free释放掉一个指针内容后, 指针变量的值被置为NULL
B 32位系统下任何类型指针的长度都是4个字节
C 指针的数据类型声明的是指针实际指向内容的数据类型
D 野指针是指向未分配或者已经释放的内存地址
🙈大家觉得答案是什么呢
🙉答案是 A 啦~
➡️ 让我们一起来解题吧~
free释放掉的指针,free不会将它置为空,我们要主动将它置为空指针
。
📙考点十三:宏替换的理解与运算
设有以下宏定义:
#define N 3+1
#define Y(n) ((N+1)*n)
则执行语句 z = 2 * ( N + Y(5 + 1) )后, z 的值为
A 60 B 190 C 248 D 其他都错
🙈大家觉得答案是什么呢
🙉答案是 A 啦~
💡本题的解题关键:
- 对宏替换的简单理解,替换原则:直接替换
- 如有不理解,可以参考✅宏定义及替换规则
➡️ 让我们一起来解题吧~
💯直接替换:N=3+1 Y(n) = ((N+1)*n)
1️⃣z = 2 * ( 3+1 + Y(5 + 1) ) ; Y(n) (( 3+1+1)*n)
2️⃣Y(n) = (( 3+1+1)*5 + 1) =26; z=2*(3+1+26)=60
📒考点十四:源文件各个阶段的理解
由多个源文件组成的C程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序。下面哪个阶段可以发现被调用的函数未定义?
A 预处理 B 编译 C 链接 D 执行
🙈大家觉得答案是什么呢
🙉答案是 C 啦~
➡️ 让我们一起来解题吧~
编辑:也就是编写C/C++程序。
预处理:相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。
编译:将预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。
链接:通过链接器将一个个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。 链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够***作系统装入执行的统一整体。在此过程中会发现被调用的函数未被定义。
📗考点十五:整形提升的计算
char a ; int b ; float c ; double d ;
则表达式 a* b + d - c 值的类型为()
A float B int C char D double
🙈大家觉得答案是什么呢
🙉答案是 D 啦~
➡️ 让我们一起来解题吧~
📖编程题【全面深度解析】
🏷️[编程题]Fibonacci数列
1、Fibonacci数列是这样定义的:
F[0] = 0 F[1] = 1 for each i ≥ 2: F[i] = F[i-1] + F[i-2]
因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ...,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。
输入描述:
输入为一个正整数N(1 ≤ N ≤ 1,000,000)
输出描述:
输出一个最小的步数变为Fibonacci数"
示例1:
输入:15
输出:2
🔍题目传送门:OJ链接
#include <stdio.h>
#include <math.h>
//库函数 abs()
int main()
{
int n = 0;
scanf("%d", &n);
int f1 = 0;
int f2 = 1;
int f3 = f1 + f2;
while (n)
{
if (n == f2)//输入的数等于右边的数
{
printf("0\n");
break;
}
else if (n < f2)//输入的数小于右边的数
{
if (abs(f1 - n) < abs(f2 - n))
{
printf("%d\n", abs(f1 - n));
}
else
{
printf("%d\n", abs(f2 - n));
}
break;
}
//如果输入的数大于右边的数,向右再计算一组,直到满足前两个条件中的其一个条件即可
f1 = f2;
f2 = f3;
f3 = f1 + f2;
}
return 0;
}
🏷️[编程题]替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
🔍题目传送门:OJ链接
🐸这道题目是源自身边的,并非凭空捏造
🔥因为搜索字符串,字符串是不能空开的,所以必须要把空格替换掉(空格的ASCII码值是20)。在搜索引擎我们可以发现👇🏻
💡解题关键:
➡️思路:
1.str指向的是要处理的字符串,length是要处理的字符串的长度
2.空格一个要替换成%20 三个字符;意味中are happy要整体后移,空出来两个空格,用来放下%20;同理happy也要整体后移两个位置,以放下%20。
3.一个空格要换成三个字符,两个空格替换,意味着字符串长了4个字符
4.设定end1和end2; 分别指向length-1和new length-1字符串的最后一位
5.遍历一遍str 遇到空格就spacecent ++;
6.while 循环end1不等于end2,则把end1的值赋予end2;end1–;end2–;
7.如果str[end1]等于空格则把空格替换成%20;end1–;
8.直到end1=end2,循环终止;
class Solution {
public:
void replaceSpace(char* str, int length) {
//统计空格的个数
int space_count = 0;
char* cur = str;
while (*cur)
{
if (*cur == ' ')
{
space_count++;
}
cur++;
}
//计算末尾位置end1,end2
char* end1 = str + length - 1;
char* end2 = str + length - 1 + 2 * space_count;
while (end1 != end2)
{
if (*end1 != ' ')
{
*end2-- = *end1--;
}
else
{
*end2-- = '0';
*end2-- = '2';
*end2-- = '%';
end1--;
}
}
}
};