【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!(上)

简介: 【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!

前言

   🌈hello! 各位宝子们大家好啊,又是新的一天开始了,今天给大家带来的是动态内存规划这一章节!

   ⛳️我们在创建变量的时候大家都知道大小是固定,不够灵活。而动态内存分配可以改变这一现象!当我们需要多少就可以规划多少,而不需要时就可以释放掉,这样是不是就可以极大地避免了内存的浪费!

   📚本期文章收录在《C语言高阶篇》,大家有兴趣可以看看呐

  ⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!

💬 为什么存在动态内存分配

  ⛳️在前面内容中我们学的开辟空间大多都是用数据类型直接创建空间。

  • 比如用整形开辟一个大小为4个字节的空间
  • 或者数组开辟一个连续的储存空间
  • 而这些临时变量大多都是存放在栈区的
    🔥 注:在前面C/C++中内存大致分的三个区域有讲过《C/C++的三个内存区域》
int main()
{
  int a = 0;//在栈空间上开辟四个字节
  int arr[40]={0};//在栈空间上开辟40个字节
}

但是这的开辟空间的方式有两个缺点:

  • 数组空间申请多了,如果没有用完就会照成空间的浪费!
  • 空间开辟大小是固定的

所以像以前的空间开辟方法满足不了我们的需求,那么有没有我们想开辟多少空间就开辟多少,而当我们不想要的时候还可以释放!这个时候就需要动态内存开辟了!

💬 动态内存函数的介绍

  ⛳️ 而动态内存开辟就需要用到相关的函数分别是:mallocfreecallocrealloc把这四个函数只要掌握就可以完全的掌握动态内存分配了,下面我们就详细给大家介绍介绍:

1️⃣ 动态内存函数 malloc

动态内存开辟的函数:malloc

void* malloc (size_t size);

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

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

⛳️ 好了malloc的使用方法给大家介绍了,接下来就是给大家介绍介绍这个这个函数如何使用:

  • 他们的库函数都是#include <stdlib.h>
  • 所以使用的时候一定要记得加头文件哦!
#include <stdio.h>
#include <stdlib.h>
int  main()
{
  int arr[10] = { 0 };
  malloc(40);
  return 0;
}

我们都知道数组创建的空间是连续,而malloc申请的空间也是连续的但是malloc的空间是没有类型的。

  • 那么我们想像数组一样访问整形4个字节来访问怎么办呢?
  • 很简单我们把 malloc 的返回值类型强制转换为 int*
  • 整形指针接收 malloc 的返回值就可以
#include <stdio.h>
#include <stdlib.h>
int  main()
{
  int arr[10] = { 0 };
  int* p=(int*)malloc(40);
}

这样我们就可以和整形数组一样存放整形了,因为指针解引用每次也跳过4个字节

💭 malloc 函数返回失败怎么办

如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

  • 如果开辟失败,就会给 p 返回NULL 空指针
  • 而我们一旦对空指针在进行访问不会,越界访问越界了嘛?
  • 而这是绝对不允许的,一旦越界就会导致程序崩溃⁉️
  • 所以我们加一段代码来保证程序的安全性
int  main()
{
  int arr[10] = { 0 };
  int* p = (int*)malloc(40);
  //开辟失败
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  return 0;

这样就就可以在开辟失败时及时避免错误,直接return返回让程序结束!

  • 这里开辟失败是,让库函数 perror 给我们提示一下
  • malloc 里面出现了什么错误!
  • 下面就给大家观察一下开辟失败是什么样的

📑图片展示:

⛳️ 大家看这里当我们申请的空间太大是开辟不了就会给我们返回空间不够的错误提示

  • ps:申请的空间一定要非常大不然测试就不会返回错误值的
  • 博主试了好几遍还以为是自己的代码问题结果是申请空间太小了

💭 malloc 是在哪里开辟空间的

⛳️我们都知道临时变量是存放在栈空间的,那么malloc申请的空间是哪里的呢?

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
  int arr[10] = { 0 };
  int* p = (int*)malloc(40);
  //开辟失败
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d\n", p[i]);
  }
  return 0;
}

📑 代码结果:

  ⛳️这里打印的就是我们申请空间的值,但由于malloc函数并不会给我们初始化所以里面存放的都是随机值。

  • 那么这里面的动态内存分布到底是什么样呢?
  • 为什么里面全部都是随机值呢?
  • 这个图片来告诉你一切

  ⛳️我们动态内存分配都是在堆区开辟空间的, p 指针变量是在栈区里面开辟的空间里面。所以当malloc在返回时返回了起始地址然后我们用 p 接收了malloc申请空间的起始地址

  • 但是,malloc这个函数只返回起始地址并不进行初始化

💭 malloc申请空间为0

  ⛳️ 做为一个程序员我们在想要申请空间的时候肯定是已经知道,要申请多少空间。你又要malloc申请空间,又只申请0个空间,这种行为本来就是不合理,所以我们在使用malloc时要避免这种情况以免出现不必要的错误!

  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。

📆 malloc申请空间会主动释放嘛

  ⛳️而malloc申请的空间,当程序退出时,才会还给操作系统,而当程序未结束时,动态内存申请的内存空间,是不会主动释放的。这样就会照成内存的浪费!

  • 这时就需要使用free来释放,我们申请的动态内存空间
  • 编程的好习惯是,每次使用完malloc都要使用free释放空间
  • 下面我们就来介绍一下free函数

2️⃣ 动态内存函数 free

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

  • void free (void* ptr);

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

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

⛳️ 好了free的参数详情给大家介绍了,接下来就是给大家介绍介绍这个这个函数如何使用:

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
  int arr[10] = { 0 };
  int* p = (int*)malloc(40);
  //开辟失败
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d\n", p[i]);
  }
  free(p);
  p = NULL;
  return 0;
}

  ⛳️ 这就是 free 的使用方法了,是不是非常简单。只需要把我们指针变量 p 传给 free 函数,因为 p 里面存放了 malloc 申请空间的起始地址,那么为什么还要把 p 给置为空指针呢?

  • 因为我们虽然把指针p记录的动态空间给释放了
  • 但是p本身不会被释放,而p里面存放的地址就成 野指针
  • 这个情况是非常不安全的所以我们把它置为空!



目录
相关文章
|
6月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
227 0
|
4月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
187 26
|
4月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
312 15
|
11月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
402 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
11月前
|
存储 编译器 C语言
【C语言】数据类型全解析:编程效率提升的秘诀
在C语言中,合理选择和使用数据类型是编程的关键。通过深入理解基本数据类型和派生数据类型,掌握类型限定符和扩展技巧,可以编写出高效、稳定、可维护的代码。无论是在普通应用还是嵌入式系统中,数据类型的合理使用都能显著提升程序的性能和可靠性。
534 8
|
11月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
406 6
|
12月前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
307 6
|
12月前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
12月前
|
C语言 开发者
C语言中的模块化编程思想,介绍了模块化编程的概念、实现方式及其优势,强调了合理划分模块、明确接口、保持独立性和内聚性的实践技巧
本文深入探讨了C语言中的模块化编程思想,介绍了模块化编程的概念、实现方式及其优势,强调了合理划分模块、明确接口、保持独立性和内聚性的实践技巧,并通过案例分析展示了其应用,展望了未来的发展趋势,旨在帮助读者提升程序质量和开发效率。
597 5
|
12月前
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
372 4

热门文章

最新文章

下一篇
oss云网关配置