C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列)

这篇具有很好参考价值的文章主要介绍了C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享

系列文章目录

🌟 个人主页:古德猫宁-

🌈 信念如阳光,照亮前行的每一步



前言

本节目标:前面的文章介绍了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;
}

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享
解释:

上面这段代码中使用 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;
}

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享
解释:

  • 这段代码存在一个问题,即在将指针 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;
}

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享

解释:

  • 这段代码存在一个问题。在使用 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;
}

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享
解释:

  • 上面这段代码存在一个问题,即在释放内存后又尝试再次释放相同的内存块。这是不正确的,因为一旦通过 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);
}

C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列),c语言,开发语言,学习,笔记,经验分享
解释:

  • 上面这段代码中,在结尾没有调用 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

到了这里,关于C语言中6个常见的动态内存的错误详解(能看懂文字就能明白系列)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C生万物 | 常见的六种动态内存错误

    学习过C语言中的动态内存函数,例如【malloc】、【calloc】、【realloc】、【free】,那它们在使用的过程中会碰到哪些问题呢,本本文我们一起来探讨下~ 代码: 分析: 首先看到第一个,你要知道的是 INT_MAX 是什么。它是一个宏定义,表示int类型(整型)能够表示的最大值,其

    2024年02月11日
    浏览(32)
  • 二维前缀和&二维差分(超详细,python版,其他语言也很轻松能看懂)

    上一篇文章讲解了一维前缀和一维差分,本篇进阶为二维。 二维前缀和跟一维前缀和求法相同,这里直接上例子。 数组a = [[1,2,2,1],[3,2,2,1],[1,1,1,1]] a数组如图: 则数组a的前缀和为:数组b[[1,3,5,6],[4,8,12,14],[5,10,15,18]] b数组如图: 前缀和递推公式为 b[i][j] = b[i - 1][j] + b[i][j - 1]

    2024年04月22日
    浏览(38)
  • TCP/IP协议族之TCP、UDP协议详解(小白也能看懂)

            在进行网络编程之前,我们必须要对网络通信的基础知识有个大概的框架,TCP/IP协议族涉及到多种网络协议,一般说TCP/IP协议,它不是指某一个具体的网络协议,而是一个协议族。本篇章主要针对IP协议、TCP和UDP协议记录总结。 OSI七层参考模型是国际标准化组织(

    2024年02月02日
    浏览(44)
  • YOLOv8预测参数详解(全面详细、重点突出、大白话阐述小白也能看懂)

    YOLOv8现在可以接受输入很多,如下表所示。包括图像、URL、PIL图像、OpenCV、NumPy数组、Torch张量、CSV文件、视频、目录、通配符、YouTube视频和视频流。表格✅指示了每个输入源是否可以在流模式下使用,并给出了每个输入源使用流模式的示例参数 预测参数 Key Value Description s

    2024年02月11日
    浏览(38)
  • 【计算机视觉】YOLOv8参数详解(全面详细、重点突出、大白话阐述小白也能看懂)

    comments description keywords true Master YOLOv8 settings and hyperparameters for improved model performance. Learn to use YOLO CLI commands, adjust training settings, and optimize YOLO tasks modes. YOLOv8, settings, hyperparameters, YOLO CLI commands, YOLO tasks, YOLO modes, Ultralytics documentation, model optimization, YOLOv8 training YOLO 设置和超参数

    2024年02月05日
    浏览(45)
  • 【c语言】重温一下动态内存,int数组过大会造成栈错误

    项目场景:互助群同学在刷题的过程中,遇到的一个题目,需要申请一个很大数组,于是这个同学就写了 int[1000000] ,其实这样写也没有错,可是运行后却显示栈错误。于是就找到我来请教,我想就这个问题延申一下,在谈谈栈空间,堆空间等。 这里抛开逻辑不谈,在申请in

    2024年02月04日
    浏览(39)
  • 数据在内存中的储存·大小端(文字+画图详解)(c语言·超详细入门必看)

    前言:Hello,大家好,我是心跳sy😘,本节我们介绍c语言的两种基本的内置数据类型:数值类型和字符类型在内存中的储存方法,并对大小端进行详细介绍(附两种大小端判断方法),文章每个例题和知识点都会有详细的解释,友友们放心食用,我们一起来看看吧~!! 👉我

    2024年02月10日
    浏览(38)
  • 【c语言】详解动态内存管理

    回想一下我们之前学过的内存开辟方式: 在学习c语言时我们知道数据结构通常是固定大小的。就拿数组举例,一旦程序完成编译,那么 数组的大小及元素的个数就确定了 。那么在不修改程序并且再次编译程序的情况下就无法改变数据结构的大小。总结就是下面两个特点:

    2024年02月07日
    浏览(38)
  • 【C语言】动态内存管理详解

    目录 为什么存在动态内存分配 动态内存函数的介绍 malloc 和 free calloc realloc 常见的动态内存错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放(内

    2024年02月15日
    浏览(38)
  • 详解C语言—动态内存分配(二)

    目录 前言: 几个经典的例题题 例一: 例二: 例三: 例四: 例五:   C/C++程序的内存开辟 柔性数组 柔性数组的特点: 柔性数组的使用:  柔性数组的代替: 柔性数组的优势: 小结: 希望在复习完详解C语言—动态内存分配(一)​​​​​​​,阅读此篇文章会进一步提升

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包