C 语言编程教程

C 语言 - 首页

C 语言基础

C 语言 - 概述 C 语言 - 特性 C 语言 - 发展历史 C 语言 - 环境设置 C 语言 - 程序结构 C 语言 - Hello World C - 编译过程 C - 注释 C - 标记 C - 关键字 C - 标识符 C - 用户输入 C - 基本语法 C - 数据类型 C - 变量 C - 整数提升 C - 类型转换 C - 类型转换 C - 布尔值

C 语言中的常量和文字

C - 常量 C - 字面量 C - 转义序列 C - 格式说明符

C 语言中的运算符

C - 运算符 C - 算术运算符 C - 关系运算符 C - 逻辑运算符 C - 位运算符 C - 赋值运算符 C - 一元运算符 C - 递增和递减运算符 C - 三元运算符 C - sizeof 运算符 C - 运算符优先级 C - 其他运算符

C 语言中的决策

C - 决策 C - if 语句 C - if...else 语句 C - 嵌套 if 语句 C - switch 语句 C - 嵌套 switch 语句

C 语言中的循环

C - 循环 C - While 循环 C - For 循环 C - Do...while 循环 C - 嵌套循环 C - 无限循环 C - Break 语句 C - Continue 语句 C - goto 语句

C 语言中的函数

C - 函数 C - Main 函数 C - 按值调用函数 C - 按引用调用函数 C - 嵌套函数 C - 可变参数函数 C - 用户定义函数 C - 回调函数 C - return 语句 C - 递归

C 语言中的作用域规则

C - 作用域规则 C - 静态变量 C - 全局变量

C 语言中的数组

C - 数组 C - 数组的属性 C - 多维数组 C - 将数组传递给函数 C - 从函数返回数组 C - 可变长度数组

C 语言中的指针

C - 指针 C - 指针和数组 C - 指针的应用 C - 指针运算 C - 指针数组 C - 指向指针的指针 C - 将指针传递给函数 C - 从函数返回指针 C - 函数指针 C - 指向数组的指针 C - 指向结构体的指针 C - 指针链 C - 指针 vs 数组 C - 字符指针和函数 C - NULL 指针 C - void 指针 C - 悬垂指针 C - 解引用指针 C - Near、Far 和 Huge 指针 C - 指针数组的初始化 C - 指针与多维数组

C 语言中的字符串

C - 字符串 C - 字符串数组 C - 特殊字符

C 语言的结构体和联合

C - 结构体 C - 结构体和函数 C - 结构体数组 C - 自引用结构 C - 查找表 C - 点 (.) 运算符 C - 枚举(或 enum) C - 结构填充和打包 C - 嵌套结构 C - 匿名结构和联合 C - 联合 C - Bit 位字段 C - Typedef

C 语言中的文件处理

C - 输入和输出 C - 文件 I/O(文件处理)

C 语言中的预处理器

C - 预处理器 C - #pragma 编译指示 C - 预处理器操作符 C - 宏 C - 头文件

C 语言中的内存管理

C - 内存管理 C - 内存地址 C - 存储类

C 其他主题

C - 错误处理 C - 可变参数 C - 命令执行 C - 数学函数 C - static 静态关键字 C - 随机数生成 C - 命令行参数

C 语言编程资源

C语言问题与解答答案 C语言快速指南 C语言速查表 C语言实用资源 C语言讨论


C 语言的内存管理

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

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

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

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

函数 描述
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。

动态分配内存

如果您知道数组的大小,那么操作起来就很简单,您可以将其定义为数组。例如,如果您需要存储一个人的姓名,那么您可以安全地定义一个最多可容纳 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
");
   } else {
      printf("Name = %s
", 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
");
   } else {
      printf("Name = %s
", 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
");
   } else {
      printf("Name = %s
", 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
");
   } else {
      printf("Name = %s
", name);
      free(name);
   }
}

输出

在代码的末尾,分配给 char * 指针 的内存被取消分配。

Name = TutorialsPoint India Private Limited