[学习笔记]c语言中关于内存的详解
什么是内存
内存(Memory)是计算机的重要部件,也称内存储器和主存储器,它用于暂时存放cpu中的运算数据,以及与硬盘等外部存储器交换数据,是外存与cpu沟通的桥梁,计算机中所有的程序运行都在内存中进行。
C语言中内存分区模型
分区名 | 存储内容 |
---|---|
代码区 | 存放函数体内的二进制代码 由操作系统管理 代码区的内容是共享的 多次运行同一个程序不会重复占用代码区内存 并且代码区是只读的 |
全局区/静态区/常量区 | 存放全局变量和静态变量及常量 程序结束后由操作系统释放 |
栈区 | 由编译器自动分配释放 存放函数的参数值 局部变量等 (高地址向地址 寻址快 地址连续) |
堆区 | 由程序员分配和释放 若程序员不释放 程序结束时由操作系统回收(低地址向高地址 寻址慢 地址不连续) |
动态分配内存的概述
数组声明时需预先定义数组的长度,且长度固定不变,但是在实际编程中,往往会发生内存空间取决于实际输入数据的情况,无法预先确定,为了解决上述问题,c语言提供了一些内存管理函数,可以按需动态分配内存的空间,也可以把不在使用的内存空间回收。
动态分配内存就是在堆区开辟空间
静态分配内存的概述
在程序编译或运行中,按事先规定好的大小分配内存空间 例如 int a[10]
内存空间分配在栈区或者全局变量区
动态内存函数 malloc
需引入头文件: #include<stdlib.h>
函数原型:void *malloc(unsigned int size)
在堆区中分配一块长度为size字节的连续区域 用来存放类型说明符指定的类型的数据
函数返回值是一个 void*指针 使用时必须做响应的强制类型转换,分配的内存空间内容不确定
一般使用memset 进行初始化
申请成功返回开辟好空间的首地址
若申请失败,返回NULL
调用malloc之后一定要判断一下是否申请成功
多次调用malloc申请内存,地址不一定是连续的
动态内存函数 free
需引入头文件: #include<stdlib.h>
函数原型:void free(void *ptr)
ptr : 开辟的堆区空间的首地址
释放 ptr 指向的内存
前提必须是 malloc,calloc,relloc动态申请的内存
char *p = (char *) malloc(100 * sizeof (char ));
free(p);
由于p被释放后,没有赋值,所以p还是指向原先申请的内存地址,但内存已经不能再用了,p变成野指针了
一块动态申请的内存只能free一次,不能多次free
free函数只能释放堆区空间
free函数释放malloc,calloc,relloc返回值指定的空间,不能只释放一部分
为防止野指针,free之后将p赋值为NULL
动态内存函数 calloc
需引入头文件: #include<stdlib.h>
函数原型:void *calloc(unsigned nmemb,unsigned size);
在内存的堆中,申请nmemb块,每块大小为size个字节的连续区域
函数返回值是一个 void*指针 ,分配的内存空间内容为0
申请成功返回开辟好空间的首地址
若申请失败,返回NULL
malloc分配的内存 内容不确定,calloc默认为0
动态内存函数 relloc
由于连续使用malloc和calloc申请内存时,内存地址不一定是连续的,有时会有需求,在原有内存的基础上挨着申请内存,或者开始使用malloc或者calloc申请一块内存,想释放后面一部分内存。
为满足这个需求,relloc应运而生
需引入头文件: #include<stdlib.h>
函数原型:void *relloc(void *s,unsigned newsize);
在原内存空间s的基础上重新申请内存,新的内存大小为newsize字节,
如果原先内存后面有足够大的连续的空间,即追加,
如果不够,则relloc会在堆区申请一个连续的newsize大小的空间,
把原内容拷过来,再释放原先的内存,最后返回新的内存地址。
如果newsize比原内存小,则会释放原内存多出的空间,只留newsize个字节
申请成功返回新的内存的首地址
内存泄漏
内存泄漏的概念:
申请的内存,首地址丢了,找不了,再也没法使用了,也没法释放了,这块内存就被泄漏了
内存泄漏的例子1:
int main() {
char *p;
// 使用malloc申请100字节的内存
p = (char *)malloc(100);
//紧接着p指向一个字符串
p = "hello word";
// 从此之后,你再也找不到此前申请的100个字节了
// 这块内存就泄漏了
}
内存泄露的例子2:
void func(){
char *p;
// 使用malloc申请100字节的内存
p = (char *)malloc(100);
}
int main() {
//每次调用func时 都会申请100个字节的内存
func();
func();
func();
//没有返回内存的首地址,内存没有被释放,共泄漏300字节的内存
}
申请的内存一定不要把首地址丢了,不用的内存一定要释放,
为防止野指针,free释放内存之后要赋值为NULL
关于内存的知识后续会再补充
今天就这样,出门遛弯了~