C语言——动态内存与柔性数组

目录

一、为什么要有动态内存

二、动态内存函数

1.malloc和calloc

2.realloc

3.free

三、柔性数组


一、为什么要有动态内存

        在c语言中,我们一般如下创建变量

int x =10;

char y = 'a';

         但是这样创建的变量,所开辟的内存大小是固定的,我们想要开辟大一点的空间是,我么可以这样

int x[10] = {0};

        这样虽然我们开辟了40个字节的空间,但是我们只能在编译时开辟空间,但是当我们需要在程序运行时开辟空间时,我们就可以用到动态内存了 

二、动态内存函数

1.malloc和calloc

malloc定义

void* malloc (size_t size)

        这个函数的功能是在开辟size大小的空间,单位为字节,并返回这段空间的首地址。

        那么问题来了,这个函数需要一个size_t类型的数据,size_t是个什么东西?其实size_t是编译器自己重命名的一个名字,它原来的名字叫unsigned int。

C语言——动态内存与柔性数组_第1张图片

这个函数有一下注意事项

  • 函数的返回值类型是void*,在使用时需要强制类型转换成需要的类型。
  • 空间开辟失败时,会返回NULL。所以我们在使用该函数时需要判断一下是不是空指针。
  • 创建空间大小的单位是字节,在使用时需要自己计算空间的大小。
  • size_t的最小值是0,但是我们不要在使用时开辟0个字节的空间,这种行为是未定义的,取决于不同的编译器。

除了malloc,还有一个和malloc很像的函数,这个函数叫calloc

calloc定义

void* calloc (size_t num, size_t size)

        这个函数是开辟num个大小为size字节的空间,并且每个字节都初始化为0。与malloc的区别也只有会将申请的的空间每个字节初始化为0;

2.realloc

realloc定义

void* realloc (void*  ptr, size_t size)

        这个函数可以改变之前创建空间的大小,ptr为之前创建空间的首地址,size为调整之后的大小,

当扩大空间时会有两种情况

  1. 如果后面的空间足够,直接原来的内存加上后面需要的内存,空间不改变
  2. 如果后面的空间不够,则会在堆上找一块合适的空间使用,并且把原来的内容拷贝一份

3.free

free定义

void free (void* ptr)

        动态内存只能手动释放,free就是释放回收我们之前开辟的动态内存,prt就是指向需要释放空间的首地址

注意事项

  • ptr指向的空间必须是动态开辟的,否者free函数的行为是未定义的
  • ptr如果为NULL,则函数什么是都不做

三、柔性数组

        在结构体中,当最后一个元素是未知大小的数组,这个数组就是柔性数组

struct arr
{
 int i;
 int a[];
};

在创建使用柔性数组时请注意一下几点

  • 柔性数组前必须至少还要一个成员
  • sizeof返回值不会包括柔性数组的大小
  • 包含柔性数组的结构体用malloc函数分配内存,并且分配内存大小应该大于结构体大小,多出来的空间就是柔性数组的空间

struct arr *p = (struct arr*)malloc(sizeof(struct arr)+10*sizeof(int));

        开辟出来的空间用结构体指针接收,使用这个结构体就可以对指针解引用。

        还有一个办法也可以达到柔性数组的效果,就是把数组写成指针的形式,然后开辟出一块空间用指针接收

struct arr
{
 int i;
 int *a;
};

但是柔性数组有两个优势

1.方便内存的释放

如果写的代码是在一个给别人用到函数中,你在里面做了两次的内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也要进行free,所以要把结构体的内存以及其成员的内存一次性分配好,并返回用户一个结构体指针,这样用户只需要free一次就可以把结构体指针指向的内存释放掉了。

2.有利于访问的速度

柔性数组开辟的空间是连续的,连续的内存有利于提高访问速度,也有益于减少内存碎片(内存碎片就是已开辟的连续内存之间的内存)
 

你可能感兴趣的:(C语言进阶,c语言)