跳至主要內容

C语言

zzz大约 3 分钟后端C语言

C语言

内存

size命令查看内存布局

  • 代码段 :方法中的要执行的代码
  • 数据段 :已经初始化的静态变量
  • bss段:未初始化的静态变量
image-20220108153610135
image-20220108153610135

堆栈区别

  • 堆和其他区段一样,都是从低地址向高地址发展

  • 栈则相反,是由高地址向低地址发展

常用方法

mallocfreecallocrealloc

内存池

频繁的调用mallocfree等操作会产生较多的内存碎片。

程序用一个单链表去维护一个内存池。

宏定义

预处理(文件包含、宏定义、条件编译)=》编译

宏定义只是做简单的替换

不带参数宏定义

  • 宏命名通常约定大写

  • 宏定义不是说明或语句,结尾不需要加分号

  • 作用域是从定义位置开始到真个程序结束

  • 可以用#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中有限制。

文件

打开关闭函数fopenfclose

文件读写

读取单个字符:

fgetc、getc,fgetc是一个函数;而getc则是一个宏的实现。

读取字符串:

fgets