【C语言】内存管理

【C语言】内存管理

文章目录

1.概念

C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。

在 C 语言中,内存是通过指针变量来管理的。指针是一个变量,它存储了一个内存地址,这个内存地址可以指向任何数据类型的变量,包括整数、浮点数、字符和数组等。C 语言提供了一些函数和运算符,使得程序员可以对内存进行操作,包括分配、释放、移动和复制等。

2.库函数

序号 函数及描述
1 void *calloc(int num, int size); 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为0。所以它的结果是分配了 num * size 个字节长度的内存空间,并且每个字节的值都是0。
2 void free(void *address); 该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
3 void *malloc(int num); 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。
4 void *realloc(void *address, int newsize); 该函数重新分配内存,把内存扩展到 newsize

**注意:**void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。

3.动态分配内存

编程时,如果预先知道数组的大小,那么定义数组时就比较容易。例如,一个存储人名的数组,它最多容纳 100 个字符,所以您可以定义数组,如下所示:

c 复制代码
char name[100];

但是,如果预先不知道需要存储的文本长度,例如想存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来分配内存,如下所示:

malloc

c 复制代码
void *malloc(size_t size);

size 参数指定了需要分配的内存大小,单位是字节(byte)。size_t 是一个无符号整数类型,通常用来表示大小和计数。

功能描述:
malloc 函数在程序的堆区(heap)请求一块至少为 size 字节的内存区域。如果内存分配成功,malloc 返回一个指向这块内存的指针,程序员可以使用这个指针来访问和操作分配的内存。
如果分配失败,通常是因为堆上没有足够的内存空间,malloc 会返回 NULL。
c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char name[100];
    char *p;

    strcpy(name, "xiao ming");

    /* 动态分配内存 */
    p = (char *)malloc( 10 * sizeof(char) );// 分配一个整数数组的空间,大小为10个char
    if( p == NULL )
    {
        perror("malloc");
    }else{
        strcpy( p, "xiao ming is a student ");
    }
    printf("Name = %s\n", name );
    printf("p: %s\n", p );
	free(p);
}

注意事项

  • 初始化malloc 分配的内存空间不会被自动初始化,它的初始内容是未定义的。如果需要初始化,必须手动设置。
  • 内存泄漏 :使用 malloc 分配的内存必须在不再需要时使用 free 函数释放。如果忘记释放,将导致内存泄漏。
  • 大小计算 :分配数组时,需要使用 sizeof 来确保分配的内存大小正确。例如,分配一个包含 n 个元素的数组时,应使用 n * sizeof(element) 作为 malloc 的参数。
  • 错误处理 :如果 malloc 返回 NULL,应该妥善处理这种情况,可能是程序应该终止或采取其他恢复措施。
  • 指针类型malloc 返回的是 void* 类型的指针,这是C语言中所有指针类型的通用类型。在使用 malloc 分配特定类型的内存时,通常需要强制类型转换,如 int* array = malloc(10 * sizeof(int));

malloc 是动态内存分配的核心函数之一,在需要处理不确定数量的数据或实现某些数据结构(如链表、树等)时非常有用。正确使用 mallocfree 对于编写稳健和高效的C程序至关重要。

calloc

calloc 是 C 语言中用于动态内存分配的另一个标准库函数,它在很多方面与 malloc 相似,但有一个关键的区别在于初始化行为。下面是 calloc 函数的详细介绍:

函数原型

c 复制代码
void *calloc(size_t num, size_t size);
  • num 参数指定了要分配的元素数量。
  • size 参数指定了每个元素的大小,单位是字节。

功能描述

  • calloc 函数在程序的堆区分配一块总大小为 num * size 字节的内存区域,并且将这块内存区域的每个字节都初始化为0。这使得 calloc 成为分配和初始化静态数组或数据结构(如矩阵)的理想选择。
  • 如果内存分配成功,calloc 返回一个指向这块内存的指针;如果失败,返回 NULL

使用示例

c 复制代码
#include <stdlib.h> // 包含calloc函数的头文件

int main() {
    int rows = 5;
    int columns = 5;
    // 分配一个5x5的整数矩阵,并初始化为0
    int *matrix = calloc(rows * columns, sizeof(int));

    if (matrix == NULL) {
        // 处理内存分配失败的情况
        fprintf(stderr, "Memory allocation failed.\n");
        return 1;
    }

    // 使用分配的内存
    // 注意:矩阵已经初始化为0

    free(matrix); // 释放分配的内存
    return 0;
}

注意事项

  • 初始化 :与 malloc 不同,calloc 分配的内存区域会自动初始化为0,这对于需要清零的数据结构非常有用。
  • 内存泄漏 :和 malloc 一样,使用 calloc 分配的内存也必须在使用完毕后用 free 函数释放,以避免内存泄漏。
  • 大小计算 :分配数组或复合数据结构时,应使用 sizeof 来确保分配的内存大小正确。
  • 错误处理 :如果 calloc 返回 NULL,应该妥善处理这种情况,可能是程序应该进行错误恢复或终止。
  • 指针类型calloc 返回的是 void* 类型的指针,在使用时通常需要强制类型转换到具体的数据类型指针。

calloc 是动态内存分配中一个非常有用的函数,特别是当你需要分配一块内存并确保它是清零的状态时。正确地使用 calloc 可以帮助你更容易地初始化复杂的数据结构,并保持代码的清晰和简洁。

4.重新调整内存的大小和释放内存

当程序退出时,操作系统会自动释放所有分配给程序的内存,但是,建议在不需要内存时,都应该调用函数 free() 来释放内存。

或者,可以通过调用函数 realloc() 来增加或减少已分配的内存块的大小。让我们使用 realloc() 和 free() 函数。

realloc

realloc 是 C 语言中的一个用于内存管理的函数,它允许你更改先前使用 malloccalloc 函数分配的内存块的大小。这个函数非常有用,当你需要调整一个数据结构的大小以适应程序运行时变化的需求时。

函数原型

c 复制代码
void *realloc(void *ptr, size_t new_size);
  • ptr 是指向先前分配的内存块的指针。
  • new_size 是新的内存大小,单位是字节。

功能描述

  • realloc 尝试将指针 ptr 指向的内存块调整为 new_size 字节大小。
  • 如果 ptrNULLrealloc 表现得就像 malloc(new_size),分配一个新的内存块。
  • 如果 new_size 是 0,realloc 表现得就像 free(ptr),释放内存块。
  • 如果 realloc 成功,它返回指向重新分配(可能移动)内存块的指针。如果内存块被移动,原内存块的内容会被复制到新位置。
  • 如果 realloc 失败,它返回 NULL,原始内存块保持不变。

使用示例

c 复制代码
#include <stdlib.h> // 包含realloc函数的头文件

int main() {
    int *array = malloc(5 * sizeof(int)); // 初始分配
    if (array == NULL) {
        fprintf(stderr, "Initial memory allocation failed.\n");
        return 1;
    }

    // 假设需要扩大数组
    array = realloc(array, 10 * sizeof(int)); // 重新分配更大的空间
    if (array == NULL) {
        fprintf(stderr, "Memory reallocation failed.\n");
        free(array); // 确保释放原始内存
        return 1;
    }

    // 使用扩大后的数组
    // ...

    free(array); // 释放分配的内存
    return 0;
}

注意事项

  • 内存块可能移动realloc 可能会将内存块移动到堆中的另一个位置,因此返回的新指针可能与原始指针不同。这意味着你应该总是使用 realloc 返回的指针来引用内存。
  • 内容复制 :如果内存块被移动,realloc 会自动将原始内存块的内容复制到新位置。
  • 内存泄漏风险 :如果 realloc 失败,原始内存块仍然有效,不会自动释放。因此,你应该在重新分配内存之前保存原始指针的副本,并在必要时释放它。
  • 错误处理 :如果 realloc 返回 NULL,应该检查 new_size 是否为预期值,并处理可能的错误情况。
  • 性能考虑 :频繁地使用 realloc 可能会导致性能问题,特别是如果内存块经常需要移动到新位置时。

realloc 是一个强大的工具,可以帮助你管理程序运行时的内存需求。然而,由于它可能会改变内存块的位置,使用时需要小心,确保正确地处理返回的新指针。

free

free 函数是 C 语言中用于释放之前使用 malloccallocrealloc 函数分配的动态内存的标准库函数。正确地使用 free 函数对于防止内存泄漏和有效管理程序的内存使用至关重要。

函数原型

c 复制代码
void free(void *ptr);
  • ptr 是指向要释放的内存块的指针。如果 ptrNULL,调用 free 没有效果,但这种调用是安全的,不会引发错误。

功能描述

  • free 函数的作用是将之前动态分配的内存块返回给操作系统或运行时环境,使其可以被其他部分的程序再次使用。
  • 当没有更多的内存可用于新的内存分配请求时,释放不再需要的内存块是一种良好的编程实践。

注意事项

  • 释放NULL指针 :根据 C 标准,尝试释放一个 NULL 指针是安全的,free 将不做任何操作。
  • 悬挂指针:释放内存后,指针指向的内存已经不再属于你的程序,因此不应再使用该指针(称为悬挂指针)。
  • 内存泄漏 :如果忘记了调用 free 来释放动态分配的内存,将导致内存泄漏,长期运行的程序可能会因此耗尽可用内存。
  • 重复释放:不应尝试多次释放同一块内存,这可能会导致未定义的行为或程序崩溃。

使用 free 函数是 C 语言编程中的一个重要方面,它确保了程序的健壮性和资源的有效使用。记住,每次使用 malloccallocrealloc 分配内存时,都应该在适当的时候使用 free 来释放内存。

相关推荐
zhangzhangkeji27 分钟前
c++ 定点 new 及其汇编解释
开发语言·c++
Oracle_66640 分钟前
C基础算法与实现
c语言·算法
Pakho love1 小时前
Linux:文件与fd(被打开的文件)
android·linux·c语言·c++
W说编程1 小时前
C语言指针专题四 -- 多级指针
c语言·开发语言·数据结构·c++·嵌入式硬件
我命由我123451 小时前
游戏引擎 Unity - Unity 下载与安装
c语言·开发语言·c++·后端·unity·c#·游戏引擎
我命由我123452 小时前
游戏引擎 Unity - Unity 启动(下载 Unity Editor、生成 Unity Personal Edition 许可证)
c语言·c++·后端·unity·c#·游戏引擎·ue4
Allen Bright2 小时前
Java动态代理:原理与实现
java·开发语言
weixin_404679313 小时前
指数分布推导
开发语言·c#
codingexpert4043 小时前
使用 Julia Distributions.jl 进行概率分布处理
开发语言·概率论·julia
九离十3 小时前
C语言教程——文件处理(2)
c语言·开发语言