C语言学习系列->动态内存管理

简介: C语言学习系列->动态内存管理

前言

要想学好数据结构,在C语言学习过程中就需要把指针、结构体和动态内存管理学好。在前面的文章,小编已总结了指针和结构体,本篇水文 小编为大家整理了一下C语言中的动态内存管理。

概述

已经掌握了开辟空间,为什么还要有动态内存分配?

int a=1;    //申请4个字节
char c='g';     //申请1个字节
int arr[30]={0};   //申请120个字节

这些申请好了之后,空间大小就是固定的,不能再去做调整,并不能满足实际生活需要。

long long ago 我们说过变长数组,变长数组的大小可以由变量来指定,但是一旦创建好之后,依然还是不能调整大小,而且只适用于C99中。

总的来说,申请的空间大小不能灵活调整。

因此,在C语言中:动态内存管理就给了程序员一个权限,自己申请,自己使用,使用完自己释放。

🚩malloc and free

🔜malloc

malloc是C语言中的动态内存开辟函数:

头文件:stdlib.h

malloc申请函数是在堆区上申请的

void* malloc (size_t size);

Allocates a block of size bytes of memory, returning a pointer to the

beginning of the block.

The content of the newly allocated block of memory is not initialized,

remaining with indeterminate values.

If size is zero, the return value depends on the particular library

implementation (it may or may not be a null pointer), but the returned

pointer shall not be dereferenced.

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

• 如果开辟成功,则返回⼀个指向开辟好空间的指针。

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

• 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃

⼰来决定。

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

code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
  //申请10个整型空间,即40个字节
  int *p = (int*)malloc(10 * sizeof(int));
  //开辟失败
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  //开辟成功,则使用空间
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    *(p + i) = i;   //0 1 2 3 4 5 6 7 8 9 
  }
  //打印
  for (i = 0; i < 10; i++)
  {
    printf("%d ", p[i]);
  }
  return 0;
}

🔜free

开辟完内存后,在结束后需要释放

有两种释放方式:

1.free

2.程序结束后,操作系统自己释放

void free (void* ptr);

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

• 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。

• 如果参数 ptr 是NULL指针,则函数什么事都不做。

code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
  //申请10个整型空间,即40个字节
  int *p = (int*)malloc(10 * sizeof(int));
  //开辟失败
  if (p == NULL)
  {
    perror("malloc");
    return 1;
  }
  //开辟成功,则使用空间
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    *(p + i) = i;   //0 1 2 3 4 5 6 7 8 9 
  }
  //打印
  for (i = 0; i < 10; i++)
  {
    printf("%d ", p[i]);
  }
  //释放
  free(p);
  p = NULL;
  return 0;
}

free( p ) 仅仅是把 p 指针指向的这块空间归还给了操作系统

free只能释放动态申请的空间

🚩calloc and realloc

🔜calloc

void* calloc (size_t num, size_t size);

• 函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。

• 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全

code

#include <stdio.h>
#include <stdlib.h>
int main()
{
  int *p = (int*)calloc(10, sizeof(int));
  if(NULL != p)
  {
    int i = 0;
    for(i=0; i<10; i++)
    {
      printf("%d ", *(p+i));
    }
  }
  free(p);
  p = NULL;
  return 0;
}

输出结果

0 0 0 0 0 0 0 0 0 0

如果我们对申请的内存空间的内容要求初始化,那么可以很⽅便的使⽤calloc函数来完成任务。

🔜realloc

void* realloc (void* ptr, size_t size);

• realloc函数的出现让动态内存管理更加灵活。

• 有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的时

候内存,我们⼀定会对内存的⼤⼩做灵活的调整。那 realloc 函数就可以做到对动态开辟内存⼤⼩的调整。

• ptr 是要调整的内存地址

• size 调整之后新⼤⼩

• 返回值为调整之后的内存起始位置

• 这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到 新 的空间

• realloc在调整内存空间的是存在两种情况:

情况1:原有空间之后有⾜够⼤的空间

情况2:原有空间之后没有⾜够⼤的空间

情况1

当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。

情况2

当是情况2 的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

code

#include <stdio.h>
#include <stdlib.h>
int main()
{
  int *ptr = (int*)malloc(100);
  if(ptr != NULL)
  {
    //业务处理
  }
  else
  {
    return 1;
  }
  //扩展容量
  //代码1 - 直接将realloc的返回值放到ptr中
  ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
  //代码2 - 先将realloc函数的返回值放在p中,不为NULL,在放ptr中
  int*p = NULL;
  p = realloc(ptr, 1000);
  if(p != NULL)
  {
    ptr = p;
  }
  //业务处理
  free(ptr);
  return 0;
}


目录
相关文章
|
19天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
31 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
19天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
48 6
|
23天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
40 6
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
101 13
|
24天前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
1月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
57 11
|
24天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
1月前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
52 11
|
21天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
50 1
|
27天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。