寒假作业Day 08
一、选择题
1、下列关于 const 和 #define 定义常量的区别,说法不正确的有( )
A: define宏是在预处理阶段展开。const常量是编译运行阶段使用
B: 宏没有类型,不做任何类型检查,仅仅是展开。const常量有具体的类型,在编译阶段会执行类型检查
C: define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。const常量会在内存中分配(可以是堆中也可以是栈中)
D: const定义和#define定义的常量在程序运行过程中只有一份拷贝
A: define宏是在预处理阶段展开。const常量是编译运行阶段使用
这个说法是不完全正确的。#define宏确实是在预处理阶段展开,但是const常量并不是在编译运行阶段使用,而是在编译阶段就已经确定了其值,并且在运行时是不可变的。所以,A选项中的“编译运行阶段使用”是不准确的。
B: 宏没有类型,不做任何类型检查,仅仅是展开。const常量有具体的类型,在编译阶段会执行类型检查
这个说法是正确的。#define宏只是简单的文本替换,没有类型,也不做类型检查。而const常量是有类型的,并且在编译阶段会进行类型检查。
C: define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。const常量会在内存中分配(可以是堆中也可以是栈中)
这个说法也是正确的。宏在预处理阶段会根据其在代码中的使用次数进行展开,并且不会分配内存。而const常量确实会在内存中分配存储空间,具体是在栈中还是堆中取决于其定义的位置和方式。
D选项说的是:“const定义和#define定义的常量在程序运行过程中只有一份拷贝。” 这个说法中,“const定义在程序运行过程中只有一份拷贝”是正确的,因为const常量在内存中确实有唯一的存储空间。但是,将#define宏与const常量相提并论,并说它们都有一份拷贝是不准确的,因为#define宏只是文本替换,并没有在内存中分配存储空间。
这个宏接收两个参数 x ,y,如果在上述声明之后,你把 Mul(x,y) 置于程序中,预处理器就会⽤下⾯这个表达式替换上⾯的表达式:++x*++y
a+b=3,b+c=5,++(a+b)*++(b+c)=++3 * ++5,即4 *6=24
大家是不是以为是这样的,但实际上,当我们使用编译器编译,我们会发现,最后的答案却为14,这是为什么呢?
其实真正的带入是这样子的:++a + b * ++b + c=2+3 * 3+3=14
对于上述关于预编译和编译的说法,我们可以逐一分析:
A: C语言由源代码生成的各阶段如下,C源程序-编译预处理-编译-优化程序-汇编程序-链接程序-可执行文件
这个说法是正确的。C语言源代码首先经过预处理器处理,包括宏替换、条件编译等;然后经过编译器编译成汇编代码;接着汇编器将汇编代码转换成机器代码;最后链接器将多个目标文件(包括库文件)链接成一个可执行文件。
B: 常见的预编译指令有#include,#define,#if、#else和#endif
这个说法也是正确的。这些确实是C语言中常见的预处理指令。
C: 编译程序可以识别一些特殊的符号,比如__LINE__ ,表示当前行号的整数,这些是在编译阶段处理的
这个说法不完全准确。__LINE__这样的预定义宏是在预处理阶段处理的,而不是编译阶段。预处理阶段会替换这些宏为相应的值(例如当前源代码行号)。
D: #define定义宏,可以多次使用
这个说法是正确的。#define是C语言中的预处理指令,用于定义宏,宏可以在代码中多次使用,并在预处理阶段被替换为其定义的值或表达式。
A: 预处理命令行必须使用分号结尾
这是不正确的。预处理命令行(如#include, #define等)后面不需要分号。分号是在C语言源代码中用来表示语句结束的,而预处理命令行并不是C语言的语句。
B: 凡是以#号开头的行,都被称为编译预处理命令行
这是正确的。在C语言中,任何以#开头的行都被视为预处理指令或预处理命令行。这些行在编译的预处理阶段被处理。
C: 预处理命令行不能出现在程序的最后一行
这是不正确的。预处理命令行可以出现在程序的任何位置,包括最后一行。只要它们是有效的预处理指令,编译器就会在预处理阶段对它们进行处理。
D: 预处理命令行的作用域是到最近的函数结束处
这也是不正确的。预处理命令行的作用域通常是全局的,它们在整个源文件中都有效,而不是仅限于最近的函数结束处。例如,使用#define定义的宏可以在整个源文件中使用,而不仅仅是定义它的那个函数。
在main函数开始执行时,a已经被定义为10,所以在main函数中的第一个printf语句会输出10…。
接下来调用foo函数。在foo函数中,a的原始定义(10)被#undef取消了,然后a被重新定义为50。但是,请注意,#undef和#define指令在foo函数中的修改不会影响到main函数中a的值,因为预处理器指令的修改是全局的,但是它们的修改在预处理阶段就已经确定,并且不会随着函数的调用而改变。
当foo函数返回后,main函数中的第二个printf语句继续执行,此时a的值仍然是10,因为在预处理阶段a的值就已经确定为10了,即使foo函数中进行了重新定义,也不会影响到main函数中a的值。
二、编程题
#include <stdio.h>
int main() {
//首先把1~100000的值都存储到数组里,以便之后使用
int a[100000] = {0};
a[0] = 1;
a[1] = 2;
for (int i = 2; i < 100000; i++) {
a[i] = 2 * a[i - 1] + a[i - 2];//这是数值规律
a[i] %= 32767;//每次都模一个32767防止数值溢出
}
int n = 0;
scanf("%d", &n);
while (n--) {
int k = 0;
scanf("%d", &k);
printf("%d\n", a[k - 1]);//因为数组从0下标开始
}
return 0;
}
方法一:用for循环
#include <stdio.h>
#include<string.h>
int main() {
char arr[1000] = {0};
int count_English = 0;
int count_Space = 0;
int count_Number = 0;
int count_Else = 0;
gets(arr);
int len=strlen(arr);
for(int i=0;i<len;i++) {
if (arr[i] >= 'a' && arr[i]<= 'z' || arr[i] >= 'A' && arr[i] <= 'Z') {
count_English++;
}
else if (arr[i] == ' ') {
count_Space++;
}
else if (arr[i] >= '0' && arr[i] <= '9') {
count_Number++;
}
else {
count_Else++;
}
}
printf("%d\n%d\n%d\n%d\n", count_English, count_Space, count_Number, count_Else);
return 0;
}
方法二:用while循环
#include <stdio.h>
#include<string.h>
int main() {
char arr[1000] = {0};
char* p=arr;
int count_English = 0;
int count_Space = 0;
int count_Number = 0;
int count_Else = 0;
gets(arr);
while(*p) {
if (*p >= 'a' && *p <= 'z' || *p >= 'A' && *p <= 'Z') {
count_English++;
}
else if (*p == ' ') {
count_Space++;
}
else if (*p >= '0' && *p <= '9') {
count_Number++;
}
else {
count_Else++;
}
p++;
}
printf("%d\n%d\n%d\n%d", count_English, count_Space, count_Number, count_Else);
return 0;
}
两者的区别在于一个用指针,一个用数组下标,其实核心方法都是一个样子