include guards
防止 .h 文件重复编译两次。
使用
#ifndef EGG_H // 就是if not define
#define EGG_H // 接上句,如果没有定义,就定义,如果定义了就跳过这句
#endif // 直到这一句通过这三条预处理器指令,确保头文件中的内容只编译一次。
更简单的方式
现代编译器使用更为简单的方式,在头文件第一行写上:
#pragma once // 这个头文件只包含一次函数定义与函数原型
所谓函数原型,就是在 .h 这种文件中定义的,后面是 ; 而非 {} 的函数。
而函数定义就是我们日常写的一些方法了。
简要地说,函数原型不关注如何实现一个函数的,它只是说明这个函数需要什么,返回什么。
而函数定义就关注这个函数是如何实现的。
函数原型出现的原因
解决编译顺序问题。
也就是向前声明。
c 语言的内存管理
主要就用到三个方法,malloc,realloc,free。
malloc
分配内存。
int *arr = (int*)malloc(10 * sizeof(int));
// malloc需要根据参数开辟空间,以字节为单位的,所有需要用到sizeof,这个返回类型需要的字节数量,然后malloc返回的是一个指针
// 这就需要转换了,把这个指针变成int类型的指针,前面就加上int*realloc
重新分配内存。
// 先分配一个小数组
int *arr = (int*)malloc(5 * sizeof(int));
// 需要更多空间!
int *new_arr = (int*)realloc(arr, 10 * sizeof(int));
// 原本内存不够了,就分配一个新的内存,接受两个参数,第一个是原本的指针,第二个是新开辟的空间的大小
// 第二个参数是扩展到的位置,而不是原本的增加了,不是append,而是new capacityfree
有 malloc,就要有 free,分配了内存就要关闭。
int *ptr = (int*)malloc(5 * sizeof(int));
free(ptr);
ptr = NULL // 好习惯,释放完后将指针设置为NULL,避免误用内存泄露
如果分配了空间,但是没有 free 就会造成内存泄露。
这个内存指的就是 ram,虽说 ram 断点就丢失,并且当程序完全退出后,操作系统会收回该程序占用的所有内存空间。
但是问题会出在程序运行期间。
长期运行的程序可能会因为内存耗尽而关闭。
其实 win 10 就有这个问题,win 10 的桌面窗口管理器就有内存泄漏问题,运行时间久了,可能占 10 几个 G 的 ram,电脑变得非常卡。
struct
只能包含数据字段,不能包含函数。
并且每次都要定义,都要加上 struct 才行,即便是已经定义好的 struct。
比如:
struct Student{}; // struct定义完需要加上分号,表示语句结束
void getStudent(struct Student student);而 cpp 中的 struct 是支持包含数据与方法的。
c 需要通过一些高级技巧,例如函数指针,才能模拟方法,模拟类。
fgets 使用
函数原型
char *fgets(char *str, int n, FILE *stream);str:指向字符数组的指针,用于存储读取的字符串。这个就是缓冲区char buffer[100]。n:最大读取字符数(包括结尾的空字符\0)。stream:文件流(如stdin或文件指针)。
返回指向字符数组的指针。
stream
流,是数据输入输出的抽象对象,用于统一接口处理各种数据源。
主要类型:
- 标准流
- stdin:标准输入,键盘
- stdout:标准输出,屏幕
- stderr:标准错误,屏幕
- 文件流
- 通过
fopen()打开文件返回的指针
- 通过
- 其他流
- 字符串流
- 网络套接字流
strtol
将字符串转换为长整型。
函数原型
#include <stdlib.h>
long strtol(const char *str, char **endptr, int base);str:要转换的字符串endptr:指向剩余未转换部分的指针(可设为NULL),比如"1234abc",这个指针最后就指向"abc"了。base:进制(2-36,0表示自动检测)
返回转换后的长整型值。
失败了返回 0。
数组退化
c 语言中数组参数会退化成为指针,所以数组的所有其他属性,长度什么的就全部丢失了。
缓冲区
缓冲区(Buffer) 是内存中的一块临时存储区域,用于在数据从一个地方传输到另一个地方时暂存数据。
在C语言输入输出中,主要有两种缓冲区:
- 输入缓冲区:存储从键盘等输入设备读取的数据
- 输出缓冲区:存储要显示到屏幕等输出设备的数据
使用 c 语言的读取操作,经常会出现缓冲区问题,比如上一个 gets 的结束后输入 \n 也就是按下 enter,被下一个 gets 直接读取了,因为这个被放进缓冲区了,没有清空,下一个 gets 直接读取,导致程序出错。
scanf 的模式匹配机制
scanf 本质上是一个模式匹配函数,它根据格式字符串中的格式说明符来解析输入。