这是 C 语言很可能与您已经熟悉的其他语言有较大不同的一个重要方面:手动内存管理。
其他语言通常使用引用计数、垃圾回收或其他机制来决定何时为数据分配新的内存,以及当没有变量再引用它时何时释放内存。
这很不错。你不用担心内存释放问题,只需放弃对某个数据项的所有引用,系统就会在某个时刻自动释放与它关联的内存。
但 C 语言并不完全是这样。
当然,在 C 语言中,一些变量在进入作用域时会自动分配内存,离开作用域时自动释放。我们称这类变量为自动变量,它们是普通的块作用域“局部”变量,没有问题。
但是如果你想让某个数据的生命周期长于特定的代码块,这时就需要手动管理内存。
你可以明确告诉 C 为你分配一定数量的字节,这些字节可以随意使用。这部分内存会一直保留,直到你显式地释放它。
你必须释放不再需要的内存!如果不释放,这就是所谓的内存泄漏,你的程序将持续占用这部分内存直到退出。
如果你手动分配了内存,使用完后就必须手动释放。
那么,怎么做呢?我们将学习几个新函数,并结合 sizeof 运算符,这将帮助我们确定要分配多少字节。
在 C 语言中,开发者通常说自动局部变量分配在“栈”上,手动分配的内存则在“堆”上。规范中并没有明确提到这些概念,但所有 C 程序员一提起它们就明白是什么意思。
本章我们将学习的所有函数都可以在 <stdlib.h> 头文件中找到。
malloc() and free()malloc() 函数接受一个要分配的字节数参数,返回指向这块新分配内存的 void* 指针。
因为返回的是 void*,你可以将它赋给任何类型的指针……通常这会对应你要分配的字节数。
那么,我应该分配多少字节呢?我们可以用 sizeof 来帮忙。如果想分配一个 int 所需的空间,就用 sizeof(int),然后将其作为参数传递给 malloc()。
当你使用完这块内存后,可以调用 free() 来表示不再需要这块内存,它就可以被其它用途使用。作为参数传入的,必须是你从 malloc() 拿到的同一个指针(或者它的副本)。用 free() 释放内存后继续使用那块内存,会导致未定义行为。
我们来试试。给一个 int 分配足够的空间,存入一个数,然后打印出来。
// 为一个 int 分配空间(大小为 sizeof(int) 字节):
int *p = malloc(sizeof(int));
*p = 12; // 存入数据
printf("%d\\n", *p); // 打印:12
free(p); // 用完释放内存
//*p = 3490; // 错误:未定义行为!free 之后不能使用指针!
在这个刻意设计的例子里,这么做其实没啥优势。直接用自动变量的 int 也可以实现同样功能。但我们接下来会看到,这种内存分配方式在处理更复杂的数据结构时优势明显。