C语言动态内存管理

      CSDN成就一亿技术人     

目录

一.为什么要存在动态内存分配

二.动态内存函数

1.malloc和free

2.calloc

3.realloc

三.常见的动态内存错误

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

2.对动态开辟空间的越界访问

3.对非动态开辟内存使用free释放

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

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

6.动态开辟内存忘记释放(内存泄露)

四.柔性数组

1.柔性数组的特点:

2.柔性数组的使用

3.柔性数组的优势

C/C++程序的内存开辟


 

0基础小白学C语言看这一篇就够了(C语言详讲)-CSDN博客https://blog.csdn.net/lh11223326/article/details/136971590?spm=1001.2014.3001.5501

一.为什么要存在动态内存分配

如下是之前常见的内存开辟方式:

int val=20;//在栈空间上开辟四个字节
char arr[10]={0};//在栈空间上开辟10个字节的连续空间

但上述开辟的空间有两个特点:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

对于空间的需求,不仅仅是上述的情况,有时候需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。这时候只能试试动态开辟了。

 

二.动态内存函数

1.malloc和free

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

void *malloc(size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  • 如果参数size为(),malloc的行为是标准是未定义的,取决于编译器。

C语言提供了另外一个函数free,专门是来做动态内存的释放和回收的,函数原型如下:

void free(void*ptr);

free函数用来释放动态开辟的内存。

  • 如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数ptr是NULL指针,则函数什么事都不做。

malloc和free都声明在stdlib.h头文件中。如下:

#include<stdio.h>
int main(){//代码1int num=0;scanf("%d",&num);//int arr[num]={0};//代码2int *ptr=NULL;ptr=(int*)malloc(num*sizeof(int));if(NULL!=ptr)//判断ptr指针是否为空{int i=0;for(i=0;i<num;i++){*(ptr+i)=0;}}free(ptr);//释放ptr所指向的动态内存ptr=NULL;//是否有必要return 0;
}

 

2.calloc

C语言还提供了一个函数叫calloc,calloc函数也用来动态内存分配,原型如下:

void*calloc(size_t num,size_t size);
  • 函数的功能是num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0。
#include<stdio.h>
#include<stdlib.h>
int main(){int*p=(int*)calloc(10,sizeof(int));if(NULL!=p){//使用空间}free(p);p=NULL;return 0;
}

申请的内存空间的内容要求初始化,那么可以使用calloc函数。

 

3.realloc

  • realloc函数的出现让动态内存管理更加灵活。
  • 有时候申请的空间太小了,有时候申请的空间太大了,为了合理的时候内存,要对内存的大小灵活的调整,那realloc函数就可以做到对动态开辟内存大小的调整。
  • 函数原型如:
  • void*realloc(void *ptr,size_t size);
  • ptr是要调整的内存地址
  • size调整之后新大小
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
  • realloc在调整内存空间的是存在两种情况:
  • 1.原有空间之后又足够大的空间:
  • 要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
  • 2.原有空间之后没有足够大的空间:
  • 原有空间之后没有足够多的空间时,扩展的方法是,在堆空间上另外找一个合适大小的连续空间来使用,这样函数返回的是一个新的内存地址。551690a2f5564dd094944e4411fb0159.png
  • 因为上述两个情况使用realloc函数就需要注意:
#include<stdio.h>
#include<stdlib.h>
int main() {int* ptr = (int*)malloc(100);if (ptr != NULL) {//业务}else {exit(EXIT_FAILURE);}//扩展容量//代码1ptr = (int*)realloc(ptr, 1000);//代码2int* p = NULL;p = realloc(ptr, 1000);if (p != NULL) {ptr = p;}//业务处理free(ptr);return 0;
}

 

三.常见的动态内存错误

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

void test() {int* p = (int*)malloc(INI_MAX / 4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

2.对动态开辟空间的越界访问

void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}

3.对非动态开辟内存使用free释放

void test(){int a=10;int*p=&a;free(p);
}

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

void test(){int*p=(int*)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}

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

void test(){int*p=(int*)malloc(100);free(p);free(p);//重复释放
}

6.动态开辟内存忘记释放(内存泄露)

忘记释放不再使用的动态开辟的空间会造成内存泄露。

void test(){int*p=(int*)malloc(100);if(NULL!=p){*p=20;}
}
int main(){test();while(1);}

 

 

四.柔性数组

柔性数组(flexible array)这个概念,他是存在的,C99中,结构中的最后一个元素允许是未知大小的数组,这就叫【柔性数组】成员,如

typedef struct st_type{int i;int a[];//柔性成员
}type_a;

1.柔性数组的特点:

  • 结构体中的柔性数组成员前面必须至少一个其他成员。
  • sizeof返回的这种结构大小不包括柔性数组的内存。
  • 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存大小应该大于结构的大小,以适应柔性数组的预期大小。

如:

//code1
typedef struct st_type{int i;int a[0];//柔性数组成员
}type_a;
printf("%d\n",sizeof(type_a));//输出的是4

2.柔性数组的使用

//代码1
int i = 0;
type_a* p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
//业务处理
p->i = 100;
for (i = 0; i < 100; i++)
{p->a[i] = i;
}
free(p);

这样柔性数组相当于获得了100个正行元素的连续空间。

3.柔性数组的优势

上述的type_a结构也可以设计为:

//代码2
typedef struct st_type
{int i;int* p_a;
}type_a;
type_a* p = (type_a*)malloc(sizeof(type_a));
p->i = 100;
p->p_a = (int*)malloc(p->i * sizeof(int));
//业务处理
for (i = 0; i < 100; i++)
{p->p_a[i] = i;
}
//释放空间
free(p->p_a);
p->p_a = NULL;
free(p);
p = NULL;

上述代码1和代码2可以完成同样的功能,但是方法1的实现有两个好处:

方便内存释放:

如果代码是在给别人用的函数中,在里面做了二次内存分配,并把真个结构体返回给用户,用户调用free可以释放结构体,但是用户不知道这个结构体内的成员需要free,所以不能指望他发现这件事,所以,我们把结构体的内存以及其成员的内存一次性分配好,并返回给用户一个结构体指针,用户做一次free就可以把所有内存给释放掉。

有利于访问速度:

连续的内存有益于提高访问速度,也有利于减少内存碎片。

 

扩展:

C/C++程序的内存开辟

C/C++程序内存分配的几个区域:

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

 

下篇建议

C语言结构体,联合体,枚举类型-CSDN博客https://blog.csdn.net/lh11223326/article/details/136221733?spm=1001.2014.3001.5501

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

总结虚函数表机制——c++多态底层原理

前言&#xff1a; 前几天学了多态。 然后过去几天一直在测试多态的底层与机制。今天将多态的机制以及它的本质分享给受多态性质困扰的友友们。 本节内容只涉及多态的原理&#xff0c; 也就是那张虚表的规则&#xff0c;有点偏向底层。 本节不谈语法&#xff01;不谈语法&#x…

【MySQL】InnoDB引擎

逻辑结构 InnoDB存储引擎逻辑结构如图所示&#xff1a; Tablespace&#xff1a;表空间&#xff0c;一个数据库可以对应多个表空间。数据库中的每张表都有一个表空间&#xff0c;用来存放表记录、索引等数据。 Segment&#xff1a;段&#xff0c;表空间中有多个段&#xff0c…

R语言迅速计算多基因评分(PRS)

Polygenic Risk Scores in R 最朴素的理解PRS&#xff1a; GWAS分析结果中&#xff0c;有每个SNP的beta值、se值、P值&#xff0c;因为GWAS分析中将SNP变为0-1-2编码&#xff0c;所以这些显著的SNP的beta值&#xff0c;就可以用于预测。 比如&#xff1a;GWAS分析中&#xf…

iOS开发之SwiftUI

iOS开发之SwiftUI 在iOS开发中SwiftUI与Objective-C和Swift不同&#xff0c;它采用了声明式语法&#xff0c;相对而言SwiftUI声明式语法简化了界面开发过程&#xff0c;减少了代码量。 由于SwiftUI是Apple推出的界面开发框架&#xff0c;从iOS13开始引入&#xff0c;Apple使用…

成为创作者的第 730 天——创作纪念日

​​ 文章目录 &#x1f4e8; 官方致信&#x1f3af;我的第一篇文章&#x1f9e9; 机缘与成长 &#x1f3af; 成就&#x1f3af; 目标 &#x1f4e8; 官方致信 今天早上打开 CSDN 私信一看&#xff0c;看到了这一条消息&#xff0c;然后看了下日期。突然感慨到&#xff0c;是…

基于NetCoreServer的WebSocket客户端实现群播(学习笔记)

一、NetCoreServer介绍 超快速、低延迟的异步套接字服务器和客户端 C# .NET Core 库&#xff0c;支持 TCP、SSL、UDP、HTTP、HTTPS、WebSocket 协议和 10K 连接问题解决方案。 开源地址&#xff1a;https://github.com/chronoxor/NetCoreServer 支持&#xff1a; Example: TC…

Java中的代理模式(动态代理和静态代理)

代理模式 我们先了解一下代理模式&#xff1a; 在开发中&#xff0c;当我们要访问目标类时&#xff0c;不是直接访问目标类&#xff0c;而是访问器代理类。通过代理类调用目标类完成操作。简单来说就是&#xff1a;把直接访问变为间接访问。 这样做的最大好处就是&#xff1a…

基于Spring Boot网络相册设计与实现

摘 要 网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&am…

在微信小程序中或UniApp中自定义tabbar实现毛玻璃高斯模糊效果

backdrop-filter: blur(10px); 这一行代码表示将背景进行模糊处理&#xff0c;模糊程度为10像素。这会导致背景内容在这个元素后面呈现模糊效果。 background-color: rgb(255 255 255 / .32); 这一行代码表示设置元素的背景颜色为白色&#xff08;RGB值为0, 0, 0&#xff09;&a…

第八节:深入讲解SMB中的Http组件

一、概述 Http组作是SMB中的核心组件之一&#xff0c;在第七节中讲解了如何简洁的进行web程序部署和运行&#xff0c;这只是它的功能之一。在本节中&#xff0c;我们将介绍Http组件的重要属性。 二、请求头Request 1、支持方法 支持POST、GET、PUT、DELETE、OPTIONS等方法&a…

uniapp ios证书失效

前面是按照网上查找的方法 作者大大的地址 1、一个ios账户&#xff08;688付费版&#xff09; 2、登录 Apple Developer 3、创建Identifiers ps&#xff1a;创建时需继承苹果的sdk&#xff0c;只需要一个就行 点击continue再点击Register即可 4、创建.cer证书 &…

DP:斐波那契数列模型

创作不易&#xff0c;感谢三连支持 &#xff01; 斐波那契数列用于一维探索的单峰函数之中&#xff0c;用于求解最优值的方法。其主要优势为&#xff0c;在第一次迭代的时候求解两个函数值&#xff0c;之后每次迭代只需求解一次 。 一、第N个泰波那契数 . - 力扣&#xff08;…

AnyGo for Mac最新激活版:位置模拟软件打破地域限制

AnyGo for Mac&#xff0c;一款专为Mac用户打造的位置模拟软件&#xff0c;让您能够轻松打破地域限制&#xff0c;畅享无限可能。 软件下载&#xff1a;AnyGo for Mac v7.0.0最新激活版 通过AnyGo&#xff0c;您可以随时随地模拟出任何地理位置&#xff0c;无论是国内热门景点还…

Word2vec学习笔记

&#xff08;1&#xff09;NNLM模型&#xff08;神经网络语言模型&#xff09; 语言模型是一个单纯的、统一的、抽象的形式系统&#xff0c;语言客观事实经过语言模型的描述&#xff0c;比较适合于电子计算机进行自动处理&#xff0c;因而语言模型对于自然语言的信息处理具有重…

【Unity】uDD插件抓屏文字显示不清晰怎么办?

【背景】 之前介绍过用一款简称uDD&#xff08;uDesktopDuplication&#xff09;的开源插件抓取电脑桌面。整体效果不错&#xff0c;看电影很流畅。但是当切换到文档&#xff0c;或者仔细看任何UI的文字部分时&#xff0c;发现就模糊了。 【分析】 由于是依托于Canvas上的Te…

【vue3学习之路(一)】

文章目录 前言一、vue3项目创建1.1环境准备1.1.1 基于 vue-cli 创建&#xff08;脚手架创建&#xff09;1.1.2 基于 vite 创建&#xff08;推荐&#xff09; 二、熟悉流程总结 前言 参考视频&#xff1a;https://www.bilibili.com/video/BV1Za4y1r7KE?p10&spm_id_frompag…

怎么压缩动图的大小?gif图片过大怎么压缩?动图压缩不求人

工作中&#xff0c;大家都可能会遇到处理GIF图片的情况。 比如&#xff1a; 1.网站 网页上如果有一大堆图片&#xff0c;一定要处理动图&#xff08;它容量太大了&#xff09;。 因为这玩意多了很卡&#xff0c;使网页加载速度慢。 2.公众号 公众号上传动图和整篇推文是有…

4.1.1 SN74LVC245A型总线收发器

SN74LVC245A是德州仪器(Texas Instruments)推出的一款集成电路芯片,属于SN74系列。它是一款双向总线驱动器,可用于高速CMOS逻辑电平之间的电平转换。这款芯片可以实现3.3V/5V逻辑电平之间的转换,具有高速和低功耗的特点。SN74LVC245A在电子系统中常用于数据总线的电平转换…

QT_day3:2024/3/22

作业1&#xff1a;设计界面 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin…

Python库xarray:强大的多维数据处理工具

Python库xarray&#xff1a;强大的多维数据处理工具 在数据科学和科学计算领域&#xff0c;处理多维数据是一项常见而重要的任务。Python库xarray是一个功能强大的工具&#xff0c;专门用于处理、分析和可视化多维数据集。本文将深入介绍xarray库的特性、用法和优势&#xff0c…