1. 常量(Constant)
2. 幻数
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char *argv[]) {
printf("area = %f\n", 3.14159*5.3*5.3);
printf("circumference = %f\n", 2*3.14159*5.3);
return 0;
}
在程序中直接使用的常数,称为幻数(Magic Number)
问题1:使用幻数存在什么问题?
回答1:
- 程序的可读性变差
- 容易发生书写错误,产生不一致性
- 当常数需要改变时,要修改所有引用它的代码,繁琐,还可能有遗漏
问题2:良好的程序设计风格建议把幻数定义为符号常量或者const常量的优点?
回答2: - 减少重复书写常数的工作量
- 提高程序的可读性和可维护性
3. 符号常量
符号常量通俗地讲就是“替换”,即用一个标识符来替代常量,又称为“宏定义”或者“宏替换”。
符号常量格式:#define 标识符 常量
例:#define pi 3.14
注意:末尾不加分号
编译预处理命令:在源程序编译之前,先对程序中的编译预处理命令进行处理 然后将处理的结果和源程序一起进行编译,以得到目标代码
预编译时,将程序中出现的宏名全部替换为字符串 ——宏展开,宏替换
由符号常量产生的一些问题:
问题1:宏常量存在的问题是什么?
回答1:
- 没有数据类型,编译器在宏替换时不进行类型检查
- 只进行简单的字符串替换,极易产生意想不到的错误
问题2:能否声明具有某种数据类型的常量呢?
回答2:由此,我们引出const常量。
问题3:const常量与宏常量相比的优点是什么?
回答3:
- const常量有数据类型,编译器能对其进行类型检查
- 某些集成化调试工具可以对const常量进行调试
4. const常量
const常量格式:#define 标识符 常量
例:#define pi 3.14
注意:const double pi=3.14;
5. 符号常量与const常量的比较
程序示例1:
#include <stdio.h>
#include <stdlib.h>
#define pi 3.14
int main(int argc, char *argv[]) {
double r=2;
printf("%.2f\n",pi*r*r);
return 0;
}
输出结果1:
12.56
程序示例2:
#include <stdio.h>
#include <stdlib.h>
const double pi=3.14;
int main(int argc, char *argv[]) {
double r=3;
printf("%.2f\n",2*pi*r);
return 0;
}
输出结果2:
18.84
注意:这两种写法都被称为常量,这是因为它们一旦确定其值后就无法改变。这两种方法都可采用,但推荐const的写法。
6. define除定义常量外,可以定义任何语句或片段
格式:#define 标识符 任何语句或片段
例:#define ADD(a,b) ((a)+(b))
程序示例:
#include <stdio.h>
#include <stdlib.h>
#define ADD(a,b) ((a)+(b))
int main(int argc, char *argv[]) {
int num1 = 3 , num2 = 5;
printf("%d\n",ADD(num1,num2));
return 0;
}
输出结果:
8
问题1:#define ADD(a,b) ((a)+(b))
是否能写成#define ADD(a,b) (a+b)
?
回答1:不能,因为宏定义是直接将对应的部分替换,然后才能进行编译和运行。
程序示例2:
#include <stdio.h>
#include <stdlib.h>
#define CAL(x) (x*2+1)
int main(int argc, char *argv[]) {
int a = 1;
printf("%d\n",CAL(a+1));
return 0;
}
输出结果2:
4
问题2:为什么输出结果不是5?
回答2:这就是宏定义的陷阱,它把替换的部分直接原封不动替换进去。导致CAL(a+1)实际上是(a+1*2+1)也就是1+2+1=4。
总结:尽量不要使用宏定义来做除了定义常量以外的事情,除非给能加的地方都加上括号。