系列文章目录
🌟 个人主页
:古德猫宁-
🌈 信念如阳光,照亮前行的每一步
前言
本节目标:
前面的文章介绍了C语言的动态内存开辟,本文重点讲述常见的动态内存的错误
一、对NULL指针的解引用操作
void test()
{
int* p = (int*)malloc(sizeof(int));
*p = 20;
free(p);
}
解释:
这段代码的主要目的是使用动态内存分配(malloc)为一个整数分配内存,将其值设置为 20,然后使用 free 函数释放该内存。从代码的角度来看,没有显著的问题,但是有一些潜在的注意事项:
在实际的程序中,最好在调用 malloc 后检查分配是否成功。如果内存分配失败,malloc 将返回 NULL,释放内存后,我们最好将指针置为 NULL,以避免悬挂指针问题
修改后:
void test()
{
int* p = (int*)malloc(10*sizeof(int));
*p = 20;//如果p的值是NULL,就会有问题
if (p == NULL)//判断分配是否成功
{
perror("malloc");//报错
return 1;
}
free(p);//释放空间
p = NULL;
}
二、对动态开辟空间的越界访问
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
//使用
int i = 0;
for (i = 0; i <= 10; i++)
{
*(p + i) = i;//当循环到第11次时就越界访问了
}
//
free(p);
p = NULL;
return 0;
}
解释:
上面这段代码中使用 malloc 分配了 40 字节的内存,然后在循环中尝试写入 11 个整数。由于数组索引是从 0 开始的,因此当 i 等于 10 时,实际上是在访问 *(p + 10),这越过了为数组分配的内存范围。
所以我们可以这样改:
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(11*sizeof(int));//分配足够的空间来存储11个整数
if (p == NULL)
{
return 1;
}
//使用
int i = 0;
for (i = 0; i <=11; i++)
{
*(p + i) = i;//循环的上限改为 10,不会越界访问
}
//
free(p);
p = NULL;
return 0;
}
三、对非动态开辟内存使用free释放
int main()
{
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
//使用
//...
p = &a;//p指向的空间就不再是堆区上的空间
free(p);
p = NULL;
//....
return 0;
}
解释:
- 这段代码存在一个问题,即在将指针 p 指向堆分配的内存后,又将其指向了一个栈上的变量 a,然后尝试使用 free(p)释放内存。这是不正确的,因为 p 指向的不再是通过 malloc 分配的堆内存,而是指向了栈上的变量。
- 当我们使用 free 函数释放内存时,应该确保指针指向的是通过 malloc 或类似函数动态分配的内存块。在这种情况下,并没有释放通过 malloc 分配的内存,而是尝试释放栈上的变量,这可能导致未定义的行为。
- 所以在释放通过 malloc 分配的内存,我们确保在释放之前不要改变指针 p 指向的位置。
修改后:
#include <stdlib.h>
int main() {
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL) {
return 1;
}
// 使用
//...
// 不要改变指针 p 指向的位置,不要执行 p = &a;
// 释放内存
free(p);
p = NULL;
//....
return 0;
}
四、使用free释放一块动态开辟内存的一部分
#include<stdlib.h>
int main()
{
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
//使用
p++;
//释放
free(p);
p = NULL;
return 0;
}
解释:
- 这段代码存在一个问题。在使用 malloc 分配内存后,我们将指针 p 递增了一个位置 (p++),然后尝试使用 free 函数释放内存。这样做是不正确的,因为 p 不再指向 malloc 分配的起始位置,而是指向了分配内存块的下一个位置。free 函数要求传入的指针必须指向通过 malloc 等分配函数返回的精确地址。
- 如果对指针进行了移动,应该确保在释放内存之前将指针重新指向 malloc 分配的起始位置。
修改后:
#include <stdlib.h>
int main() {
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL) {
return 1;
}
// 使用
p++; // 移动指针
// 重新指向起始位置
p--;
// 释放内存
free(p);
p = NULL;
return 0;
}
五、 对同一块动态内存多次释放
int main()
{
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL)
{
return 1;
}
//使用
//释放
free(p);
p = NULL;
free(p);
p = NULL;
return 0;
}
解释:
- 上面这段代码存在一个问题,即在释放内存后又尝试再次释放相同的内存块。这是不正确的,因为一旦通过 free 函数释放了内存,就不应该再次使用相同的指针来释放。这可能导致未定义的行为,甚至程序崩溃。
- 代码中,第一次调用 free(p) 将内存释放了,并将指针 p 设置为 NULL。然后,你又尝试使用 free(p),这是不安全的。
修正这个问题的方法是只调用一次 free,而不是两次:
#include <stdlib.h>
int main() {
int a = 10;
int* p = (int*)malloc(40);
if (p == NULL) {
return 1;
}
// 使用
// 释放内存
free(p);
p = NULL;
// 避免再次释放相同的内存块
// free(p); // 这一行应该注释掉或删除
return 0;
}
六、动态开辟内存忘记释放(内存泄漏)
void test()
{
int* p = (int*)malloc(100);
if (NULL != p)
{
*p = 20;
}
free(p);
p = NULL;
}
int main()
{
test();
//
while (1);
}
解释:
- 上面这段代码中,在结尾没有调用 free 来释放动态内存分配的空间,而且main函数无限循环,这个函数被调用多次,每次都分配内存但没有释放,程序将持续占用更多的内存,最终可能导致系统资源(内存池)不足,这类问题称为内存泄漏。
修改后:
void test()
{
int* p = (int*)malloc(100);
if (NULL != p)
{
*p = 20;
}
free(p);
p = NULL;
}
int main()
{
test();
return 0; // 添加这行以正常退出程序
}
忘记释放不再使用的动态开辟的空间会造成内存泄漏
切记:动态开辟的空间一定要释放,并且正确释放。文章来源:https://www.toymoban.com/news/detail-764417.html
总结
各位要对上面常见的动态内存开辟有一个清晰的认知,并避免这些问题的出现,今天的笔记到此结束啦文章来源地址https://www.toymoban.com/news/detail-764417.html
到了这里,关于C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!