- gcc编译流程:
第一步:预处理--》将C原文件编译成C文件
文件展开,注释去掉,宏替换去掉,不做语法检查
gcc -E test.c -o test.i
第二步:编译--》将预处理之后的C文件编译成汇编文件
gcc -S test.i -o test.s
第三步:汇编--》将汇编文件编译生成机器文件
gcc -c test.s -o test.o
第四部:链接--》将所有的机器文件共同参与链接,生成一个可执行文件
Gcc *.o -o app
- 对于传参,到底是传普通变量还是传一级指针变量,又或者是传二级指针变量的选择思路
看是否需要在子函数内部引起实参本身发生改变
int a = 90,b = 89,
在子函数中实现ab两个数交换(在子函数中引起实参ab本身发生改变,因此需要将ab
的地址传过去)---func(&a,&b)
Int *p =null;
子函数中实现给实参p赋值一个连续的空间首地址,子函数中引起实参p发生改变,此时p会具备一个首地址,因此需要将&p传过去
Func(&p)-->pointer = &p *pointer = p 因此通过给*pointer赋值就相当于给实参p赋值
- 指针函数
函数返回值类型是指针类型的函数
- 函数指针
指向函数的指针
命名方式:返回值类型(*pfunc)(形参列表)
针对函数指针类型取别名的写法:
返回值类型 (*新类型名)(形参列表);
- 函数指针数组
数组元素类型是函数指针类型的数组
定义:
函数指针类型 数组名[元素个数]; //取完别名之后可以这样定义函数指针数组。
返回值类型 (*数组名[元素个数])(参数表列表);
- 回调函数
把B函数的地址(即函数名或者&函数名)作为A函数的参数,传递给A函数,在A函数中通过使用这个参数间接调B函数的过程称为回调函数
- 动态内存管理
- 申请空间
Void *malloc(size_t size);
功能:申请空间在堆区中
参数:所需申请空间占据的字节数
返回值:成功返回连续空间的首地址,失败返回NULL
void *calloc(size_t nmemb, size_t size);
功能:申请空间
参数:
参数1:所需申请的元素个数
参数2:元素的大小(字节数)
返回值:成功返回连续空间的首地址,失败返回NULL
注意:calloc在申请完空间之后,会自动将申请的连续空间初始化为’\0’
- 释放空间
void free(void *ptr);
功能:释放空间
参数:所需释放空间的首地址
返回值:无返回值
- 扩容空间
void *realloc(void *ptr, size_t size);
功能:用来扩容空间
参数:
参数1:所需扩容空间的首地址(malloc的返回值)
参数2:扩容之后总的字节数(旧 + 新)
返回值:成功返回扩容之后空间的首地址,失败返回NULL
注意:扩容之后的空间首地址可能和之前的地址一样,也可不一样!!!
头文件:
#include <string.h>
- 重置空间
void *memset(void *s, int c, size_t n);
功能:用来重置一片内存空间 (当做清空空间居多!)
参数:
参数1:所需重置内存空间首地址
参数2:所需重置的字符 ---》’\0’ , 0
参数3:所需重置内存空间的大小---》sizeof()
- 结构体
概念:是一种构造类型,目的是为了将一个事物的多重属性表示清楚(可是不同属性也可以是相同得到数据类型)
如何构造一个结构类型:
struct 结构体名
{
数据类型1 成员1 ;
数据类型2 成员2;
。。。。
数据类型N 成员N;
};
如何定义结构体变量:
Struct 结构体名 变量名;
如何给结构体成员赋值:
变量名= {值1,值2.。。。。。。};
struct 结构体名 变量名 = {值1,值2,。。。。。};
如何访问结构体中的成员:
方式1:变量名.成员名;
方式2:结构体指针->成员名;
- 枚举
概念:跟宏比较类似,意味着也是一些常量值,只不过这些常量值是被放在一个集合里面。
如何定义一个枚举类型?
enum 枚举名
{
枚举数值名1,
枚举数值名2,
。。。。
};
- 大小端(字节序)
大端存储:低字节处的内容存储在高地址处,高字节处的内容存储在低地址处
小端存储:低字节处的内用存储在低地址处,高字节出的内容存储在高地址处
低字节:一串二进制数据的右边
低地址:小的地址编号
- 调试BUG的方式
gdb调试工具
流程:
- 生成带有调试信息环境的可执行文件
方式:gcc -g test.c -o App
- 进入该可执行文件
方式:gdb App
- 设置断点 -->让程序从哪里开始调试
方式:b 行标/函数名
- 运行
方式: r
- 单步运行
n: 不进入子函数内部,但不代表不执行子函数
s: 进入子函数内容,并开始执行子函数中每一行代码
- 找到错误所在的行
响应:看到程序打印出一行文本“Program recived Sigmentation fault....”,上一行就是引起错误的所在行。
- 结束调试
方式:按下q退出即可。
- 递归函数
概念:重复调用其他函数或者调用自己,但是调用的时候一定要注意结束调用的条件。
如何编写一个标准的递归函数?
三要素:
- 从哪里开始?
- 从哪里结束?
- 每一步干什么?
使用递归函数完成斐波那契数列的打印
1 1 2 3 5 8 13 21.。。。。。。。
实现要求:输入需要打印的个数N,就输出对应的前N项。
多文件编译
创建一个后缀是.h文件eg: touch test.h
打开test.h ---> vim test.h
编写以下代码:
#ifndef _TEST_H_
#define _TEST_H_
- 宏定义
- 结构体定义
- 取别名
- 全局变量的声明
- 函数的声明
- 枚举类型的定义
#endif
Vim -p 同时打开多个文件进行编辑
Xa 退出并保存多个文件
- Make
概念:工程管理工具
可以将很多.c文件+.h文件进行统一管理
使用:
命令行输入make 目标名 即可
如何编写一个Makefile文件?
---》统一格式
目标:依赖
[Tab]命令表
嵌套Makefile:
Make中的变量
- 用户自定义变量
格式:
变量名:=值 (定义变量且赋初值,变量名建议大写)
- 自动变量
$< :依赖中的第一个依赖
$^ :所有依赖
$@:目标名
$()----取值
- 系统预定义变量
CC:编译器的名称,默认值是cc ,用户可以自己赋值为: eg CC :=cc
CFLAGS:编译器的选项,无默认值,用户可以自己赋值:eg: CFLAGS:= -c -g -Wall
RM:代表删除,默认值为:rm -f,用户可以自己赋值为 eg: RM := -rf
- 环境变量
export :添加一些指定的环境变量到整个系统环境中去
eg:
export 变量1 变量2 变量3
- make -C 指定某个路径
Make -C ./src------>执行src下的单makefile
Make -C ./obj------>执行obj下的单makefile
- Makefile文件中“#文字说明”:相当于注释