目录

  • 1 第一章 C语言简介
    • 1.1 C语言前世今生
    • 1.2 主流开发环境介绍
    • 1.3 第一个小程序解析
    • 1.4 常见编译错误
    • 1.5 章节知识点小结
  • 2 算法基础
    • 2.1 算法-程序的灵魂
    • 2.2 算法的描述-流程图
  • 3 数据类型与运算符
    • 3.1 数据描述
    • 3.2 运算符和表达式1
    • 3.3 运算符和表达式2
    • 3.4 章节知识点小结
  • 4 顺序结构程序设计
    • 4.1 输入和输出
    • 4.2 顺序结构程序设计
    • 4.3 章节知识点小结
  • 5 选择结构程序设计
    • 5.1 关系运算符和关系表达式
    • 5.2 逻辑运算符和逻辑表达式
    • 5.3 if语句
    • 5.4 条件运算符
    • 5.5 switch语句
    • 5.6 章节知识点小结
  • 6 循环结构程序设计
    • 6.1 while循环结构
    • 6.2 do_while循环结构
    • 6.3 for循环结构
    • 6.4 循环的嵌套
    • 6.5 break语句和continue语句
    • 6.6 章节知识点小结
  • 7 数组
    • 7.1 一维数组
    • 7.2 二维数组
    • 7.3 字符数组
    • 7.4 章节知识点小结
  • 8 函数
    • 8.1 子程序设计
    • 8.2 函数定义
    • 8.3 函数的调用
    • 8.4 局部变量和全局变量
    • 8.5 参数传递
    • 8.6 函数递归调用
    • 8.7 章节知识点小结
  • 9 指针
    • 9.1 指针的基本概念
    • 9.2 指针变量的定义及引用
    • 9.3 通过指针引用数组元素
    • 9.4 指向多维数组的指针和指针变量
    • 9.5 用指向数组的指针作函数参数
    • 9.6 指针与字符串
    • 9.7 函数指针和指针函数
    • 9.8 章节知识点小结
  • 10 用户自己建立数据类型
    • 10.1 定义和使用结构体变量
    • 10.2 使用结构体数组
    • 10.3 结构体指针
    • 10.4 章节知识点小结
  • 11 编译预处理
    • 11.1 宏定义预处理
    • 11.2 文件包含预处理
    • 11.3 条件编译预处理
    • 11.4 章节知识点小结
  • 12 文件
    • 12.1 文件的基本知识
    • 12.2 文件的基本操作
    • 12.3 章节知识点小结
宏定义预处理

宏定义命令----#define   
      
  使用#define命令并不是真正的定义符号常量,而是定义一个可以替换的宏。被定义为宏的标示符称为“宏名”。在编译预处理过程时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。

在C语言中,宏分为有参数和无参数两种。
 

1.无参数的宏

 

其定义格式如下:

1
#define 宏名  字符串

在以上宏定义语句中,各部分的含义如下:

1
2
3
4
#:表示这是一条预处理命令(凡是以“#”开始的均为预处理命令)。
define:关键字“define”为宏定义命令。
宏名:是一个标示符,必须符合C语言标示符的规定,一般以大写字母标示宏名。
字符串:可以是常数,表达式,格式串等。在前面使用的符号常量的定义就是一个无参数宏定义。

Notice:预处理命令语句后面一般不会添加分号,如果在#define最后有分号,在宏替换时分号也将替换到源代码中去。在宏名和字符串之间可以有任意个空格。

1
#define PI 3.14

它的作用是指定用标识符PI来代替“3.1415926”这个字符串,在编译预处理时,将程序中在该命令以后出现的所有的PI都用“3.1415926”代替。这种方法使用户能以一个简单的名字代替一个长的字符串,因此把这个标识符(名字)称为“宏名”,在预编译时将宏名替换成字符串的过程称为“宏展开”。# define 是宏定义命令。

1.1不带参数的宏定义的应用。

程序代码:

#include<stdio.h>

#define PI3.1415926

main()

{

float l,s,r,v;

printf(“input radius: ”);

scanf(“%f”,&r);

l=2.0*PI*r;

s=PI * r * r;

v=3.0/4 * PI * r * r * r ;

printf(“l=%10.4f\ns=%10.4f\nv=%10.4f\n”,l,s,v);

}

 

在使用宏定义时,还需要注意以下几点:

1
2
3
4
5
6
7
8
9
宏定义是宏名来表示一个字符串,在宏展开时又以该字符串取代宏名。这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。
宏名在源程序中若用引号括起来,则预处理程序不对其作宏替换。
宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层替换。
习惯上宏名可用大写字母表示,以方便与变量区别。但也允许用小写字母。


例1.2不带参数的宏定义的应用。

#include<stdio.h>

# define R 3.0

# define PI3.1415926

# define L 2 * PI * R

# define S PI * R * R

main()

{

    printf(“L=%f\nS=%f\n”,L,S);

}


经过宏展开后,printf函数中的输出项L被展开为2 * 3.1415926 * 3.0S展开为3.1415926 * 3.0 * 3.0printf函数调用语句展开为

printf("l=%f\nS=%f\n",2 *3.1415926 *3.03.1415926 * 3.0 *3.0);



2带参数的宏
 

1
#define命令定义宏时,还可以为宏设置参数。与函数中的参数类似,在宏定于中的参数为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,还要用实参去代换形参。

带参宏定义的一般形式为:

1
#define 宏名(形参表) 字符串  


在定义带参数的宏时,宏名和形参表之间不能有空格出现,否则,就将宏定义成为无参数形式,而导致程序出错。

1
#define ABS(x)  (x)<0?-(x):(x)

 以上的宏定义中,如果x的值小于0,则使用一元运算符(-)对其取负,得到正数。

  带参的宏和带参的函数相似,但其本质是不同的。使用带参宏时,在预处理时将程序源代码替换到相应的位置,编译时得到完整的目标代码,而不进行函数调用,因此程序执行效率要高些。而函数调用只需要编译一次函数,代码量较少,一般情况下,对于简单的功能,可使用宏替换的形式来使用。

2.2带参数的宏定义的应用

程序代码:

# define PI3.1415926

# define S(r)PI * r * r

main()

{

float a,area;

     a=3.6;

     area=S(a);

     printf(“r=%f\narea=%f\n”,a,area);

}

运行结果:

  

赋值语句area=S(a);经宏展开后为

area=3.1415926 * a * a;

说明:

(1) 对带参数的宏的展开只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。例12.3中语句中有S(a),在展开时,找到# define命令行中的S(r),将S(a)中的实参a代替宏定义中的字符串"PI* r * r"中的形参r,得到PI * a * a。这是容易理解而且不会发生什么问题的。但是,如果有以下语句:

area=S(a+b);

这时把实参a+b代替PI * r * r中的形参r,成为

area=PI * a + b * a + b;

请注意在a+b外面没有括号,显然这与程序设计者的原意不符。原意希望得到

area=PI * (a + b) * (a + b);

为了得到这个结果,应当在定义时,在字符串中的形式参数外面加一个括号。即

   # define  S (r)  PI* (r) * (r)

在对S(a+b)进行宏展开时a+b代替r就成了

PI * (a + b) *( a + b);

这就达到了目的。

(2) 宏定义时,在宏名与带参数的括弧之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。例如如果有

    # define S (r) PI * r * r

被认为S是符号常量不带参的宏名),它代表字符串" (r) PI * r * r"。如果有

    area=S (a)

被展开为

    area=(r) PI * r * r (a)

显然不对了。