Cprogramming 简明教程

Memory Management in C

C 的一个重要特点是,编译器负责管理为代码中声明的变量分配内存的方式。一旦编译器分配了必需的字节内存,在运行时将无法对其进行更改。

编译器采用静态内存分配方法。但是,有时你可能需要在运行时按需分配内存。阅读本章,了解动态内存管理在 C 中的工作原理。

Functions for Dynamic Memory Management in C

C 编程语言提供了用于动态内存分配和管理的几个函数。这些函数可以在 <stdlib.h> header file 中找到。

Function

Description

void * calloc (int num, int size);

此函数分配一个 num 元素的数组,每个元素以字节为单位的大小为 size。

void free(void *address);

此函数释放由地址指定的内存块。

void *malloc(size_t size);

此函数分配一个 num 字节的数组并将其保留为未初始化状态。

void * realloc (void *address, int newsize);

此函数重新分配内存,将其扩展到 newsize。

Allocating Memory Dynamically

如果你了解数组的大小,那么很容易,可以将其定义为数组。例如,如果你需要存储一个人的姓名,则可以安全地定义一个数组来容纳最多 100 个字符(假设一个姓名不包含超过 100 个字符)。所以,你可以如下定义一个数组:

char name[100];

这是 static memory allocation 的一个示例。现在我们考虑一种情况,你不知道需要存储的文本的长度,例如,你想存储关于某个主题的详细描述。在这种情况下,如果内容小于分配的大小,则该代码的执行期间会浪费掉已分配的内存。

另一方面,如果所需的大小超过已分配的内存大小,则可能导致不可预测的行为,包括导致数据损坏,因为数组的大小无法动态更改。

在这些情况下,你需要使用本章所述的动态内存分配方法。

The malloc() Function

此函数在 stdlib.h 头文件中定义。它分配所需大小的内存块,并返回一个 void pointer

void *malloc (size)

size 参数是指以字节为单位的内存块。要分配类型指定数据所需的内存,你需要使用 typecasting 运算符。

例如,以下代码片段分配存储 int 类型所需的内存:

int *ptr;
ptr = (int *) malloc (sizeof (int));

这里我们需要定义一个 pointer to character 而不用定义需要多少内存,稍后,基于需求,我们可以分配内存。

Example

以下示例使用 malloc() 函数分配存储字符串所需的内存(而不是声明一个固定大小的 char 数组):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char *name;
   name = (char *) malloc(strlen("TutorialsPoint"));
   strcpy(name, "TutorialsPoint");

   if(name  == NULL) {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   } else {
      printf("Name = %s\n", name);
   }
}

编译并执行上述代码会产生以下输出:

Name = TutorialsPoint

The calloc() Function

calloc()函数(表示连续分配)分配请求的内存并返回其指针。

void *calloc(n, size);

此处,“n”是要分配的元素数量,“size”是每个元素的字节大小。

以下代码片段分配存储 10 个 int 类型所需内存:

int *ptr;
ptr = (int *) calloc(25, sizeof(int));

Example

我们用 calloc() 函数重写上述程序。你只需将 malloc 替换为 calloc

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char *name;
   name = (char *) calloc(strlen("TutorialsPoint"), sizeof(char));
   strcpy(name, "TutorialsPoint");

   if(name  == NULL) {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   } else {
      printf("Name = %s\n", name);
   }
}

因此,你可完全控制并可在分配内存时传递任何大小的值,这与数组不同,后者一旦定义大小,你就无法更改它。

Resizing and Releasing the Memory

当程序退出时,操作系统会自动释放程序分配的所有内存。然而,在你不再需要使用已分配内存时通过调用 free() 函数明确释放已分配内存是一种很好的做法。

在本节中,我们将重点介绍 realloc()free() 这两个函数的使用,你可使用它们来调整大小并释放已分配内存。

The realloc() Function

C 中的 realloc()(重新分配)函数用于动态更改先前分配的内存的内存分配。你可以通过调用 realloc() 函数来增加或减少已分配内存块的大小。

使用 realloc() 函数的原型如下所示:

void *realloc(*ptr, size);

其中,第一个参数“ ptr ”是先前已使用 malloc、calloc 或 realloc 分配要重新分配的内存块的指针。如果此指针为 NULL,将分配一个新块,且函数返回其指针。

第二个参数“ size ”是内存块的新大小(以字节为单位)。如果该值为“0”,且 ptr 指向现有的内存块,则 ptr 指向的内存块将被释放,且返回 NULL pointer

Example

以下示例演示在 C 程序中如何使用 realloc() 函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char *name;
   name = (char *) calloc(strlen("TutorialsPoint"), sizeof(char));
   strcpy(name, "TutorialsPoint");

   name = (char *) realloc(name, strlen(" India Private Limited"));
   strcat(name, " India Private Limited");


   if(name == NULL) {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   } else {
      printf("Name = %s\n", name);
   }
}

编译并执行上述代码会产生以下输出:

Name = TutorialsPoint India Private Limited

The free() Function

C 中的 free() 函数用于动态取消分配使用 malloc() 和 calloc() 等函数分配的内存,因为它们不会自行释放内存。

在 C 编程中,对未使用内存的任何引用都会创建垃圾存储,可能导致程序崩溃之类的问题。因此,明智的做法是使用 free() 函数对已分配内存执行手动清理操作。

以下是如何使用 free() 函数的原型:

void free(void *ptr);

其中 ptr 是先前已分配的内存块的指针。

Example

以下示例演示在 C 程序中如何使用 free() 函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

   char *name;
   name = (char *) calloc(strlen("TutorialsPoint"), sizeof(char));
   strcpy(name, "TutorialsPoint");

   if(name  == NULL) {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   } else {
      printf("Name = %s\n", name);
      free(name);
   }
}

在代码结尾处,分配给 char * pointer 的内存被取消分配。

Name = TutorialsPoint India Private Limited