C语言:内存的分配与管理
1、内存区域的划分标准:
代码段 存储代码
数据段 静态/全局数据、常量(const)
堆区(heap) 动态内存分配(更灵活的设置容器大小存储数据)
栈区(stack) 局部变量、函数参数
2、内存分配方式的原理:静态分配和动态分配
静态分配:编译器在处理程序源代码时分配(变量)
动态分配:程序执行时按动态要求来分配(由程序员来决定,用完得人为释放)
比较:静态的程序执行前分配,效率高,灵活差,对象是有名字的变量,内存分配和释放由编译器完成;动态对象没有名字的变量,通过指针间接地对它进行操作。
3、理解野指针的概念:
概念:野指针不是空(NULL)指针,二是指向不属于自己的内存指针。
三种形式:
(1)指针变量没有被初始化。
(2)指针p被free或者delete之后,没有将其置NULL,但是p仍然指向这块已经不属于自己的内存。
(3)通过函数返回局部变量的地址。局部变量存放在stack栈中,函数一被执行完,在这个栈中的数据就会被释放,此时返回的指针就没有了指向,也就是函数中的那一块内存已经不属于返回的这个指针了。
4、内存泄露的概念:
内存被分配后被系统记录,但是用完了,最后没有被释放,记录也就没有被删除此时内存一直被占用,即为内存泄露。类似于图书馆,好借好还。
5、理解malloc函数原型的含义:
#include<stdlib.h>
malloc 函数原型:
void * malloc(unsigned int size);
通用类型指针,真正使用时,需要强制转换为要使用的类型
说明:(1)、size这个参数的含义是分配的内存的大小(以字节为单位)
(2)、返回值:失败,则返回值为NULL(空指针)。成功,则返回是一个 指向空类型(void)的指针,即所分配内存块的首地址。
记住:先对返回值做判断?如果为空,分配内存失败。反之,申请成功。
(1) 用malloc申请一块只保存一个整型类型的内存
int *p = (int*)malloc(sizeof(int)
(2) 用malloc申请一块能够保存25个整型类型的内存
int *p = (int *)malloc(sizeof(int)*25)
对动态空间的访问方式
对单一内存的访问
*p = 100;
对动态数组的访问
p[1];*(p+1);(p+1)
数组存储数据时:
*(p+i)//循环存储数据过程中,p所指向的一块内存首地址一直没有变过,变化的只是数据在这一块内存中存放的位置。测试过
*p++;//循环存储数据中,p所指向的内存首地址一直在变化,其实,就是一块内存只是存放了一个数据,p就移动指向了另一块空间首地址,接着存下一个数据。测试过
6、释放内存的函数free的含义:
函数原型:free (void *block)//释放的必须是malloc返回的地址
说明:动态内存的申请和释放必须配对
7、注意事项:
(1)如果函数参数是一个指针,不要指望指针自己去申请动态内存。也就说指针必须指向一个有效的内存区域。
(2)指针消亡了,p=NULL并不代表它所指向的内存会被自动释放;内存被释放了,free(p)并不代表指针会消亡或者成了空指针。必须两者结合。
(3)malloc分配内存后,程序结束前必须使用free()将已分配的内存空间释放。malloc和free必须是一对一的关系,不能一对多即过度释放。
8、知识拓展:
(1)使用calloc函数分配动态内存
函数原型:void *calloc(unsigned n,unsigned size );
作用是:在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般比较大,足以保存一个数组。
意义:用calloc函数可以为一维数组开辟动态的存储空间,n为数组元素个数,每个元素长度为size。这就是动态数组。函数返回指向所分配域的起始位置的指针;如果分配不成功,返回NULL。
例如:
p = calloc(50,4);//开辟50*4个字节的临时分配域,把起始地址赋给指针变量p
(2)使用realloc函数分配动态内存
函数原型:void* realloc(void *p,unsigned int size);
作用:如果已经通过malloc函数或将calloc函数获得了动态空间,想改变其大小,可以用realloc函数重新分配。
意义:用realloc函数将p所指向的动态空间的大小改变为size。p的指向不变,如果分配不成功,返回NULL。
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!