C语言:动态内存(一篇拿捏动态内存!)

这篇具有很好参考价值的文章主要介绍了C语言:动态内存(一篇拿捏动态内存!)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C语言:动态内存(一篇拿捏动态内存!),C语言基础整理,c语言,开发语言,c++,算法,柔性数组,学习方法,深度学习

目录

学习目标: 

为什么存在动态内存分配 

动态内存函数:

1. malloc 和 free

2. calloc

3. realloc

常见的动态内存错误:

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

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

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

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

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

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

程序的内存开辟:

柔性数组:

柔性数组的使用:

柔性数组的优势:

 以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!


学习目标: 

为什么存在动态内存分配?
动态内存函数的介绍:
1、malloc;
2、free;
3、calloc;
4、realloc;
5、常见的动态内存错误;
6、内存开辟;
6、柔性数组。

为什么存在动态内存分配 

一般的开辟空间的方式有两个特点:

1. 空间开辟大小是固定的。
2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配
        由于对空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道, 那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。

动态内存函数:

1.malloc和free

void*  malloc (size_t size);
        
         size:内存块的大小(以字节为单位)。是无符号整型。 size_t
1.1 这个函数向内存申请一块 连续可用 的空间,并返回指向这块空间的指针。
1.2 如果开辟成功,则返回一个指向开辟好空间的指针
      如果开辟失败,则返回一个 NULL 指针,因此 malloc 的返回值 一定要做检查。
1.3 返回值的类型是 void* ,所以 malloc 函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
1.4 如果参数 size 0 malloc 的行为是标准是未定义的,取决于编译器。

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

void  free (void* ptr);
        
         ptr:指向先前分配有的内存块的指针。
1.1 free 函数用来释放动态开辟的内存
1.2 如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的。
1.3 如果参数 ptr NULL 指针,则函数什么事都不做
1.4 malloc和free都声明在 stdlib.h 头文件中。
#include <stdio.h>

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

2. calloc

void* calloc (size_t num, size_t size);
        
        num:要分配的元素数。
        size:每个元素的大小。
2.1 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且 把空间的每个字节初始化为0。
2.2 与函数 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;
}

3.realloc

        有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
void*  realloc (void* ptr, size_t size);
        
        ptr:指向先前分配有的内存块的指针。或者这可以是一个 空指针,在这种情况下,将分配一个新块(就像被调用一样)。
        size:内存块的新大小(以字节为单位)。是无符号整型。 size_t
3.1 ptr 是要调整的内存地址。
3.2 size 调整之后新大小。
3.3 返回值为调整之后的内存起始位置。
3.4 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 的空间。
3.5 realloc 在调整内存空间的是存在两种情况:
        情况1 :原有空间之后有足够大的空间
                要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
        情况2 :原有空间之后没有足够大的空间
               原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
#include <stdio.h>
int main()
{
     int *ptr = (int*)malloc(100);
     if(ptr != NULL)
     {
         //业务处理
     }
     else
     {
         exit(EXIT_FAILURE);    
     }
     //扩展容量
     //ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
 
     int*p = NULL;
     p = realloc(ptr, 1000);
     if(p != NULL)
     {
         ptr = p;
     }
     
     free(ptr);
     return 0;
}

常见的动态内存错误:

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

void test()
{
     int *p = (int *)malloc(INT_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);//ok?
}

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();
     return 0;
}

程序的内存开辟:

C语言:动态内存(一篇拿捏动态内存!),C语言基础整理,c语言,开发语言,c++,算法,柔性数组,学习方法,深度学习

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

柔性数组:

typedef struct st_type
{
        int i ;
        int a []; // 柔性数组成员
} type_a ;
有些编译器会说上述定义错误,可改成:
typedef struct st_type
{
        int i ;
        int a [ 0 ]; // 柔性数组成员
} type_a ;
1.1 结构中的柔性数组成员前面必须至少一个其他成员。
1.2 sizeof 返回的这种结构大小不包括柔性数组的内存。
1.3 包含柔性数组成员的结构用 malloc () 函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
typedef struct st_type
{
int i ;
int a [ 0 ]; // 柔性数组成员
} type_a ;
printf ( "%d\n" , sizeof ( type_a )); // 输出的是 4

柔性数组的使用:

int i = 0;
//这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
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);

柔性数组的优势:

第一个好处是: 方便内存释放
        如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处是: 这样有利于访问速度.
        连续的内存有益于提高访问速度,也有益于减少内存碎片(开辟的空间中间的间隔内存没有被利用)。

 以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!

                                              C语言:动态内存(一篇拿捏动态内存!),C语言基础整理,c语言,开发语言,c++,算法,柔性数组,学习方法,深度学习文章来源地址https://www.toymoban.com/news/detail-692004.html

到了这里,关于C语言:动态内存(一篇拿捏动态内存!)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【字节跳动青训营】后端笔记整理-1 | Go语言入门指南:基础语法和常用特性解析

    **本人是第六届字节跳动青训营(后端组)的成员。本文由博主本人整理自该营的日常学习实践,首发于稀土掘金:🔗Go语言入门指南:基础语法和常用特性解析 | 青训营 本文主要梳理自 第六届字节跳动青训营(后端组)-Go语言原理与实践第一节(王克纯老师主讲) 。同时

    2024年02月13日
    浏览(52)
  • C语言数据在内存中的存续:一篇文章让你秒懂基础!

    JAMES别扣了-CSDN博客 💕在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. 😍希望我的文章对大家有着不一样的帮助,欢迎大家关注我,我也会回关,大家一起交流一起互动,感谢大家的多多支持哈! 🎉欢迎

    2024年04月13日
    浏览(37)
  • C语言:字符函数和字符串函数(一篇拿捏字符串函数!)

    目录 求字符串长度: 1. strlen(字符串长度) 长度不受限制函数: 2. strcpy(字符串拷贝) 3. strcat(字符串追加) 4. strcmp(字符串比较) 长度受限制函数: 5. strncpy(字符串拷贝) 6. strncat(字符串追加) 7. strncmp(字符串比较) 字符串查找: 8. strstr(查找字符串子串) 9. strtok(字符串分割) 错误信

    2024年02月10日
    浏览(90)
  • java语言基础(有c语言基础)

    jdk+记事本编译 编译javac Hello.java 执行java Hello byte b=123;//整型8位最大值是2的7次减一,第一位是符号位 short s=32156;//最大是2的15次-1 int i=101;//31 long l=123;63 float s=3.14; double d=3.14; boolean ok=true; char c=\\\'a\\\'; 3.14默认double 在后面加f float s=3.14f; (F不区分大小写 java无符号 字符 可以赋值

    2024年02月16日
    浏览(33)
  • R语言基础之R语言入门

             R语言最初是由新西兰奥克兰大学统计系的教授 Ross Ihaka 和 Robert Gentleman 在 S语言基础上开发完成的。是一门解释性语言。在我看来R语言是一门数学性极强的语言,或者说这是一门为数学而生的语言,因为其具有极其出色的计算与统计分析能力,但是在程序流转方

    2024年02月16日
    浏览(39)
  • 汇编语言笔记(一)——汇编语言基础

    一、开发环境 我使用visual studio 2022 preview,其他版本的设置大同小异。 第一步: 打开visual studio,点击“创建新项目”: 第二步: visual studio并没有专门的汇编项目,所以需要挂羊头卖狗肉,选择C++空项目 第三步: 输入项目名称,点击创建 第四步: 鼠标右键单击项目名称—

    2024年02月05日
    浏览(34)
  • 码蹄杯语言基础:选择结构(C语言)

    请编写一个简单程序,输入一个整数,和10比较,输出比较结果 格式 输入格式: 输入整型 输出格式: 输出…大于或者等于或者小于10 输入a,b两个整数,输出他们之间的最小值 格式 输入格式: 输入2个整数用空格分隔 输出格式: 输出为整型 输入a,b两个整数,输出他们之间

    2024年02月06日
    浏览(33)
  • 码蹄杯语言基础:结构体(C语言)

    码蹄集网站地址:https://www.matiji.net/exam/ojquestionlist 狼群新生了一只尊贵的艾尔法狼,请设计一个结构体,管理它的信息,信息包括名字,年龄,性别。 输入艾尔法狼宝宝的信息,然后再输出他的信息。 格式 输入格式: 输入名字性别为字符型,年龄整型 输出格式: 输出名字

    2024年02月11日
    浏览(32)
  • Go语言基础知识(一):基础介绍

    Go 语言又称 Golang,由 Google 公司于 2009 年发布,近几年伴随着云计算、微服务、分布式的发展而迅速崛起,跻身主流编程语言之列,和 Java 类似,它是一门静态的、强类型的、编译型编程语言,为并发而生,所以天生适用于并发编程(网络编程)。 目前 Go 语言支持 Windows、

    2024年02月13日
    浏览(43)
  • 【大语言模型LLM】-基础语言模型和指令微调的语言模型

    🔥 博客主页 : 西瓜WiFi 🎥 系列专栏 : 《大语言模型》 很多非常有趣的模型,值得收藏,满足大家的收集癖! 如果觉得有用,请三连👍⭐❤️,谢谢! 长期不定时更新,欢迎watch和fork!❤️❤️❤️ ❤️ 感谢大家点赞👍 收藏⭐ 评论⭐ 🎥 大语言模型LLM基础-系列文章

    2024年04月28日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包