【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里面存放的地址就成 野指针
  • 这个情况是非常不安全的所以我们把它置为空!



目录
相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
23天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
35 3
|
1月前
|
NoSQL C语言 索引
十二个C语言新手编程时常犯的错误及解决方式
C语言初学者常遇错误包括语法错误、未初始化变量、数组越界、指针错误、函数声明与定义不匹配、忘记包含头文件、格式化字符串错误、忘记返回值、内存泄漏、逻辑错误、字符串未正确终止及递归无退出条件。解决方法涉及仔细检查代码、初始化变量、确保索引有效、正确使用指针与格式化字符串、包含必要头文件、使用调试工具跟踪逻辑、避免内存泄漏及确保递归有基准情况。利用调试器、编写注释及查阅资料也有助于提高编程效率。避免这些错误可使代码更稳定、高效。
229 12
|
1月前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
1月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
1月前
|
程序员 C语言
C语言内存函数精讲
C语言内存函数精讲
|
25天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
21 0
|
1月前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
19 0
|
1月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
1月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
40 0