预处理
在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能,是由预处理程序完成的。对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。
预处理指令
指令 | 描述 |
---|---|
#define | 定义宏 |
#include | 包含一个源代码文件 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则返回真 |
#ifndef | 如果宏没有定义,则返回真 |
#if | 如果给定条件为真,则编译下面代码 |
#else | #if 的替代方案 |
#elif | 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码 |
#endif | 结束一个 #if……#else 条件编译块 |
#error | 当遇到标准错误时,输出错误消息 |
#pragma | 使用标准化方法,向编译器发布特殊的命令到编译器中 |
宏定义
用一个标识符来表示一个字符串,称为"宏"。在预编译处理时,将程序中定义的宏名用定义宏名的字符串去替换,称为“宏替换“。宏替换可以是常量也可以是表达式,如果在宏替换后不必加上
;
,若加上会一起替换。宏定义必须定义到函数之外,要终止其作用域后使用#undef
指令。
无参宏定义
定义:
#define 标识符 字符串
例:
#include <stdio.h>
#define N x+x*y
int main()
{
int x = 2, y = 1;
printf("%d",N*N);
//x+x*y*x+x*y=2+2*1*2+2*1=8
return 0;
}
运行结果:
8
如上所示,N是通过字符串进行直接替换,而不是通常意义(x+x*y)*(x+x*y)=16。
有参宏定义
定义:
#define 宏名(形参列表) 字符串
例:
#include <stdio.h>
#define M(x) x>10?1:0
int main()
{
int x = 2;
printf("%d",M(x));
return 0;
}
运行结果:
0
带参宏定义中宏名和形参直接不能有空格出现,形参不分配内存单元,不必做类型定义。宏调用中实参有具体的值去替换形参,必须作类型说明。
文件包含
文件包含命令是把指定的文件插入到命令行的位置取代改命令行,把指定的文件和当前的源程序文件连成一个源文件。
- 使用尖括号表示在包含文件中去查找(包含目录是由用户在设置环境时设置的),不去在源文件目录去查找。
#include <文件名>
- 使用双引号表示首先在当前源文件目录上查找,若未找到才到包含目录上去。
#include "文件名"
条件编译
预处理程序提供了条件编译的功能,按不同的条件去编译不同的程序部分,产生不同的目标代码。
定义:
#条件编译指令 条件
//语句
#else
//语句
#endif
例:
#include <stdio.h>
#define N 1
int main()
{
#ifdef N
int a[N];
#else
int a[1];
#endif // N
a[0] = 1;
printf("%d",a[0]);
return 0;
}
运行结果:
1
指针
指针可以用来表示各种数据结构,通过指针可以很轻松的进行各种中数据操作。
定义
数据类型 *指针变量名;
引用
取地址
int a = 0;
int *p = &a;
指针p保存着a变量的地址,即为0xa950
,通过取值符&
来获得a的地址。
用值
#include<stdio.h>
int main()
{
int a = 0;
int *p = &a;
*p = 1;
printf("p的值为:%p,*&p的值为%d,a的值为:%d",p,*&p,a);
return 0;
}
运行结果:
p的值为:000000000061FE14,*&p的值为000000000061FE14,a的值为:1
通过*
运算符进行取值,与&
相反。
数组指针
在一个数组中,由连续的存储空间组成,数组名就是由数组第一个元素的首地址。
#include<stdio.h>
int main()
{
int a[10];
*a = 1;
printf("%d",a[0]);
return 0;
}
运行结果:
1
所以*a=a[0],a=&a[0],两者相同。可用指针来进行数组的赋值运算,如
*(a++)
。
二维数组
#include<stdio.h>
int main()
{
int a[3][3];
printf("a[0][0]=%d,a=%d\n",&a[0][0],a);
printf("a[0][1]=%d,a[0]+1=%d\n",&a[0][1],*(a)+1/*a[0]+1*/);
printf("a[1][0]=%d,a+1=%d\n",&a[1][0],a+1);
return 0;
}
运行结果:
a[0][0]=6422000,a=6422000
a[0][1]=6422004,a[0]+1=6422004
a[1][0]=6422012,a+1=6422012
多维数组
#include<stdio.h>
int main()
{
int b[3][3] = {1,2,3,4,5,6,7,8,9};
int (*a)[3];
a=b;
printf("%d ",a[0][0]);
printf("%d",a[1][0]);
return 0;
}
运行结果:
1 4
其中
int (*a)[3]
中的括弧不能缺,若不加括号则表示为一个指针数组。其中的a是一个指针变量,代表一个指针变量里有一个一维数组。其中a+i
表示指向了一维数组的首地址,*(a+i)+j则表示二维数组a[i][j]的地址。
字符串指针
#include<stdio.h>
int main()
{
char str[] = "123";
char *s = "556";
/*
char *s;
s = "556";
数组字符串不可通过str="123"来进行赋值操作
*/
printf("str=%s,str[1]=%c\n",str,str[1]);
printf("s=%s,s+1=%c",s,*(s+1));
return 0;
}
运行结果:
str=123,str[1]=2
s=556,s+1=5
通过指针可以更灵活的给字符串进行赋值操作,字符串指针变量本身是一个指针变量用来存储字符串的首地址,在字符串中以’\0’来进行结尾操作,而字符串数组本身由若干元素组成,来进行整个字符串的存储。
函数指针
定义:
数据类型 (*函数指针变量名)(数据类型.....)
#include<stdio.h>
int add(int a,int b){
return a+b;
}
int main()
{
int (*p)(int,int) = add;
printf("%d",(*p)(1,2));
return 0;
}
运行结果:
3
回调函数
回调函数是指函数指针做为一个函数的参数来进行调用。
#include <stdio.h>
int add(int a,int b){
return a+b;
}
int sum(int a,int b,int (*ad)(int,int)){
return (*ad)(a,b);
}
int main()
{
printf("%d",sum(1,2,add));
return 0;
}
运行结果:
3
指针类型
定义 | 含义 |
---|---|
int i | 定义整型变量i |
int *p | p为指向整型数据的指针变量 |
int a[n] | 定义整型数组a,有n个元素 |
int *p[n] | 定义指针数组p,它由n个指向整型数据类型的指针元素组成 |
int (*p)[n] | p为指向含有n个元素的一维数组的指针变量 |
int f() | f为带回整型函数值的函数 |
int *p() | p为带回一个指针值的函数,该指针指向整型数据类型 |
int (*p)() | p为指向函数的指针,该函数返回一个整型值 |
int **p | p是一个指针变量,它指向一个指向整型数据类型的指针变量 |
留言