第五十四天学习记录:C语言进阶:动态内存管理Ⅱ

常见的动态内存错误

1、对NULL指针的解引用操作

int* p=(int*)malloc(4);
//p进行相关的判断
*p=10;//malloc开辟空间失败,有可能对NULL指针解引用
free(p);
p=NULL;

2、对动态开辟的内存的越界访问

int* p=(int*)malloc(40);//10个int
if(p!=NULL)
{
	int i=0;
	//越界
	for(i=0;i<=10;i++)
	{
		*(p+i)=i;
	}
	free(p);
	p=NULL;
}

3、对非动态开辟内存的free

int a=10;
int* p=&a;
//...
//对非动态开辟内存的free
free(p);

4、使用free释放动态开辟内存的一部分

int* p=(int*)malloc(40);
if(p!=NULL)
{
	int i=0;
	for(i=0;i<10;i++)
	{
		*p++ = i;
	}
	free(p);
	p=NULL;
}

5、对同一块动态内存多次释放

int* p=(int*)malloc(40);
if(p!=NULL)
{
	//使用
	free(p);
	//...
	free(p);
}

6、动态开辟内存忘记释放(内存泄漏)

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int i = 0;
	while (1)
	{
		++i;
		printf("%d\n", i);
		malloc(1);
	}
	return 0;//死机警告!!!不要轻易尝试
}

问:realloc的第一个参数的指针地址必须是malloc或calloc创建的在堆上的地址吗?
ChatAI答:
是的,realloc 的第一个参数必须是由 malloccallocrealloc 函数返回的指针,且该指针必须指向堆上申请的内存空间。如果该指针不合法,也就是不是由上述函数返回的指针,或者指向的不是堆上的内存空间,那么 realloc 可能会导致未定义的行为。

问:realloc的第一个参数的指针也可以为NULL
ChatAI答:
是的,realloc 函数的第一个参数也可以是 NULL 指针。如果第一个参数是 NULL,那么 realloc 的行为和 malloc 的行为是等价的,如果分配内存成功,realloc 将会返回一个指向新内存块的指针。

例如下面的代码可以在堆上分配一段初始化为 0 的内存空间:

int *p = NULL;
p = realloc(p, sizeof(int) * 10);
if (p == NULL) {
    // 分配内存失败的处理
    printf("realloc failed");
} else {
    // 分配内存成功的处理,继续使用 p 指向的内存空间
    printf("realloc succeeded");
}

在函数调用后,如果 realloc 成功了,那么 p 将会指向一个大小为 10 个整数的内存块,并且内存块中的每个整数都将会被初始化为 0。如果 realloc 调用失败了,那么 p 会继续指向 NULL,程序会打印 “realloc failed”。

问:多次free(NULL);也不会报错吗?
ChatAI答:
在 C 语言中,多次调用free(NULL)不会导致程序崩溃或错误。因为在 C 标准中,对 NULL 指针调用 free 函数是被允许的,且不会影响程序的执行。

值得注意的是,在多次释放同一个内存指针时,可能会导致不可预测的错误,这应该避免这种情况的发生,通常情况下在free 之后将指针置空,避免出现重复释放的问题。

例题1:
请问以下代码会有什么样的结果?

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}

void Test()
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

1、运行代码程序会出现崩溃的现象
2、程序存在内存泄漏的问题
str以值传递的形式给p
p是GetMemory函数的形参,只能函数内部有效
等GetMemory函数返回之后,动态开辟内存尚未释放
并且无法找到,所以会造成内存泄漏

改进1:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

void GetMemory(char** p)
{
	*p = (char*)malloc(100);
}

void Test()
{
	char* str = NULL;
	GetMemory(&str);
	assert(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

改进2:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char* GetMemory(char* p)
{
	p = (char*)malloc(100);
	return p;
}

void Test()
{
	char* str = NULL;
	str=GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	free(str);
	str = NULL;
}

int main()
{
	Test();
	return 0;
}

例题2:
请问以下代码会有什么样的结果?

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char* GetMemory()
{
	char p[] = "hello world";
	return p;
}

void Test()
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

int main()
{
	Test();
	return 0;
}

非法访问。
p的内容已被回收,但地址返回了。

例题3:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void GetMemory(char **p,int num)
{
	*p = (char*)malloc(num);
}

void Test()
{
	char* str = NULL;
	GetMemory(&str,100);
	strcpy(str, "hello");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

内存泄漏。

例题4:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void Test()
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

int main()
{
	Test();
	return 0;
}

非法访问。
篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str成为野指针。if (str != NULL)不起作用。

在这里插入图片描述
图片转自比特科技

C/C++程序内存分配的几个区域:
1、栈区(stack):在执行函数时,函数内局部变量的储存单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。
3、数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4、代码段:存放函数体(类成员函数和全局函数)的二进制代码。

实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量除了作用域就销毁。
但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁,所以生命周期变长。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/25013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux使用PowerShell模块管理MsSql-Server

1.安装PowserShell 更新包列表 sudo apt-get update 安装依赖: sudo apt-get install -y wget apt-transport-https software-properties-common 下载 key: wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb&…

chatgpt赋能python:Python内置函数:如何查找和使用?

Python内置函数&#xff1a;如何查找和使用&#xff1f; 作为一名有10年Python编程经验的工程师&#xff0c;我想与大家分享一下Python内置函数的使用技巧。Python内置函数是指已经定义好的函数&#xff0c;无需另外安装也无需导入就可以直接在Python中使用的函数。这篇文章将…

linuxOPS基础_linux文本文件查看

vi/vim vim文档编辑操作太多了,可以看这篇单独介绍vim的文章>https://blog.csdn.net/weixin_44368963/article/details/130963920 cat查看文件 命令&#xff1a;cat 作用&#xff1a;查看文件内容 语法&#xff1a;#cat 文件名称 ​ #cat 文件1 文件2 > 文件3 **特别注…

C++第六章:函数

函数 一、函数基础1.0 简介形参和实参形参列表函数的返回类型 1.1 局部对象自动对象局部静态对象 1.2 函数声明在头文件中进行函数声明 1.3 分离式编译编译和链接多个源文件 二、参数传递2.1 传值参数指针形参 2.2 传引用参数使用形参返回额外信息 2.3 const形参和实参指针或引…

javaWebssh中小学课件资源系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh中小学课件资源系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT…

rust 中protobuf生成与使用

首先创建一个项目proto 进入到这个文件夹中 创建我们的proto文件 初始化的项目结构是这个样子的 新建一个hello.proto文件内容如下 syntax "proto3";package hello;service Greeter {rpc SayHello (HelloRequest) returns (HelloReply) {} }message HelloRequest …

法规标准-ISO 20900标准解读

ISO 20900是做什么的&#xff1f; ISO 20900全名为智能交通系统-部分自动泊车系统(PAPS)-性能要求和试验程序&#xff0c;其中主要是对PAPS系统的功能要求、性能要求及测试步骤进行了介绍 PAPS类型 I类型PAPS系统反应 II类型PAPS系统反应 一般要求 运行期间的最大速度 系统…

PowerToys Windows 工具集

Microsoft PowerToys | Microsoft Learn Microsoft PowerToys&#xff1a;用于自定义 Windows 的实用工具 项目2023/04/1918 个参与者 反馈 Microsoft PowerToys 是一组实用工具&#xff0c;可帮助高级用户调整和简化其 Windows 体验&#xff0c;从而提高工作效率。 安装 …

移动端布局之流式布局1(百分比布局):流式布局基础、案例:京东移动端首页1

移动端布局之流式布局1 流式布局&#xff08;百分比布局&#xff09;基础案例&#xff1a;京东移动端首页搭建相关文件夹结构设置视口标签以及引入初始化样式normalize.css引入我们的css初始化文件与首页css body设置index.css app布局和app内容填充index.htmlindex.css 搜索模…

机器学习-4 决策树算法

决策树算法 算法概述分类算法与分类器决策树算法树模型决策树的原理决策树算法的关键决策树构造的基本思路 算法基本思想决策树的训练与测试三种经典的决策树生成算法基于信息增益的ID3算法基于信息增益率的C4.5算法C4.5算法C5.0算法 基于基尼系数的CART算法 算法流程算法关键问…

c语言之结构体(初阶)

目录 1&#xff1a;结构体类型的声明 2&#xff1a;结构体初始化 3&#xff1a;结构体成员访问 4&#xff1a;结构体传参 1&#xff1a;结构体类型的声明 1&#xff1a;为啥要有结构体&#xff0c;因为当我们描述一个复杂对象的时候&#xff0c;可能平时我们的一个类型不能…

二叉搜索树(查找、插入、删除的讲解实现+图文并茂)

目录 1. 二叉搜索树&#xff08;BST&#xff09; 1.1 二叉搜索树概念 1.2 二叉搜索树操作 1.2.1 二叉搜索树的查找 1.2.2 二叉搜索树的插入 1.2.3 二叉搜索树的删除 2. 二叉搜索树的实现 2.1BST基本结构 2.2 BST操作成员函数(非递归&#xff09; 2.3 BST操作成员函数&#x…

一起学SF框架系列4.6-模块context-AbstractApplicationContext

org.springframework.context.ApplicationContext接口表示Spring IoC容器&#xff0c;负责实例化、配置和组装bean。容器通过读取配置元数据来获取关于实例化、配置和组装哪些对象的指令。配置元数据以XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象…

在vite或者vue-cli中使用.env[mode]环境变量

在项目中总会遇到一些默认的配置,需要我们配置到静态文件中方便我们去获取,这时候就可以用到这个.env环境变量文件,在cli创建的项目中顶层的nodejs会有一个process对象,这个对象可以根据不同的环境获取不同的环境配置文件,但是vite中获取变量的方式不一样。 创建变量文件.env.…

NetApp AFF C 系列——可持续、可扩展且安全可靠的全闪存解决方案

NetApp AFF C 系列 采用全新的闪存技术&#xff0c;同时辅以智能科技加持&#xff0c;将为您带来一个更为经济实惠的全闪存解决方案&#xff0c;它重新定义了安全性、可扩展性和可持续性。 为什么选择 AFF C 系列的新一代全闪存解决方案&#xff1f; 实现现代化&#xff0c;打…

使用APIPOST 进行压力测试

使用APIPOST 进行压力测试 目录概述需求&#xff1a; 设计思路实现思路分析1.apipost 压力测试 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for c…

模拟集成电路设计-MOS器件物理基础(模集系列持续更新)

学习目的 欠缺的学习路径&#xff1a; 固体物理&#xff0c;半导体器件物理&#xff0c;器件模型&#xff0c;电路设计。所有的半导体器件都看成一个黑盒子&#xff0c;只关注端电压电流。 最佳的学习路径&#xff1a;两手抓&#xff0c;因为有些二阶效应会影响到电路本身. 本…

《Spring Guides系列学习》guide66 - guide68及小结

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gui…

Tatuk GIS Developer Kernel for .NET 11.77 Crack

Tatuk GIS Developer Kernel for .NET 是一个变体&#xff0c;它是受控代码和 .NET GIS SDK&#xff0c;用于为用户 Windows 操作系统创建 GIS 专业软件的过程。它被认为是一个完全用于 Win Forms 的 .NET CIL&#xff0c;WPF 的框架是为 C# 以及 VB.NET、VC、oxygen 以及最终与…

netty学习第一课

技术主题 Netty是一个基于Java NIO&#xff08;非阻塞 I/O&#xff09;框架的网络编程框架。它提供了一系列的高级网络编程API&#xff0c;使得开发者可以非常容易地实现高性能、高可靠性的网络应用。Netty具有非常好的可扩展性和灵活性&#xff0c;能够很好地支持多种协议和数…