这些都是在面试笔试中常见的,尤其是 static 和 sizeof。
1、#ifdef、#else、#endif 在程序中使用
频率:3星
...
#define DEBUG
int main()
{
...
#ifdef DEBUG
printf(...) //如果前面定义了名为DEBUG的预处理器常量,则在此处输出信息。
#endif
...
}
2、使用 #define 宏定义时需注意的地方
频率:4星
#include<std.h>
#define SQR(x) (x*x)
int main()
{
int a,b=3;
a=SQR(b+2);
printf("a=%d\n",a);
return 0;
}
显然此处SQR(x)是想获得x的二次方。但是由于:
宏定义展开是在预处理时期,也就是在编译之前。
所以此时b并未被赋值,此时的b只是个符号,因此在第7行SQR那一行代码被展开成:
a=(b+2*b+2); //值为11,而不是5的平方。
为了达到原来的目的,将SQR(x)改成:
#define SQR(x) ((x)*(x))
这样第7行成为:
a=((b+2)*(b+2)); //执行后,a=25
3、如何连接宏参数
频率:3星
用#把宏参数变成一个字符串,用##把两个宏参数连接在一起。
#include<stdio.h>
#define STR(s) #s
#define CONS(a,b) (int)(a##e##b)
int main()
{
printf(STR(vck)); //输出字符串vck
printf("\n");
printf("%d\n", CONS(2,3)); //输出2e3,也就是2*10^3=2000
return 0;
}
4、const的使用错误
频率:4星
#include<stdio.h>
int main()
{
const int x=1; //变量x为整型常量,不能改变x的值。如果此处没有给x初始化,那么x就是一个随机数,且仍不能给它再赋值
int b=10;
int c=20;
const int* a1=&b; //a1定义为const int*类型,const在int*左侧,用来修饰指针所指向的变量,即指针指向常量 。
int* const a2=&b; //a2定义为int* const类型,const在int*右侧,用来修饰指针本身,即指针本身为常量。
const int* const a3=&b; //a2定义为const int* const类型,const在int*两侧,指针和指向的内容都不能改变。
x=2; //此处错误。因为变量x为整型常量,不能改变x的值。
a1=&c; //允许。把a1指向c,改变的是指针a1本身
&a1=1; //不允许。指针a1指向的内容是常量,不能改变的。
a2=&c; //不允许。指针a2本身是不能改变的。
*a2=1; //允许。a2指向的内容可以改变。
a3=&c; //不允许
*a3=1; //不允许
return 0;
}
5、说明const和#define的特点及区别
频率:3星
#define
只是用来做文本替换的。在程序进行编译之前,编译器首先会将“#define Pi 3.1415926”以后所有代码中的“PI”全部换成“3.1415926”,然后进行编译。它的生命周期止于编译期,它存在于程序的代码段,在实际程序中它只是一个常数,一个命令中的参数,没有实际的存在。
const常量
存在于程序的数据段,并在堆栈分配了空间。它在程序中实实在在地存在着且可以被调用、传递。
区别:
const常量有数据类型,而宏常量没有数据类型。编译器可以对const常量进行类型安全检查。
6、C++中const有什么作用
1)const用于定义常量;
const定义的常量编译器可以对其进行数据静态类型安全检查。
2)const修饰函数的形参(形式参数);
当输入参数为用户自定义类型和抽象数据类型时,应该将“值传递”改为“const &传递”,可以提高效率。如:
void fun(A a);
void fun(A const &a);
第一个函数效率低。函数体内产生A类型的临时对象用于复制参数a,临时对象的构造、复制、析构过程都将消耗时间。
第二个函数提高了效率,用“引用传递”不需要产生临时对象,节省了临时对象的构造、复制、析构过程消耗的时间。但光引用有可能改变a,所以加const。
3)const修饰类的成员函数(函数定义体)
任何不会修改数据成员的函数都应用const修饰,这样当不小心修改了数据成员或调用了非const成员函数时,编译器都会报错。const修饰类的成员函数形式为:
int GetCount(void) const;