一、内存的分配方式
二、常见的内存错误及对策
1.使用malloc申请内存后,应该用 if ( p==NULL)或 if ( p! =NULL) 进行防错处理。防止因内存分配失败而使用指针值为 NULL 的内存。
2.如果指向内存块的指针是函数的参数,则在函数的入口处使用assert断言进行检查。
3.不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
4.避免数组或指针的下标越界,特别要当心发生“多 1 ”或者“少 1”操作。
5.动态内存的申请与释放必须配对,程序中 malloc 与 free 的使用次数一定要相同,防止内存泄漏。
6.用 free 释放了内存之后,立即将指针设置为 NULL,防止产生“野指针”。
7.程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
8.不要返回指向“栈内存”的指针因为该内存在函数体结束时被自动销毁。
三、指针与数组的对比
1.数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
2.指针可以随时指向任意类型的内存块,它的特征是“可变”
3.用运算符sizeof 可以计算出数组的容量(字节数)。但无法计算指针所指的内存容量,除非在申请内存时记住它。
4.注意当数组作为函数的参数进行传递时,该数组会自动退化为同类型的指针。因此,当函数内需用到数组的大小参与计算时,不能在函数内计算数组大小。需要在调用函数之前先使用sizeof计算出数组大小,再将结果作为参数传入函数。
四、free 把指针怎么了?
只是把指针所指的内存给释放掉,但并没有把指针本身干掉。
如果此时不把指针设置为 NULL,那么指针就成了“野指针”
五、杜绝“野指针”
1.初始化指针变量(NULL或有效地址)
2.指针使用之前进行有效性检查
3.如果函数的参数是指针,则在函数的入口处使用assert断言进行有效性检查。
4.指针被 free 释放掉之后,及时设置NULL。
5.注意指针指向的变量的作用范围。例如函数不要返回指向“栈内存”的指针,不要引用另一代码块中的变量地址
六、内存耗尽怎么办?
如果在申请动态内存时找不到足够大的内存块,malloc 和 new 将返回 NULL 指针,宣告内存申请失败。通常有两种方式处理“内存耗尽”问题。
(1)判断指针是否为 NULL,如果是则马上用 return 语句终止本函数。
(2)判断指针是否为 NULL,如果是则马上用 exit (1) 终止整个程序的运行。
如果一个函数内有多处需要申请动态内存,那么方式(1)就显得力不从心(释放内存很麻烦),应该用方式(2)来处理。
七、malloc/realloc/free 的使用要点
1.malloc 返回值的类型是 void * ,所以在调用 malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。
2.在 malloc 的“( ) ”中使用 sizeof 运算符是良好的风格
3.realloc函数可以对动态开辟的内存的大小进行调整
初次调用realloc效果相当于malloc
不能用存放旧地址的指针接受新空间的地址,如果realloc申请内存失败返回NULL的话,会使指针中的地址丢失,而造成丢失数据
3.free(p)
如果 p 是NULL指针,那么 free 对 p 无论操作多少次都不会出问题。
如果 p 不是 NULL 指针,那么 free 对 p连续操作两次可能会导致程序运行错误。
如果 p 指向的空间不是动态开辟的,那free函数的行为是未定义的,可能会导致程序运行错误。
如果使用free释放的动态内存块不完整,会造成内存泄露。(不要随意移动指向动态内存空间首地址的指针)
八、柔性数组
柔性数组的特点
1.在C99标准下 ,结构体中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
2.结构体中的柔性数组成员前面必须至少有一个其他成员。
3.sizeof 返回的这种结构体大小不包括柔性数组的内存。
4.包含柔性数组成员的结构体用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组的使用
柔性数组的优势
1.方便内存释放:
把结构体的内存以及其成员要的内存一次性分配好
用一次free就可以把所有的内存也给释放掉。
2.有利于提高访问速度
提高访问速度,减少内存碎片
返回专栏目录https://blog.csdn.net/zty857016148/article/details/127068555