C语言目录:
1. 概述
2. 数据类型
3. 量
4. 运算符
5. 流程控制
6. 函数
7. C程序编译过程
8. 文件
9. 内存管理
编写代码,保存后生成 hello.c
源文件
# include
int main(int argc, char const *argv[]){
printf("Hello World!");
return 0;
}
C编译器在对源程序进行编译前,会将一些特殊指令作解释(如 #include
),进而产生一个新的源程序,之后再进行通常的编译
所有的预处理指令都以 #
开始,并且结尾不用分号
预处理指令可以出现在程序的任何位置,它的作用范围从它出现的位置到文件尾,所以尽可能将预处理指令写在源程序开头
包括:文件包含、宏定义、条件编译
使用 <>
,仅在系统指定的磁盘路径下搜索所包含的文件
使用 ""
,现在当前工作目录中搜索,若找不到则在系统中寻找
宏 :用来替换重复出现的字符串
宏名:代替该字符串的标识符
宏代换(宏展开):在编译预处理阶段,对程序中出现的所有 宏名
用相应的字符串进行代换,宏代换由预处理程序自动完成
# define 标识符 字符串
字符串可以是常数,表达式,格式串等
约定:宏名一般用大写字母作为标识符,以便与变量名区别开,但用小写也没有语法错误
#include
#define PI 3.14
int main (){
float S = PI * r * r;
printf("%f", S);
return 0;
}
若字符串中出现了某个宏名,不进行替换
#define PI 3.14
char *str = "PIE";//此时不会发生宏代换
宏代换只是简单的 字符串替换 ,不做语法检查。只有编译时才对源程序进行语法检查
宏定义的有效范围是从定义位置开始到文件结束。如果需要终止宏定义的作用域,可以用 #undef
#include
#define PI 3.14
int main (){
#undef PI
float S = PI * r * r; //报错
printf("%f", S);
return 0;
}
宏定义之间可以相互引用
#define R 3.0
#define PI 3.14
#define C 2*PI*R
#define S PI*R*R
可以用宏定义表示数据类型
# define String char*
int main(){
String str = "The String";
return 0;
}
带参数的宏,在调用中,不仅要宏展开,而且要用实参数代替形参
#define 宏名(形参列表) 字符串
# define SUM(a,b) (a+b)
int main(){
int sum = SUM(1,2);
printf("%d\n",sum);
return 0;
}
宏标识符与形参列表之间不能有空格,否则会当被当做普通字符串
# define SUM (a,b) (a+b)
int main(){
int sum = SUM(1,2);//会被替换成 (a,b) (a+b)(1,2)
//编译不通过
printf("%d\n",sum);
return 0;
}
带参数的宏在宏代换时,只作简单的字符和参数的替换,不进行计算操作
宏定义时,要用 ()
将形参字符串括住
# define Twice(a) 2*a
int main(){
int res = D(3+4);// 替换结果为:2*3+4
printf("%d\n",sum);
return 0;
}
# define Twice(a) 2*(a)
int main(){
int res = D(3+4);// 替换结果为:2*(3+4)
printf("%d\n",sum);
return 0;
}
宏定义时,要将计算结果也用 ()
括住
# define Pow(a) (a)*(a)
int main(){
int res = Pow(10)/Pow(2);
//宏代换后:10*10/2*2=100
return 0;
}
# define Pow(a) ((a)*(a))
int main(){
int res = Pow(10)/Pow(2);
//宏代换后:(10*10)/(2*2)=25
return 0;
}
程序中一部分代码在满足一定条件才进行编译,否则不参与编译
优点:按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,有利于程序的移植和调试。生成的目标程序较短
#if 条件1
...
#elseif 条件2
...
#else
...
#endif
#define SCORE 67
#if SCORE > 90
printf("优秀\n");
code 优秀
#elif SCORE > 60
printf("良好\n");
code 良好
#else
printf("不及格\n");
code 不及格
#endif
typedef
typedef 原类型名 新类型名;
原类型名中含有定义部分,新类型名一般用大写表示
typedef
在编译时完成替换
typedef
的使用typedef int Integer;
typedef Integer MyInteger;
int main(){
Integer a;//等价于int a
}
typedef int NAME[20];
NAME a;//等价于 int a[20];
struct Person{
int age;
char *name;
};
typedef struct Person Person;
typedef struct Person{
int age;
char *name;
} Person;
typedef struct {
int age;
char *name;
} Person;
enum Session{
Spring,
Summer,
Autumn,
Winter
};
typedef enum Session Session;
typedef enum Session {
Spring,
Summer,
Autumn,
Winter
}Session;
typedef enum {
Spring,
Summer,
Autumn,
Winter
}Session;
指向结构体的指针
typedef struct {
float x;
float y;
}Point;
typedef Point *PP;
指向函数的指针
int sum(int a, int b) {
int c = a + b;
printf("%d + %d = %d", a, b, c);
return c;
}
typedef int (*Fn)(int, int);
// 定义一个指向sum函数的指针变量p
Fn p = sum;
带参数宏定义与函数形式类似
匹配问题:宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值
执行阶段:函数调用在程序运行时执行,而宏代换只在编译预处理阶段进行
执行效率:带参数的宏比函数具有更高的执行效率
typedef
区别宏定义与
typedef
都可对数据类型进行说明
typedef
在编译时处理,是对类型说明符的重新命名typedef char *String;//给char *起了别名String
int main(){
String str = "This is a String";
return 0;
}
#define String char * //用String对char *进行宏代换
int main(){
String str = "This is a String";
return 0;
}