深入了解C语言的动态内存管理

目录
  • 一、为什么会存在动态内存
  • 二、动态内存函数
    • 1.malloc和free
    • 2.calloc
    • 3.realloc
  • 三、动态内存函数常见错误
    • 2.对NULL指针进行解引用操作
    • 3.使用free释放一块动态开辟内存的一部分
    • 4.对静态内存进行free释放
    • 5.对同一内存空间多次释放
    • 6.动态开辟空间忘记释放
  • 四、经典笔试题
    • 1.笔试1
    • 2.笔试2
    • 3.笔试3
  • 总结

一、为什么会存在动态内存

int data=20;//在栈空间上开辟4个字节空间
char ch[5]={0};//在栈开辟5个字节连续空间

上面展示的即为我们正常开辟固定的内存空间,它有两个方面的特点

1.内存空间所占大小是固定的,不能改变的。

2.创建数组时,必须指明长度大小,在编译时内存进行分配。

很显然静态分配内存分配在一些场景,就暴露出它的弊端。如果在开发之前,我们不知道空间的需求,我们有时只有在程序运行的时候才能知道自己所需要空间大小,这时候我们只能使用动态分配内存了。

二、动态内存函数

1.malloc和free

malloc函数的参数只有一个size_t size,向内存申请一块连续可用的空间,有几点需要注意

1.如果开辟成功的话,返回指向开辟好空间的指针

2.如果开辟失败的话,则返回NULL,因此每次开辟空间之后,都要进行检查

3.malloc函数未定义返回类型,一切由使用者自己使用

4.需引用stdlib.h头文件

free函数是和malloc配套使用的,每次在堆开辟动态空间后,程序结束之前,必须进行空间释放,不然会出现动态空间泄露,在使用free时,仍需要注意几点

1.如果指针指向的空间不是动态开辟的,不能用free进行释放

2.如果指针指向的是null指针,则free函数什么事都不做

3.free不能多次使用

4.需引用stdlib.h头文件

代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	int* src = NULL;
	src = (int*)malloc(40);//开辟40字节动态内存
	if (src == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	free(src);//进行动态内存释放
	src = NULL;
	return 0;
}

相信有人会问,不是已经对动态内存进行释放,为什么还要令指针等于NULL,我们调试一把。

这里我们可以发现,虽然动态内存进行free释放,但指针仍然指向被释放的动态内存的地址,如果不置空,就会造成野指针,非法访问的问题。

2.calloc

calloc和malloc最大的区别就是,malloc只负责对内存进行动态开辟,但calloc不仅开辟,还进行初始化。

代码如下(示例):

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	int* src = (int*)calloc(10, sizeof(int));
	if (src == NULL)
		{
	      printf("%s", strerror(errno));
	      return 1;
		}
	free(src);//进行动态内存释放
	src = NULL;
	return 0;
}

我们调试一把可以发现,calloc在开辟空间时同时进行了初始化。所以如何我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。

3.realloc

当我们一次开辟动态内存不够大的时候,realloc让动态内存更加的灵活。realloc几个参数:

1.第一个参数为要调整内存的地址

2.调整后大小

3.调整后内存的起始位置

为什么还要返回调整后内存的地址,不是直接就开辟好了吗?其实reallloc函数在开辟时有以下两种情况:

1.原来的内存之后空间是足够的,则直接开辟

2.原来的内存之后空间不够用。

我们画图刨析一下

情况1:直接追加空间,原来数据不变

情况2:没有足够的空间,在堆上找一个大小合适的连续空间。所以函数返回的是一个新的内存地址。

代码如下(示例)

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	int* src = NULL;
	src = (int*)malloc(40);//开辟40字节动态内存
	if (src == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	src = realloc(src, 80);
	if (src == NULL)
	{
		printf("%s", strerror(errno));
		return 1;
	}
	free(src);//进行动态内存释放
	src = NULL;
	return 0;
}

三、动态内存函数常见错误

1.动态内存越界访问

void test1()
{
	int* src = (int*)malloc(20);
	if (NULL == src)
	{
		return 1;
	}
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		(*src+i)=i
	}
	free(src);
	src = NULL;
}

在这里我们malloc只开辟了20个字节,但(*src+5)造成了越界访问

2.对NULL指针进行解引用操作

void test2()
{
	int* src = (int*)malloc(INT_MAX);//此处INT_MAX为int的最大值
	*src = 10;//如果src是NULL时,无法解引用
	free(src);
	return 0;
}

这里未对开辟的动态内存空间进行是否为空的判断,当为空时,解引用就会出现错误。

3.使用free释放一块动态开辟内存的一部分

void test3()
{
	int* src = (int*)malloc(40);
	int i=0;
	for(i=0;i<6;i++)
	{
	*(src+i)=i;
	src++;
	}
	free(src);//此时src不指向起始位置
}

因为指针指向的地址发生变化,不在指向起始未知,进行free释放是非常危险的。

4.对静态内存进行free释放

void test4()
{
	int a = 20;
	int* src = &a;
	free(src);
}

5.对同一内存空间多次释放

void test5()
{
	int* src = (int*)malloc(40);
	free(src);
	free(src);//多次释放
}

第一个free已经将堆空间的动态内存进行释放,此时src已经是一个野指针,在进行释放是十分危险的。

6.动态开辟空间忘记释放

void test6()
{
	int* src = (int*)malloc(40);
	if (src != NULL)
	{

	}
	while (1);
}

在开辟动态内存之后,一直进行while循环,为进行free释放,会造成内存泄漏。

四、经典笔试题

1.笔试1

void test(char* src)
{
	src = (char*)malloc(30);
}
int main()
{
	char* src = NULL;
	test(src);
	strcpy(src, "wo yao jin da chang");
	printf(src);
	free(src);
}

这里会输出wo yao jin da chang 吗?

这里很明显,src仍然是NULL,所以无法输出wo yao jin da chang

2.笔试2

char* test()
{
	char arr[] = "wo yao jin da chang";
	return arr;
}
int main()
{
	char* src = NULL;
	src = tset();
	printf(src);
	return 0;
}

这里会输出wo yao jin da chang 吗?

这里test函数确实把字符串地址传给了src,但是字符串是局部变量,当函数执行完之后,就销毁了,所以src输出的内容是随机的。

3.笔试3

void test()
{
	char* src = (char*)malloc(50);
	if (src != NULL)
	{
		strcpy(src, "wo yao jin da chang");
	}
	free(src);
	if (src != NULL)
	{
		strcpy(src, "taijuanlebujinle");
		printf(src);
	}
}

这里会输出taijuanlebujinle 吗?

这里对动态内存释放后,继续进行赋值,对野指针进行了访问是错误的。

总结

看到这里大家对动态内存管理已经有了一定的认识,应该特别注意这几点,在进行动态内存开辟之后进行判断是否为空,使用完后进行free释放,并且置空,防止动态内存泄露,只要记住这几点基本就可以很好的使用动态内存了。

以上就是深入了解C语言的动态内存管理的详细内容,更多关于C语言动态内存管理的资料请关注我们其它相关文章!

(0)

相关推荐

  • 超详细分析C语言动态内存管理问题

    目录 一.为什么存在动态内存的分配 二.动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 三.常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 对同一块动态内存多次释放 3.5 动态开辟内存忘记释放(内存泄漏) 四.几个经典的笔试题 五.C/C++程序的内存开辟 六.柔性数组 6.1 柔性数组的特点 6.2 柔性数组的使用 6.3 柔性数组的优势 上期结束了[

  • C语言中动态内存管理图文详解

    目录 1.动态内存开辟的原因 2.动态内存函数的介绍 2.1malloc和free 2.2calloc 2.3realloc 3.常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟内存使用free 3.4使用释放一块动态开辟内存的一部分 3.5对同一块动态内存多次释放 3.6动态开辟内存忘记释放(内存泄漏) 4.练习 4.1练习1 4.1练习2 4.3练习3 4.4练习4 5.C/C++程序的内存开辟 总结 1.动态内存开辟的原因 常见的内存

  • 详解C语言之动态内存管理

    目录 开辟动态内存的函数 释放开辟的动态内存空间的函数 错误信息函数 具体使用例: 常见的动态内存错误 总结 先来了解一下动态管理内存所需用到的函数 开辟动态内存的函数 1.malloc函数:void* malloc(size_t size); 功能:开辟一块大小为size单位为字节的动态空间.若开辟成功返回函数开辟空间的无类型指针,若开辟失败则返回空指针NULL 2.calloc函数: void* calloc(size_t num, size_t size); 功能:开辟一块能容纳下num个

  • C语言动态内存管理的实现

    目录 1. 摘要 2. 为什么存在动态内存管理 3. 动态内存函数 3.1 malloc 3.2 free 3.3 calloc 3.4 realloc 4. 常见的动态内存错误 5. 几个经典笔试题 参考答案 6. 参考文献 1. 摘要 本文主要详解C语言中的动态内存分配 2. 为什么存在动态内存管理 我们先来看一段变量的声明: double x = 1.000000; char str[] = "abcdef"; 好的,上述变量的声明有何特点呢? 请思考一下,我的朋友. 对,没错,

  • C语言动态内存管理深入探讨

    目录 1.动态内存开辟的原因 2.动态内存函数的介绍 2.1malloc和free 2.2calloc 2.3realloc 3.常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟内存使用free 3.4使用释放一块动态开辟内存的一部分 3.5对同一块动态内存多次释放 3.6动态开辟内存忘记释放(内存泄漏) 4.练习 4.1练习1 4.1练习2 4.3练习3 4.4练习4 5.C/C++程序的内存开辟 1.动态内存开辟的原因 常见的内存开辟方

  • C语言深入细致讲解动态内存管理

    目录 为什么存在动态内存管理 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free访问 使用free 释放一块动态开辟内存的一部分 对一块动态内存多次释放 对动态内存开辟忘记释放 柔性数组 小结 为什么存在动态内存管理 我们已经掌握的内存开辟方式有: int val = 20;//在栈空间上开辟四个字节 char arr[10] = { 0 };//在栈空间上开辟10个字节

  • C语言初识动态内存管理malloc calloc realloc free函数

    目录 一.为什么存在动态内存分配 二.动态内存函数的使用 1.malloc函数 (1)malloc的定义 (2)malloc函数的注意事项 (3)malloc函数的使用 2.calloc函数 (1)calloc函数的定义 (2)calloc函数的注意事项 (3)calloc函数的使用 3.realloc函数 (1)realloc函数的定义 (2)realloc函数的注意事项 (3)realloc函数的使用 总结 一.为什么存在动态内存分配 在c语言中我们目前掌握的内存开辟方式有: int val

  • 深入了解C语言的动态内存管理

    目录 一.为什么会存在动态内存 二.动态内存函数 1.malloc和free 2.calloc 3.realloc 三.动态内存函数常见错误 2.对NULL指针进行解引用操作 3.使用free释放一块动态开辟内存的一部分 4.对静态内存进行free释放 5.对同一内存空间多次释放 6.动态开辟空间忘记释放 四.经典笔试题 1.笔试1 2.笔试2 3.笔试3 总结 一.为什么会存在动态内存 int data=20;//在栈空间上开辟4个字节空间 char ch[5]={0};//在栈开辟5个字节连

  • 详解C语言中动态内存管理及柔性数组的使用

    目录 一.malloc 二.free 三.calloc 四.realloc 1.realloc在扩容时的情况 2.realloc也能实现malloc功能 五.使用动态内存的常见错误 1.free空指针 2.对动态开辟的空间越界访问 3.对非动态开辟内容free 4.只free动态开辟空间的一部分 5.对同一块内存多次free 6.动态内存空间忘记释放(内存泄漏) 六.柔性数组 1.柔性数组的概念 2.柔性数组的特点 3.柔性数组的使用场景 4.柔性数组的优点 一.malloc 这个函数向堆区申请

  • C语言的动态内存管理你了解吗

    目录 C/C++内存分配方式 C++内存管理方式 new和delete的使用 new和delete的骚操作 new和delete的区别 重载new和delete 定位new表达式 内存泄露 总结 C/C++内存分配方式 在学习C语言阶段的时候,创建一个变量,编译器会为它分配一块内存.而创建一个C++对象的时候,编译器会为这个对象分配内存,并且调用合适的构造函数进行初始化. 那么编译器的内存分配方式是怎样的呢? 内存分配可以有以下的几种方式 从静态存储区分配.这样的分配方式在程序开始前就可以为对象

  • C语言的动态内存管理的深入了解

    目录 一.动态内存分配 二.动态内存分配函数 1.malloc() 2.realloc() 3.calloc() 三.用free函数释放内存 四.迷途指针 总结 一.动态内存分配 (1)用malloc类的函数分配内存: (2)用这些内存支持应用程序: (3)用free函数释放内存. 内存的简答来说的三大操作:分配----使用----释放 内存管理指的是:分配— ----释放 我们编写的程序代码:使用 程序本质上就是处理数据,数据信息需要存放在内存里,就是用二极管表示的开断表示二进制数,进一步用二

  • C++动态内存管理详解

    目录 1.C/C++程序地址空间 2.C语言动态内存管理 (1)malloc (2)calloc (3)realloc (4)free 3.C++动态内存管理 (1)C++为什么要设计一套自己专属的动态内存管理方式? (2)new/delete定义 1)new/delete操作内置类型 2)new/delete操作自定义类型 (3)new/delete的实现原理 4.malloc/free和new/delete的区别 共同点: 不同点: 5.内存泄漏 总结 1.C/C++程序地址空间 计算机物理

  • 一文详解C++中动态内存管理

    目录 前言 1.C/C++程序的内存开辟 2.C语言中动态内存管理方式:malloc/calloc/realloc/free 2.1malloc.calloc.realloc区别? 3.C++内存管理方式 3.1 new/delete操作内置类型 3.2 new和delete操作自定义类型 3.3new和malloc处理失败 4.operator new与operator delete函数 4.1 operator new与operator delete函数 4.1.1 我们看看operator

随机推荐