C语言动态开辟内存详解

目录
  • 1.动态内存管理
  • 2.动态开辟内存函数的介绍
    • 2.1malloc和free函数
    • 2.2calloc函数
    • 2.3relloc函数
  • 总结

1.动态内存管理

我们已经掌握的内存开辟方法,用的最多的就是数组,但是首先我们知道数组实在栈上开辟空间的,要是我们开辟大量的空间怎么办呢?而且我不确定数据的大小万一造成内存资源浪费是不是也不划算呢?所以我认为一下两点就很充分的说明动态开辟内存存在的必要性。

1.一般方式(栈上开辟)只能自动开辟少量的空间,但是堆上可以开辟大量的空间。

2.对于不定长数据保存问题,动态开辟空间可以解决。

2.动态开辟内存函数的介绍

2.1 malloc和free函数

C语言提供了一个动态开辟内存的函数。

void* malloc (size_t size);

C语言还提供了一个函数free是对动态开辟内存释放和回收的。

void free (void* ptr);

这两个函数都声明在stdlib.h这个头文件中

那如何进行内存的开辟与释放呢?举个例子。

int main() {
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p) {
		return 1;
	}
	free(p);
}

1.malloc 等空间申请都是在堆上进行申请,最后必须由free来进行释放。堆上的空间是由程序员自己管理。

2.malloc是一个函数,表明了堆空间说在程序运行起来之后,再在系统上申请的,空间只申请不释放,会造成内存泄露问题!

3.那free是做了什么呢?他是把开辟的空间给清除了?还是把指针给清空了?

其实都不是,free做的是取消了指针和所对应内存的指向 “关系”。

在实际申请空间的时候,真实给你的空间是要大于你所需要的,但是你只能使用你要的大小,多出来的字节,用来维护刚刚说的那种关系,以及保存该次申请的 元数据(属性数据):用户申请的空间有多大,所以在free传参的时候只用传入你开辟空间的起始地址就好了,根据属性数据free函数就知道该释放多少空间。

4.那我不想释放那么多可以吗?我按照以下代码free。

free(p+4);

是不行的!堆空间必须整体申请整体释放。

2.2 calloc函数

C语言还提供了一个函数calloc

void* calloc(size_t num, size_t size );

calloc跟malloc使用基本一样

只是有一点区别,malloc没做初始化,随机值,malloc效率更高一点。calloc做了初始化,效率更低一点。

2.3 relloc函数

C语言提供的这个函数让动态内存管理更加的灵活,有时候发现申请的空间太小了,有时候觉得申请的空间太大了,合理调整内存就有了relloc函数。

void* relloc (void* ptr,size_t size);

ptr是调整内存的地址,size是调整后的大小,返回值是调整之后内存的起始地址。

一般relloc在调整内存是存在两种情况

1.原有空间后面有足够大的空间

直接向后扩充就好了

2.原有空间后面没有足够大的空间

所以说ptr也就是堆空间的起始地址有可能是变化的!

最后在分享一个题

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
int main ()
{
    char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

这个打印的是啥呢?

其实是有错误的 str传入函数发生临时拷贝问题此时p和str不是一个东西进行动态内存开辟让我们的p指向开辟的空间,调用函数开辟栈帧,调用完毕释放栈帧,p是一个临时变量于那个空间已经没有指向关系了,而str依旧是NULL

更改如下

void GetMemory(char** p)
{
	*p = (char*)malloc(100);
}
int main()
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");
	printf(str);
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言编程动态内存开辟实现升级版通讯录教程示例

    目录 前言 一.存放联系人信息 二.通讯录初始化 三.增加联系人 四.销毁通讯录 后记 前言 所谓动态内存开辟的通讯录,就是我需要多少联系人,就给多少联系人,防止给定一个联系人上限,需要增加联系人无法扩容,而联系人没有上限那么多又会造成内存浪费. 本文继之前的静态通讯录作出改进,有兴趣的同学可以看看之前的文章:C语言实现静态通讯录 一.存放联系人信息 这里是用struct PeoInfodata结构体指针指向通讯录,而不再直接 struct PeoInfo data[Max] 用结构体数组定义通

  • 详解C语言动态内存的分配

    目录 C 程序中,不同数据在内存中分配说明 内存动态分配的相关函数 应用实例 动态分配内存的基本原则 总结 C 程序中,不同数据在内存中分配说明 1)全局变量——内存中的静态存储区 2)非静态的局部变量——内存中的动态存储区——stack 栈 3)临时使用的数据—建立动态内存分配区域,需要时随时开辟,不需要时及时释放——heap 堆 4)根据需要向系统申请所需大小的空间,由于未在声明部分定义其为变量或者数组,不能通过变量名或者数组名 来引用这些数据,只能通过指针来引用) 内存动态分配的相关函数

  • C语言 动态内存管理全面解析

    目录 1. 为什么存在动态内存分配 2. 动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开辟内存的一部分 3.5 对同一块动态内存多次释放 1. 为什么存在动态内存分配 *动态内存开辟在堆区* 我们已经掌握的开辟内存方式是类型直接定义变量,开辟的内存是固定的,像: int a=

  • python中的变量如何开辟内存

    python下的变量 不需要预先声明变量的类型,变量的类型和值在赋值的那一刻被初始化(声明和定义的过程一起完成) 在python中, 每一个变量在内存中创建,我们可以通过变量来查看内存中的值 哈哈,这里是不是很熟悉,跟c中的指针一样啊(访问内存中的值) 首先大家需要了解一点:在python中: x =5之后,我们要了解它的过程:系统先是找了一块内存,将5存储了进去,紧接着x指向了当前的这块内存 预测1:python下的变量是一个指针 >>> x = 4 >>> y =

  • 关于C语言动态内存管理介绍

    目录 1.为什么需要动态内存分配 2.有关动态内存函数介绍 2.1 malloc和free 2.2 calloc函数 2.3 realloc函数 3. 常见的动态内存错误 3.1 对NULL指针进行解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开辟内存的一部分 3.5 对同一块动态内存多次释放 3.6 动态开辟内存忘记释放(内存泄漏) 总结 1.为什么需要动态内存分配 关于这个问题,我们先看看我们之前是如何开辟内存的. i

  • C语言动态开辟内存详解

    目录 1.动态内存管理 2.动态开辟内存函数的介绍 2.1malloc和free函数 2.2calloc函数 2.3relloc函数 总结 1.动态内存管理 我们已经掌握的内存开辟方法,用的最多的就是数组,但是首先我们知道数组实在栈上开辟空间的,要是我们开辟大量的空间怎么办呢?而且我不确定数据的大小万一造成内存资源浪费是不是也不划算呢?所以我认为一下两点就很充分的说明动态开辟内存存在的必要性. 1.一般方式(栈上开辟)只能自动开辟少量的空间,但是堆上可以开辟大量的空间. 2.对于不定长数据保存问

  • java语言注解基础概念详解

    1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃: 2.RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期: 3.RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在: 这3个生命周期分别对应于:Java源文件(.java文件)--->.class文件--->内存中的字节码.

  • C语言 动态分配数组案例详解

    目录 一维动态数组的创建: 二维数组的创建: 很多人在编写C语言代码的时候很少使用动态数组,不管什么情况下通通使用静态数组的方法来解决,在当初学习C语言的时候我就是一个典型的例子,但是现在发现这是一个相当不好的习惯,甚至可能导致编写的程序出现一些致命的错误.尤其对于搞嵌入式的人来所,嵌入式系统的内存是宝贵的,内存是否高效率的使用往往意味着嵌入式设备是否高质量和高性能,所以高效的使用内存对我们来说是很重要的.那么我们在自己编写C语言代码的时候就应该学会使用动态数组,这也就是我这篇博客要给大家讲的,

  • C语言数据的存储详解

    目录 数据类型的介绍 整形 浮点型 构造类型 指针类型 void空类型 整数在内存中的存储 原反补的介绍 大小端的介绍 面试例题 练习 浮点数在内存中的存储 存储规则讲解 举例 IEEE754的特别规定 案例 float用%d打印的特例讲解 数据类型的介绍 数据类型存在的意义 为变量开辟的空间大小(大小决定了使用范围) 取数据的时候按照什么格式取出(先看大小端,在看数据类型(用来解析二进制数据的方式)) 整形 char unsigned char signed char short unsign

  • C语言指针教程示例详解

    目录 指针 内存 指针类型 指针运算 二级指针 指针数组 指针 指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作.另外,通过指针可以更便捷地操作数组.在一定意义上可以说,指针是 C 语言的精髓. 概念解释就不去搬原定义了,又臭又长不好理解,精炼两点就是: 1.指针是内存中的一个最小单元的编号,也就是地址: 2.平时我们说的指针,通常是指指针变量,用来存储内存地址的变量 也就是说:指针就是地址,口语中指针通常是指针变量 内存 要搞明白指针首先要搞

  • Golang 动态脚本调研详解

    目录 一.技术背景 1.1 程序的动态链接技术 1.1.1 动态链接库 1.1.2 动态共享对象 1.1.3 非编译语言的动态技术 1.2 Golang 的动态技术 二.Golang 的第三方解释器(Yaegi) 2.1 使用场景 2.1.1 内嵌解释器 2.1.2 动态扩展框架 2.1.3 命令行解释器 2.2 数据交互 2.2.1 数据输入 2.1.2 数据输出 三.实现原理 3.1 AST - 抽象语法树 3.1.1 抽象语法树示例 3.1.2 执行抽象语法树 一.技术背景 1.1 程序的

  • MyBatis 执行动态 SQL语句详解

    大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: <select id="executeSql" resultType="map"> ${_parameter} </select> 你可以如下调用: sqlSession.selectList("executeSql", "select * from sysuser where enabled

  • C#动态对象(dynamic)详解(实现方法和属性的动态)

    C#的动态对象的属性实现比较简单,如果要实现动态语言那种动态方法就比较困难,因为对于dynamic对象,扩展方法,匿名方法都是不能用直接的,这里还是利用对象和委托来模拟这种动态方法的实现,看起来有点javascript的对象味道: 1) 定义一个委托,参数个数可变,参数都是object类型:这里的委托多有个dynamic参数,代表调用这个委托的动态对象本身. public delegate object MyDelegate(dynamic Sender, params object[] PMs

  • Spring静态代理和动态代理代码详解

    本节要点: Java静态代理 Jdk动态代理 1 面向对象设计思想遇到的问题 在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能或相同特征的属性抽象到一个层次分明的类结构体系中.随着软件规范的不断扩大,专业化分工越来越系列,以及OOP应用实践的不断增多,随之也暴露了一些OOP无法很好解决的问题. 现在假设系统中有三段完全相似的代码,这些代码通常会采用"复制"."粘贴"方式来完成,通过这种方式开发

  • C++中静态初始化数组与动态初始化数组详解

    静态初始化的数组的长度必须是在程序中确定的常数,不能是由用户输入的变量 例子: int a[10];//正确 Student stud[10];//正确:Student是一个学生类 int n;cin>>n;int a[n];//错误 int n;cin>>n;Student stud[n];//错误:Student是一个学生类 动态初始化数组可以使用用户输入的变量作为数组的长度. 例子: int n; cin>>n; int *a=new int[n];//这样整数数

随机推荐