C语言内存管理



C语言的一个重要特性是编译器管理代码中声明的变量的内存分配方式。一旦编译器分配了所需的内存字节,在运行时就无法更改。

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

C语言中动态内存管理的函数

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

函数 描述
void *calloc(int num, int size); 此函数分配一个包含num个元素的数组,每个元素的大小(以字节为单位)为size。
void free(void *address); 此函数释放由address指定的内存块。
void *malloc(size_t size); 此函数分配一个包含num个字节的数组,并将其保留为未初始化状态。
void *realloc(void *address, int newsize); 此函数重新分配内存,将其扩展到newsize。

动态分配内存

如果您知道数组的大小,那么很容易定义它为一个数组。例如,如果您需要存储一个人的姓名,那么您可以安全地定义一个数组来保存最多100个字符(假设姓名不会超过100个字符)。因此,您可以按如下方式定义一个数组:

char name[100];

这是一个静态内存分配的例子。现在让我们考虑一种情况,您不知道需要存储的文本的长度,例如,您想存储有关某个主题的详细说明。在这种情况下,如果内容少于分配的大小,则在程序执行期间分配的内存会被浪费。

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

在这种情况下,您需要使用本章中描述的动态内存分配方法。

malloc() 函数

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

void *malloc (size)

size参数指的是以字节为单位的内存块。要为指定的 数据类型分配内存,您需要使用类型强制转换运算符。

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

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

在这里,我们需要定义一个指向字符的指针,而无需定义需要多少内存,然后根据需要分配内存。

示例

以下示例使用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

calloc() 函数

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

void *calloc(n, size);

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

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

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

示例

让我们使用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);
   }
}

因此,您可以完全控制,并且可以在分配内存时传递任何大小值,这与数组不同,数组一旦定义了大小,就不能更改。

调整内存大小和释放内存

当您的程序退出时,操作系统会自动释放程序分配的所有内存。但是,当您不再需要使用分配的内存时,最好通过调用free()函数显式释放分配的内存,这是一个良好的实践。

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

realloc() 函数

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

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

void *realloc(*ptr, size);

这里,第一个参数“ptr”是指向以前使用malloc、calloc或realloc分配的内存块的指针,该内存块将被重新分配。如果它是NULL,则会分配一个新的块,并且函数会返回指向它的指针。

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

示例

以下示例演示了如何在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

free() 函数

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

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

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

void free(void *ptr);

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

示例

以下示例演示了如何在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 *指针的内存被释放。

Name = TutorialsPoint India Private Limited
广告