【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1)

这篇具有很好参考价值的文章主要介绍了【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习

君兮_的个人主页

勤时当勉励 岁月不待人

C/C++ 游戏开发


Hello,米娜桑们,这里是君兮_,之前写了一篇有关数据结构顺序表的文章,中间引用了大量的动态内存开辟的知识,今天就来带大家详细了解一下动态内存管理这部分非常重要的知识,保证大家看了后都会对这部分有一个更加深刻的理解!
好了,废话不多说,开始今天的学习吧!

前言

  • 其实如果你想把这部分内容学好,掌握以下四个函数的使用方法就行
    【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习
  • 下面我们来依次介绍这几个函数

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

  • 在之前我们已经学会了这种开辟内存的方法:
int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间
  • 但是上述的开辟空间的方式有两个不那么好的地方:
    1. 空间开辟大小是固定的。
    2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
    但是对于空间的需求,。有时候我们需要的空间大小在程序运行的时候才能知道,这样就经常会导致我们在栈空间上开辟的空间太大了或者太小了,显然这种开辟空间的方式不太能满足我们的需求

二. malloc与free

  • 我们要知道的是,当你开辟了一块空间不再使用时,就必须把它free释放掉还给操作系统,因此,这一块我们合并到一起来讲

1.malloc

  • C语言提供了一个动态内存开辟的函数:
void* malloc (size_t size);
  • 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
    如果开辟成功,则返回一个指向开辟好空间的指针。
    如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void * ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  • 如果参数 size 为0,也就是开辟一块空间大小为0的空间,malloc的这种行为是标准是未定义的,取决于编译器。

2.free

  • C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收的,函数原型如下:
void free (void* ptr);
  • free函数用来释放动态开辟的内存。
    如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
    如果参数 ptr 是NULL指针,则函数什么事都不做。
  • malloc和free都声明在 stdlib.h 头文件中。
  • 好了,我们来结合具体例子实际来看下效果
#include <stdio.h>
#include <stdlib.h>
 int main()
{
    	//int arr[10];
    	int* p = (int*)malloc(40);//开辟40个字节的整形空间,把返回的开辟好空间的起始地址保存在p中
    
    	if (p == NULL)//判断malloc开辟内存是否成功
    	{
    		perror("malloc");//如果没成功,通过perror来报错
    		return 1;
    	}
    	//开辟成功
    	int i = 0;
    	for (i = 0; i < 10; i++)
    	{
    		printf("%d\n", *(p + i));//打印一下此时p中空间存储的内容
    	}
    
    	free(p);//用完后释放空间,把开辟的空间返回给操作系统
    	p = NULL;//将p置空
    	return 0;
 }

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习

除了注释中提到的点,还有以下几个值得注意的问题:

  • 1.与之后讲的calloc不同,malloc申请到空间后直接返回这片空间的起始地址,不会初始化空间的内容,所以结果打印的随机值是正常现象
  • 2.关于用free释放,如果你每次开辟空间在使用完后都不释放,这是典型的内存泄露。操作系统的内存空间是有限的,早晚你的操作系统的空间就会被这些已经无用的内容给占满,因此一定记得开辟完空间后在不用时使用free释放
  • 3.关于把p置为空指针这点,有些初学者可能会质疑这部分的必要性,其实这是非常有必要的,当我们用free把开辟的空间释放后,这片空间已经不属于你的p了,如果你的p依然指向这块空间,毫无疑问此时的p已经变成了野指针,是非常危险的,因此非常有必要!

三.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;
}

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习

  • 通过calloc的特点我们不难看出,calloc在某些需要我们对申请的内存空间的内容要求初始化时能发挥极大的作用

四.realloc

  • realloc函数的出现让动态内存管理更加灵活。
  • 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使用内存,我们需要对内存的大小做灵活的调整。那realloc 函数就可以做到对动态开辟内存大小的调整。
    函数原型如下:
void* realloc (void* ptr, size_t size);
  • ptr 是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
    realloc在调整内存空间的是存在以下两种情况:

1.原地扩容

  • 这种情况适用于原有空间之后有足够大的空间
  • 此时我们只需在原有空间的后面扩容,返回扩容后的空间即可

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习
扩展内存直接在原有内存之后直接追加空间,原来空间的数据不发生变化。

2.异地扩容

  • 当我们原有空间后面的空间不够时,realloc就会进行异地扩容
  • 扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习

  • 由于realloc扩容时存在两种情况,因此我们要注意以下错误
#include <stdio.h>
int main()
{
    int* ptr = (int*)malloc(100);
    if (ptr != NULL)
    {
        //业务处理
    }
    else
    {
        exit(EXIT_FAILURE);
    }
    //扩展容量
    //代码1
    ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
    //代码2
    int* p = NULL;
    p = realloc(ptr, 1000);
    if (p != NULL)
    {
        ptr = p;
    }
    //业务处理
    free(ptr);
    return 0;
}
  • 我们来对比一下以上的两段代码
  • 我们发现在代码1中如果直接把realloc的值赋给我们的ptr,如果是异地开辟的话,我们的ptr就会指向新的内存的起始地址,当此时realloc开辟失败的话,由于ptr指向发生了变化,我们就找不到之前的内存空间了,因此在使用realloc时,我们需要像代码2一样先判断一下开辟的新空间是否成功,当开辟成功时,再把realloc赋给我们的ptr。

三.常见的内存错误

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

void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
  • 如果我们malloc开辟内存失败的话,我们的p中存放的就是NULL的地址,在C语言中对NULL解引用是一种标准未定义行为,会直接导致程序报错!

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);
}


  • 非常常见的错误,我们一共就开辟了10个int型的空间,程序却走向了第11个,明显的错误。

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

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

  • 我们的p都不是动态开辟的,两个不是一个概念,不需要free。

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

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
  • 注意我们的free是不能一块一块的释放动态开辟的空间的,要释放就要释放全部动态开辟的内存。如果你想释放一部分内存,你需要重新分配一个新的内存块,并将需要保留的数据复制到新的内存块中,然后再使用函数释放原始的内存块。如下代码
#include <stdlib.h>
#include <string.h>

int main() {
    // 分配动态内存
    char* ptr = malloc(10);

    // 检查内存是否成功分配
    if (ptr == NULL) {
        // 处理内存分配失败的情况
        return 1;
    }

    // 复制数据到新的内存块
    char* newPtr = malloc(5);
    memcpy(newPtr, ptr, 5);

    // 释放原始的内存块
    free(ptr);

    // 使用新的内存块进行操作

    // 释放新的内存块
    free(newPtr);

    return 0;
}

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);
}
  • 在使用完动态开辟的空间后忘记使用free释放,这会造成严重的内存泄漏。导致这部分内存无法再被其他程序使用。可能会导致程序的内存消耗不断增加,最终导致程序崩溃或者系统变得不稳定。

总结

  • 今天的内容到这里就结束了,动态内存管理的基本知识点都在这里了,如果你能把上面的内容都学会的话,那么你就掌握了动态内存管理中的大部分内容,之后我们在为大家讲解几个有关的面试题加深大家的理解并且在介绍一下有关柔性数组的知识。

  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1),0基础C语言,c语言,c++,开发语言,学习文章来源地址https://www.toymoban.com/news/detail-626866.html

到了这里,关于【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 动态内存管理——C语言【进阶】(下)

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: 进阶C语言,本专栏主要讲解数据存储,进阶指针,动态内存管理,文件操作,程序环境和预处理等 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 请问运行Test 函数会有什

    2023年04月18日
    浏览(82)
  • 动态内存管理(C语言进阶版)

    📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 现在的偷懒会在以后还给你,只有多学多做才不负韶华,在默默无闻的地方发芽开花 我们已经掌握的

    2024年02月13日
    浏览(35)
  • 动态内存管理——C语言【进阶】(上)

    我们已经掌握的内存开辟方式有: 但是上述的开辟空间的方式有两个特点: 空间开辟大小是固定的。 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。 但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知

    2023年04月10日
    浏览(34)
  • 【C语言进阶(八)】动态内存管理

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 本章目标: 本篇文章 着重讲解动态内存 管理的四个函数 前期准备: 内存可以大致分为几个区域: 栈区: 存放局部变量,函数 堆区

    2024年02月16日
    浏览(28)
  • 【C语言】动态内存管理(C语言的难点与精华,数据结构的前置知识,你真的掌握了吗?)

    学习专栏 : 《零基础学C语言》 《数据结构世界》 俗话说的好,要想学好 数据结构 (数据结构世界,对数据结构感兴趣的小伙伴可以移步),就必须学好以下三方面知识: 指针 不允许你还不了解指针的那些事(一)(内存和地址+指针变量+指针运算+野指针+传址调用) 不

    2024年02月05日
    浏览(35)
  • 第五十三天学习记录:C语言进阶:动态内存管理Ⅰ

    问: 栈区堆区静态区的大小是固定的吗?如果栈区满了,会向后2者借位置吗? ChatAI答: 栈区、堆区和静态区的大小通常是由操作系统或编译器预定义的,不是固定的。这些区域的大小通常受到多种因素的影响,如系统物理内存大小、进程虚拟地址空间的大小、编译器和操作

    2024年02月06日
    浏览(58)
  • 第五十四天学习记录:C语言进阶:动态内存管理Ⅱ

    1、对NULL指针的解引用操作 2、对动态开辟的内存的越界访问 3、对非动态开辟内存的free 4、使用free释放动态开辟内存的一部分 5、对同一块动态内存多次释放 6、动态开辟内存忘记释放(内存泄漏) 问:realloc的第一个参数的指针地址必须是malloc或calloc创建的在堆上的地址吗?

    2024年02月06日
    浏览(29)
  • 【C进阶】-- 动态内存管理

    目录 1. 为什么存在动态内存分配❓ 2. 动态内存函数的介绍 2.1 malloc和free✅ ①申请:1️⃣ ②使用:2️⃣  ③释放:3️⃣ 2.2 calloc 🧨与malloc的区别: 2.3 realloc 3.常见的动态内存错误 3.1 对NULL指针的解引用操作 🎇3.2 对动态开辟空间的越界访问 3.3对非动态开辟内存使用free释放🍕

    2024年02月04日
    浏览(24)
  • 【进阶C语言】动态内存分配

    本章大致内容介绍: 1.malloc函数和free函数 2.calloc函数 3.realloc函数 4.常见错误案例 5.笔试题详解 6.柔性数组 1.malloc函数 (1)函数原型 函数参数: 根据用户的需求需要开辟多大的字节空间,为无符号的字节。 返回值: malloc函数成功开辟内存后,会返回该内存的起始地址,可

    2024年02月07日
    浏览(43)
  • C语言 — 动态内存管理(动态内存函数)

    本期分为三篇介绍动态内存管理相关内容,关注博主了解更多 博主博客链接:https://blog.csdn.net/m0_74014525 本期介绍动态内存函数,函数如何使用、函数格式、在使用在所需要的注意点及C/C++程序的内存开辟区域 第一篇:C语言 — 动态内存管理(动态内存函数) 第二篇:C语言

    2024年02月14日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包