目录
1. 内存的使用方式
栈区:局部变量、函数形参 ------> 出了使用范围自动销毁
堆区:动态内存分配的空间
静态区:全局变量、static 修饰的静态变量
在创建数组的时候,如何定义合适的数组大小?
创建10?可能太少
创建100?可能又太多了,浪费内存
用变量n?类似于这样的 int arr[n] ?n是变量,[] 定义数组需要一个常量表达式,写法 ❌
C语言是可以创建变长数组的------C99 标准提出(就是利用变量n,创建数组的大小),但是这种方式不是很普遍,很多的编译器不支持
所以这时候就需要动态内存开辟空间,在堆区申请空间
动态内存分配的函数有四个:
- malloc
- free
- calloc
- realloc
2. malloc 和 free 函数
malloc 开辟 0 字节的空间,C语言标准没有定义,最好不要这样写
2.1 malloc 开辟空间
malloc函数使用:
1. 首先,malloc 需要引用头文件 stdlib.h
2. size_t 通过之前的学习,之前是无符号整型,单位是字节,这里我们申请10个整型空间,也可以直接写40
3. 因为申请的是 int 类型,所以我们用 int* 指针来管理
4. 因为 malloc 的返回类型是void* 空类型,所以这里需要强制类型转换(int*)
2.2 malloc 开空间失败
malloc开辟空间失败的情况:
利用之前学习的 errno 错误码,strerror 将错误码转换为对应的错误信息
2.3 free 回收、释放空间
free 释放空间,需要头文件 stdlib.h
虽然,整个程序结束,系统也会回收开辟的空间
但是,如果下面还有很多任务要执行的话。那么这块空间接下来不需要使用的话,就需要人主动回收空间
这个时候,p指向的空间只是被释放掉了。但是p的地址还在,所以最好将p赋值NULL空指针
free 的注意事项:
- free 释放的空间应该是动态内存开辟的,如果不是,那么free 的行为是未定义的(程序可能会崩溃------> 动态内存开辟常见错误,多点几次关闭才能关掉)
- free 的指针如果是NULL空指针,那么函数什么都不做
3. calloc 函数
calloc 会开辟一块空间,并且每个元素会初始化 0
num : 元素的格式
size : 每个元素的大小
malloc 和 calloc 的区别:
calloc 开辟空间:
4. realloc 函数
realloc 调整动态内存开辟的大小
注意事项:
1. 追加内存足够,则直接追加,返回原来地址
2. 追加内存不够,那么将会重新找一块内存,将原来的内容拷贝并释放,然后返回新的地址
3. 为了防止realloc 追加空间失败,返回NULL'空指针修改了p,通常创建新的指针接收
realloc 和 malloc 具有一样的功能
- realloc 实现 malloc 功能
5. 常见动态内存分配的错误
5.1 直接对NULL空指针解引用
如果malloc 开辟内存失败,就会返回NULL空指针
5.2 对动态内存空间的越界访问
访问越界,有可能输出会卡死,多点几次关闭才能关掉
5.3 对非动态开辟内存使用free 释放
程序会崩溃
5.4 使用free 释放动态开辟内存的一部分
这时候p 已经改变了,不是动态内存开辟的空间,已经通过++操作指向后面了。
程序会崩溃
free 需要释放开辟的地址
5.5 对同一块动态内存多次释放
p被多次释放
程序会崩溃
如何规避这种错误:
1. 谁开辟,谁释放
2. 将p赋值为NULL空指针,free 空指针NULL,不会有任何操作
5.6 动态开辟空间忘记释放(内存泄漏)
忘记释放空间
重点 !
6. 其他
6.1 关于指针赋NULL
指针在不知道赋什么初值的时候,可以赋NULL空指针
但是这个时候是不能直接解引用的(*p = 12;❌,*p ="abc";❌),这个时候p是NULL空指针,不能解引用。想要正确使用,需要将一个地址赋值给p
例如p = &a ; p = arr
6.2 打印字符串
7. 内存分配
因此: