可以在编辑命令中使用-D选项指定宏名称所代表的的数字
1#include<stdio.h>
2int main(){
3 int radius=0;
4 printf("请输入半径:");
5 scanf("%d",&radius);
6 printf("周长是%g\n",2*PI*radius);
7 return 0;
8 }
gcc -DPI=3.14f 1.c ./a.out 执行
复习彩票:
1#include<stdio.h>
2#include<time.h>
3#define SIZE 10
4#define MAX 36
5int main(){
6 int arr[SIZE]={0};
7 int tmp=0,num=0;
8 srand(time(0));
9 do{
10 arr[tmp]=rand()%MAX+1;
11 for(num=0;num<=tmp-1;num++){
12 if(arr[num]==arr[tmp]){
13 break;
14 }
15 }
16 if(num==tmp){
17 tmp++;
18 }
19 }while(tmp<SIZE);
20 for(num=0;num<=SIZE-1;num++){
21 printf("%d ",arr[num]);
22 }
23 return 0;
24 }
如果程序中某些数字只有编译时才需赋值,就用宏代表它们
宏可以用来定义计算公式
计算公式中包含未知数字,可以使用宏的参数表示这些未知数字
1#include<stdio.h>
2#define PI 3.14f
3#define CIRCLE(r) 2*PI*r
4int main(){
5 int radius=0;
6 printf("请输入半径");
7 scanf("%d",&radius);
8 printf("周长是%g\n",CIRCLE(radius));
9 return 0;
10 }
宏的参数不可以有类型名称,宏的参数不一定只代表数字
如果有多个宏参数需要用逗号把它们分开
编译器采用二次替换的方式处理带参数的宏
宏不可以使用自己的存储区和函数进行数据传递
宏没有形式参数,也没有返回值
宏的参数代表函数的存储区
能当作数字使用的宏必须写成表达式,因为宏没有存储区用来存放返回值
计算绝对值:
1#include<stdio.h>
2#define ABS(n) n>=0?n:0-n
3int abs(int num){
4 if(num<0){
5 return -num;
6 }
7 else{
8 return num;
9 }
10 }
11int main(){
12 int num=0;
13 printf("请输入一个数字:");
14 scanf("%d",&num);
15 printf("绝对值是%d\n",abs(num));
16 printf("绝对值是%d\n",ABS(num));
17 return 0;
18 }
计算相反数:
1#include<stdio.h>
2#define NEG(n) -n
3void neg(int *p_num){
4 *p_num=0-*p_num;
5 }
6int main(){
7 int num=0;
8 printf("请输入一个数字:");
9 scanf("%d",&num);
10 neg(&num);
11 printf("相反数是%d\n",num);
12 NEG(num);
13 printf("相反数是%d\n",num);
14 return 0;
15 }
#define S(a,b) a*b
…. area=S(2,3)
练习:用宏计算两个整数的差
1#include<stdio.h>
2#define CHA(a,b) a-b
3int main(){
4 printf("%d\n",CHA(10,5));
5 printf("%d\n",20-CHA(10,5));
6 return 0;
7 }
结果: 5 5 第二个是错的
因为宏没有存储区记录返回值,所以不能保证优先计算宏内部的操作符
宏没有形式参数,不能保证优先计算宏内部的操作符
所有能当做数字使用的宏必须写在一个括号里
1#include<stdio.h>
2#define CHA(x,y) ((a)-(b))
3int main(){
4 printf("%d\n",CHA(10,5));
5 printf("%d\n",20-CHA(10,5));
6 printf("%d\n",CHA(20,10-5));
7 return 0;
8 }
不要把自增或自减的结果作为宏的参数使用
#是一个宏操作符,它可以把宏的参数转换成字符串字面符
1#include<stdio.h>
2#define STR(n) #n
3 int main(){
4 printf("%s\n",STR(2+3));
5 return 0;
6 }
就是将STR的内容n转换成字符串
##也是一个宏操作符,它可以把一个代表标识符的宏参数和其他内容连接得到一个新的标识符
1#include<stdio.h>
2#define LOCAL(n) p_##n
3int main(){
4 int LOCAL(num)=0; 相当于int p_num=0;
5 return 0;
6 }
条件编译
条件编译可以在编译程序的时候从几组语句中选择一组编译而忽略其他组
# ifdef / ifndef …. # else …… # endif
以上结构可以根据宏名称是否被定义过,从两组语句中选择一组编译
宏名必须是标识符,开头是下划线或字母
以上结构最前面的预处理指令应该从两个中选择一个,不论选择哪个,后面都应该写一个宏名称
# ifdef 表示它后面的宏名称被定义过就编译前一组,没有定义过就编译后一组
# ifndef 效果和 # ifdef 刚好相反
1#include<stdio.h>
2#define YI
3int main(){
4#ifdef YI
5 printf("1\n");
6#else
7 printf("2\n");
8#endif
9 return 0;
10 }
执行结果: 1
若没有#define YI 这行语句,则执行结果是2
练习:输入一行字母字符,根据需要输入大写小写。
1#include<stdio.h>
2#define XIAO
3int main(){
4 int i=0;
5 char c=0;
6 char arr[50]={0};
7 printf("请输入一行字母:");
8 gets(arr);
9 while((c=arr[i])!='\0'){
10 i++;
11#ifdef XIAO
12 if(c>='A'&&c<='Z'){
13 c+=32;
14 }
15#else
16 if(c>='a'&&c<='z'){
17 c-=32;
18 }
19#endif
20 printf("%c",c);
21 }
22 printf("\n");
23 return 0;
24 }
工厂店打8折,普通店不打折,精品店打12折
1 #include<stdio.h>
2 #define GONGCHANG
3 int main(){
4 #ifdefined(GONGCHANG) //GONGCHANG
5 printf("80%%\n");
6 #elif!defined(GONGCHANG)&&!defined(JINGPIN) //PUTONG
7 printf("100%%\n");
8 #else //JINGPIN
9 printf("120%%\n");
10 #endif
11 return 0;
12 }
如果用宏定义GONGCHANG 则输出80%
如果不定义 则输出100%
如果用宏定义 JINGPIN 则输出120%
1 #include<stdio.h>
2 #define JINGPIN
3 int main(){
4 #if defined(GONGCHANG)
5 printf("80%%\n");
6 #elif defined(JINGPIN)
7 printf("120%%\n");
8 #elif defined(PUTONG)
9 printf("100%%\n")
10 #endif
11 return 0;
12 }
如果用宏定义GONGCHANG 则输出80%
如果用宏定义 PUTONG 则输出100%
如果用宏定义 JINGPIN 则输出120%
1 #include<stdio.h>
2 #define GONGCHANG 1
3 int main(){
4 #if GONGCHANG
5 printf("80%%\n");
6 #else
7 printf("100%%\n");
8 #endif
9 return 0;
10 }
1为真代表工厂店打折 执行80%
0为假,代表不是工厂店,不打折 执行100%
多文件编程中一个文件里可以包含多个函数,一个函数只能属于一个文件
1. 把所有函数分散在多个不同的源文件里(通常主函数单独占一个文件)
2. 为每个源文件编写配对的以 . h 作为扩展名的头文件(主函数所在的源文件不需要配对头文件)所有不分配内存的内容都可以写在头文件里,头文件里至少包含源文件中所有函数的声明
3. 修改所有源文件包含必要头文件。(配对的头文件是必要头文件,如果头文件里声明了源文件所使用的函数,则这个头文件也是必要头文件)
可以在gcc命令后列出所有源文件名称,用这种方法可以编译多文件程序
方法1:
1. 编写main.c
1#include<stdio.h>
2#include"add.h"
3int main(){
4 int num=add(3,8);
5 printf("num是%d\n",num);
6 return 0;
7 }
2. 编写add.c
1#include"add.h"
2int add(int num,int num1){
3 return num+num1;
4 }
3. 编写add.h
1 int add(int,int);
执行命令 gcc main.c add.c ./a.out
结果是num 是11
可以把多文件程序编译过程记录到Makefile中,使用make工具按照Makefile的要求进行编译
1 #ifndef __10ADD_H__
2 #define __10ADD_H__
3 int add(int,int);
4 #endif //__10ADD_H__
这样处理作用在于只编译一次头文件
头文件内容应该包含在条件编译的预处理指令中间,这样可以避免多次编译
头文件中第一个预处理指令必须是# ifndef
头文件中使用的宏名称应该根据文件名称变化得到,这样可以避免多个头文件使用同样的宏名称
练习:编写程序从键盘得到一个数字并把它显示在屏幕上
用函数实现获得数字的过程
采用多文件编程方式实现
1.编写main.c
1 #include<stdio.h>
2#include"input.h"
3 int main(){
4 int a=input();
5 printf("输入值是%d\n",a);
6 return 0;
7 }
2.编写 input.c
1 #include<stdio.h>
2#include"input.h"
3 int input(void){
4 int num=0;
5 printf("请输入一个数 ");
6 scanf("%d",&num);
7 return num;
8 }
3.编写 input.h
1 #ifndef __11INPUT_H__
2 #define __11INPUT_H__
3 int input(void);
4 #endif // __11INPUT_H__
如果想在一个源文件里使用另外一个源文件中声明的全局变量,就需要使用extern关键字再次声明这个变量
使用extern关键字声明变量(全局变量)的语句不会分配内存,所以通常被放在头文件里
一个源文件里不能使用另一个源文件里使用的静态变量
例子:从练习中改写,从输入源函数的全局变量中拿数,不能使用返回值
1. 编写 main.c
1 #include<stdio.h>
2 #include"input.h"
3 extern int num; //需要使用input函数里声明的全局变量
4 int main(){
5 input();
6 printf("输入值是%d\n",num);
7 return 0;
8 }
2. 编写 input.c
1#include<stdio.h>
2#include"input.h"
3int num; //初次定义全局变量
4void input(void){
5 printf("请输入一个数 ");
6 scanf("%d",&num);
7 }
3. 编写 input.h
1 #ifndef __INPUT_H__
2 #define __INPUT_H__
3 extern int num;
4 void input(void);
5 #endif // __11INPUT_H__
练习:使用宏进行大小写转换
1 #include<stdio.h>
2 #define CASE(ch) ((ch)>='a'&&(ch)<='z'?(ch)-32:(ch)+32)
3 int main(){
4 char ch=0;
5 printf("请输入一个字符 ");
6 scanf("%c",&ch);
7 printf("转换结果是%c\n",CASE(ch));
8 return 0;
9 }