预处理命令
1.gcc编译的4个步骤
gcc main.c------>a.out
预处理:展开和#相关的代码:展开头文件、展开宏、处理预处理命令(条件编译)
#include<stdio.h>
#define PI 3.14
#if 0
#endif
gcc -E(生成预处理阶段的代码) main.c -o(重命名) main.i
编译:将c语言程序转换为汇编指令
gcc -S main.i -o main.s
汇编:将汇编指令转换成二进制可执行程序
gcc -c main.s -o main.o
链接:将库函数链接起来(库函数的实现
gcc main.o -o main
2.预处理命令
(1)宏定义
不带参宏:符号常量
#define 符号常量 值
#define PI 3.1415
带参宏:宏函数
#define 符号常量(参数1,参数2,...) 宏的实现
#define ADD(a,b) ((a)+(b)) //求和
#define MAX(a,b) ((a)>(b)?(a):(b)) //比大小
注意:
1.宏作为预处理命令,负责在预处理阶段展开,不做运算,只是代码的替换
2.宏名要大写,宏后不能加分号
3.宏值只是代码的替换,能加括号就加括号
4.宏和函数的区别:
宏是预处理阶段代码替换,会使代码体积增大;
函数时运行时的调用,需要保护现场和恢复现场
(2)头文件
头文件存放:
1.其他头文件
2.声明的数据类型
3.宏定义
4.函数和全局变量的声明
源文件只存放头文件#include "头文件.h"
注意:
1.<>表示包含的是系统头文件,让编译器从系统路径下找:/usr/include
2." "表示包含的头文件是用户自定义,让编译器从当前路径下找
(3)条件编译
1.防止头文件重复包含
#ifndef __大写文件名_H__
#define __ 大写文件名_H__
//头文件内容
#endif
根据宏有没有被定义过,决定头文件中的内容要不要加入编译中
2.条件编译
#if 0 //不编译
#endif
#if 1 //编译
#endif
根据逻辑表达式的结果,为真则编译,为假不编译
#ifdef 宏名 //若该宏有被定义,则编译;若没有,则执行else
#else
#endif
:vsp 文件名.c----》打开双屏
:sp 文件名.c-----》横向打开双屏
:set mouse=a-----》光标转换
:wqa------》全部退出并保存
ctrl+ww
指针
内存:程序运行过程中,可以访问到的内存存储空间;计算机为了方便对内存的管理,以字节为单位,对内存进行了编号
地址(指针):内存的编号,指针指向了一个具体的空间
指针变量:保存地址的一个变量,需要占用8字节内存空间
1.指针基础
(1)定义指针变量
基类型 *变量名
基类型:指针所指向的空间内,存储的数据类型(int、char、float、void、构造数据类型...)
*:类型说明符,说明后面的变量是一个指针
变量名:遵循标识符命名规则(p开头)
pmax、ptmp...
int *pi,*pj;
char *pch;
指针变量中保存的地址,是该数据的首地址
sizeof(指针);在64位计算机系统下,内存中占用8字节;在32位计算机系统,占4字节
(2)指针变量的初始化和赋值
int *p=NULL;
野指针:未初始化或未赋值,或指向一个已释放内存空间的指针。
操作有风险,可能导致程序崩溃;因此避免野指针:
1.给指针初变量始化成空指针NULL(本质是(void*)0)
2.给指针变量初始化成已有变量的地址
(3)指针的运算符
* 指针运算符
用于访问数据
*指针变量;------》指针降级为变量类型-----》基类型
int *p;
p------》int*
*p-----》int
注意:
1. * 只能放在指针变量前面
2. *p,访问指针变量的数据------》指针降级为变量类型-----》基类型
3. *p,访问的字节数取决于该指针的基类型
char *p; *p---->char,访问1字节
int *p; *p---->int,访问4字节
double *p; *p---->double,访问8字节
& 取地址运算符
#
取某变量的空间首地址
注意:
1.&只能给变量取地址,常量和表达式不行
2.&获取的是这个变量的首地址
(4)指针的算术运算
+ * / % 对指针运算没有意义
- 指针1-指针2; 两个指针之间相隔的元素个数=(地址之间的字节差/sizeof(基类型))
++ 指针+1:表示从当前地址向后偏移sizeof(基类型)个字节
-- 指针-1:表示从当前地址向前偏移sizeof(基类型)个字节
char *p; p+1;---->向后偏移1字节
%p打印地址
2.指针作为函数参数
1.被调函数中,想要修改主调函数中定义的变量,必须地址传递
2.被调函数中,想要仅使用主调函数中定义的变量,既可以值传递也可以地址传递
3.被调函数需要返回多个结果时,可以传递主调函数多个变量的地址,地址指向的空间可以保存被调函数得到的结果
3.指针和一维整型数组
数组的数组名就是数组首元素地址
int a[5]={0}; printf("a=%p\n",a); printf("a[0]=%p\n",&a[0]);注意:
1.数组名为一个地址常量(右值),不能为其赋值 a=#×
一维整型数组作为函数参数传递
两种写法 void printf(int a[ ],int len) void printf(int *pa,int len)