当编译程序时,声明的数组必须预留足够的内存来存储数据。
int values[] = {36, 72, 16, 28, 88, 9, 1};
当知道要存储是什么的时候,可以直接初始化;或者不知道数组中要存储多少元素,就声明一个较大的数组。
int values[7];
当然,这两者做法也是有缺点的,初始化后的数组长度已固定不能更改;声明的数组太小时,无法容纳要存储的数据;或者声明的数组太大,浪费内存空间。
C 语言提供了动态内存分配的函数库,用于内存的分配和释放。
内存分配
C 语言在 stdlib.h
头文件中提供了 malloc
、calloc
和 realloc
用于不同情况下的内存分配。
malloc
C 语言在 stdlib.h
头文件中提供了 malloc
函数执行内存分配,其函数原型如下所示。
void *malloc(size_t size);
-
void *
:返回一个指向被分配的内存块起始位置的指针。 -
size
:需要分配的内存字节数。
该函数从内存中提取一块合适的连续内存来存储,并返回指向这块内存的指针。
int *ints = (int *)malloc(7 * sizeof(int));
如上所示,返回的指针类型为 void *
,是因为不知道请求内存需存储的类型,返回的 void *
类型可以转换为其它类型的指针。因为 int
类型在不同机器上,所占字节数也不同,malloc
函数传递的参数写成 num * sizeof(type)
也方便移植。
当内存不足时,使用 malloc
分配不到内存,并返回一个指向 NULL
的指针,因此分配内存后,先判断一下是否已分配内存。
if (words == NULL) {
printf("Out of Memory!");
exit(1);
}
使用 malloc
分配内存后,内存也没有初始化,要手动初始化才行。
int *ints = (int *)malloc(7 * sizeof(int));
memset(ints, 0, 7 * sizeof(int));
如上所示,先为 ints
分配 7
个 int
大小的内存,然后使用 memset
为7
个 int
类型的 ints
初始化为 0
。或者可以使用 calloc
函数分配内存并直接初始化。
有两种方式访问 malloc
分配后的内存,第一种是使用间接访问和指针运算来访问该内存中每个内存单元的值;第二种是使用下标来访问该内存中每个内存单元的值。
当错误地访问分配内存之外区域,会引起越界错误,类似于数组越界访问,可能会破坏可用内存,导致程序失败。
calloc
C 语言中的 calloc
函数也是分配内存的函数,其函数原型如下所示。
void *calloc(size_t num_elements, size_t size_elements);
-
void *
:返回一个指向被分配的内存块起始位置的指针。 -
num_elements
:分配内存的元素数量。 -
size_elements
:每个元素所占的字节数。
该函数分配 num_elements
个字节数为 size_elements
的连续内存,并返回指向该内存的指针。
该函数与 malloc
的主要区别是 calloc
在返回指向内存的指针之前把它初始化为 0
。
int *ints = (int *)calloc(7, sizeof(int));
for (int i = 0; i < 7; ++i) {
printf("%dt", *(ints + i));
}
// 0 0 0 0 0 0 0
realloc
除了 malloc
和 calloc
两个函数外,用于分配内存的还有 realloc
函数,其函数原型如下所示。
void *realloc(void *memory, size_t new_size);
-
void *
:返回一个指向被分配的内存块起始位置的指针。 -
memory
:需重新分配内存的指针。当memory
传入的是NULL
,其行为与malloc
一样。 -
new_size
:重新分配的内存所占的字节数。
该函数用于将 memory
指针指向的内存修改为 new_size
大小。
调用该函数可以改变一块已经动态分配内存的大小。当 new_size
比原先内存大时,内存中原先的内容保留,新增加的内存添加到原先内存块后面,新内存并未以任何方式初始化。当new_size
比原先内存小时,内存块尾部的部分会被拿掉,剩余部分内存的原先内容依然保留。
int * new_ints = (int *) realloc(ints, 10 * sizeof(int));
如果原先的内存块无法改变大小,realloc
将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。因此,在使用 realloc
之后,你就不能再使用指向旧内存的指针,而是应该改用 realoc
所返回的新指针。
内存释放
当使用 malloc
、calloc
或 realloc
分配内存之后,需要手动释放内存。
free
C 语言在 stdlib.h
中提供了能够释放内存的 free
函数,其函数原型如下所示。
void free(void *memory);
-
memory
:需要释放内存的指针。
该函数释放被 malloc
、calloc
或 realloc
所返回的指针所指向的内存,供以后分配。如果传入的是 NULL
,不会产生任何效果。
free(ints);
ints = NULL;
如上所示,free
释放内存后,指针变量 ints
本身保存的地址并没有改变,这是因为释放的是指针指向的内存,指针变量并没有释放,解决 ints
继续访问内存的办法是重新把 NULL
赋值给 ints
指针。
当使用 free
释放内存时,必须整块一起释放,如果释放一部分可能引起不可预料的后果。
int *ints = (int *)malloc(7 * sizeof(int));
free(ints + 5); // 释放了后两个,前 5 个未被释放
realloc
函数会缩小一块动态分配的内存,有效地释放它尾部的部分内存。当 free
多次释放同一个内存时,有可能把其它还在使用的内存释放掉,有可能导致程序错误或崩溃。
内存泄露
动态内存分配使用时候很容易出现问题,是因为动态内存都是通过手动分配和释放的。如果分配的内存在使用完毕后不释放,将会引起内存泄露 memory leak
。如果内存泄露过多,造成之后无内存可用,增加程序的体积,程序将无法继续执行下去,可能会导致程序崩溃,因此,一个动态分配的内存块不再使用时,要记得调用 free
函数释放它,内存释放后便不再被访问。

原文始发于微信公众号(海人为记):一文讲解C语言动态内存分配
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/27466.html