C语言
C语言
内存
size命令查看内存布局
- 代码段 :方法中的要执行的代码
- 数据段 :已经初始化的静态变量
- bss段:未初始化的静态变量
堆栈区别
堆和其他区段一样,都是从低地址向高地址发展
栈则相反,是由高地址向低地址发展
常用方法
malloc
、free
、calloc
、realloc
内存池
频繁的调用malloc
和free
等操作会产生较多的内存碎片。
程序用一个单链表去维护一个内存池。
宏定义
预处理(文件包含、宏定义、条件编译)=》编译
宏定义只是做简单的替换
不带参数宏定义
宏命名通常约定大写
宏定义不是说明或语句,结尾不需要加分号
作用域是从定义位置开始到真个程序结束
可以用#undef来终止宏定义的作用域
宏定义允许嵌套
#define PI 3.14
// 支持作用范围
#define PI 3.14
// PI这个宏可以有效范围
#undef PI
// 嵌套
#define R 6371
#define PI 3.14
#define V PI * R * R * R * 4 / 3
带参数宏定义
#define MAX(x,y) (((x)>(y)) ? (x) : (y))
// #define MAX(x,y) (x>y ? x : y) 之所以上面要加括号就是为了防止运算符优先级的问题导致的问题
#和##
#
和##
是两个预处理运算符。在带参数的宏定义中,
#
运算符后面应该跟一个参数,预处理器会把这个参数转换为一个字符串。#define SQUAR(str) # str
##
运算符被称为记号连接运算符,比如我们可以使用##
运算符连接两个参数。#define TOGETHER(x,y) x ## y
可变参数
// ...代表可变参数 __VA_ARGS__是实际接收到的参数 可变参数可以传空参
#define SHOWLIST(...) printf(# __VA_ARGS__)
内联函数 inline
使用 inline关键字去定义内联函数,在编译器会将使用函数的地方进行内联替换。但是会增加编译时间,现代编译器比较聪明,就算你不写inline,它也会自动将一些函数优化成内联函数。
结构体
定义
// 声明
struct XXX {
数据类型 名称;
。
。
} [定义结构体变量];
// 使用 定义结构体变量
struct XXX 变量名;
用sizeof查看结构体大小,可以发现编译器对结构体的成员变量会做内存对齐。32位机按照4字节对齐。调整C结构体的成员变量的顺序可以达到节省内存的目的。
结构体指针
结构体指针访问成员变量又两种方法:
(*结构体指针).成员名 结构体指针 -> 成员名
函数传递结构体变量会导致程序开销变大,所以可以用结构体指针替代。
动态申请结构体
运用malloc
函数在堆中分配内存,使用完需要进行free
共用体
定义
union 共用体名称
{
共用体成员1;
共用体成员2;
....
};
成员都是共用一个地址存储内容
关键字
typedef
给数据类型取别名
// 将int取两个别名,一个是integer,一个是指针类型的PTRINT
typedef int integer,* PTRINT;
// 指向 数组的指针别名
typedef int (*PTR_TO_RUN)[3];
// 指向 返回值为int参数为void的函数的指针别名
typedef int (*PTR_TO_RUN)(void);
位域
unsigned int a:1;
位操作
C语言并没有规定一个字节的尺寸,“可寻址的数据存储单位,其尺寸必须是可以容纳运行环境的基本字符集的任何成员”。
不同数据类型的具体大小没有规定,不同的平台下可能有不同的大小限制,一般在limit.h中有限制。
文件
打开关闭函数fopen
、fclose
文件读写
读取单个字符:
fgetc、getc,fgetc是一个函数;而getc则是一个宏的实现。
读取字符串:
fgets