一.预处理命令
分为三种: 1.宏定义 2.文件包含 3.条件编译
代码变成可执行文件:
预处理 -------> 编译 ----------> 链接--------->可执行文件
宏定义
1.不带参数的定义
#define 标识符 内容
#define PI 3.1415 //PI为宏名
int main(void)
{
printf("%f\n",PI);
return 0;
}
gcc -E -Omain.i main.c
上面指令表示只做预处理,不编译。
计算机会无脑把PI替换成 3.1415。
宏名所有都需要大写,以和变量区分,且PI不能是左值。
2. 带参数的宏定义
#define 宏名(参数表) 字符串
#define ADD(a,b) (a + b)
int main(void)
{
printf("%d\n",ADD(3,4)); //输出为7
printf("%d\n",ADD(3 > 4,5)); //输出为0, 因为计算机会无脑替换 为 (3 > 4 + 5) return 0; //此时输出为假
}
因此在宏定义时,应尽量多的带上括号
如在上面的定义中,应尽量写成#define ADD(a,b) ((a) + (b))
这样就不容易出现歧义
宏与函数是有区别的,宏是以空间换时间,且代码不具有复用性。
文件包含
#include <math.h> //可以是相对路径
#include </home/linux/1.txt> //也可以是绝对路径
当为相对路径时 < > 会在 /usr/include/ 文件夹里面找需要的文件
#include "func.c" // 会在与当前 main.c 同文件夹 下找该文件
条件编译
#if 0 //相当于把下面的代码注释掉了,非0即为真,也可 #if 1 则会显示下面的代码
int main(void)
{
return 0;
}
#endif
#define ABC
int main(void)
{
#ifdef ABC //宏定义了ABC则执行下面语句
puts("Hello"); //程序段1
#else //否则执行下面语句
puts("World"); // 程序段2
#endif
}
一般用于debug
//clock.h文件
struct Clock
{
int hour;
int minute;
int second;
};
//func.c文件
#include "func.h"
void fn(struct Clock c)
{
}
//func.h文件
#include "clock.h"
extern void fn(struct Clock c);
//main.c文件
#include "clock.h" //会无脑拷贝 替换后如下
/*
struct Clock
{
int hour;
int minute;
int second;
}
*/
#include "func.h" //替换后如下
/*
#include "clock.h" 会再次替换, 替换后与上面出现了同名 struct Clock{ ......}
extern void fn(struct Clock c);
*/
int main()
{
struct Clock(c);
fn(c);
return 0;
}
会出现编译报错,因为在同一作用域中,不允许出现同名函数。
因此头文件应该改成
//clock.h文件
#ifndef CLOCK_H //这样就可以防止同名函数的出现
#define CLOCK_H
struct Clock
{
int hour;
int minute;
int second;
};
#endif
//func.h文件
#ifndef FUN_H //如果没有定义FUN_H
#define FUN_H //则定义FUN_H
#include "clock.h"
extern void fn(struct Clock c);
#endif
二.初识指针
指针是用来装地址的数据类型
定义:
基类型 *指针变量
int main(void)
{
int i = 10;
int *p;
p = &i;
*p = 6; //这里的 * 是指针运算符,表示指向 p 里面存储的地址 地方的值。 // *p与 i 等 效。 属于间接访问 i
printf("%d\n",i);
return 0;
}
输出: 6
void fn(int *n)
{
*n = 100;
}
int main(void)
{
int i = 10;
fn(&i);
printf("%d\n",i)
return 0;
}
输出: 100
此时因为传的是 i 的地址 因此 i 的值也会改变,输出为100
void maxMinOfNumbers(int a,int b,int *max,int *min )
{
if(a >b)
{
*max = a;
*min = b;
}
}
int main(void)
{
int a = 10, b = 20;
int max,min;
maxMinOfNumbers(a,b,&max,&min);
printf("%d,%d",max,min);
return 0;
}
输出: 20,10
用指针时,就可以实现返回1个以上的结果,而return 一次只能返回一个结果。
int i = 6;
int *p = &i; //此时 &*p 和 *&p 是等价的,都表示指针p,相当于*与&抵消了
//而 *&i 可以,但 &*i 会报错 因为 * 运算符后面必须是地址
int * t
// 通常 指针地址是 随机数的,我们把它称为野指针,程序一般会崩溃
指针使用的总结:
1.根据指针变量中的值去内存中定位
2.从定位处开始向后偏移sizeof(基类型)个字节
3.将偏移后的那部分内存空间当作是一个基类型变量来看