C语言动态内存分配

C语言提供了四个主要的库函数用于动态内存管理,这些函数定义在 `头文件中:

1. malloc()
2. calloc()
3. realloc()
4. free()

1. malloc()

malloc()函数用于在堆(heap)上分配指定字节数的内存块。分配的内存不会被初始化,其内容是未定义的。

函数原型

void *malloc(size_t size);

参数:
          size:要分配的内存字节数。
          返回值:
                成功:返回一个指向分配内存的指针。
                失败:返回 `NULL` 指针。

 示例

#include 
#include 

int main() {
    int *ptr;
    int n;

    printf("请输入要分配的整数个数: ");
    scanf("%d", &n);

    ptr = (int *)malloc(n * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 使用分配的内存
    for(int i = 0; i < n; i++) {
        ptr[i] = i + 1;
        printf("ptr[%d] = %d\n", i, ptr[i]);
    }

    // 释放内存
    free(ptr);
    return 0;
}

输出:

C语言动态内存分配_第1张图片

2. calloc()

calloc()函数用于在堆上分配内存,并初始化分配的内存块为零。与 malloc() 不同,calloc()接受两个参数,分别表示元素的数量和每个元素的大小。

void *calloc(size_t num, size_t size);

参数:
        num:元素的数量。
        size:每个元素的大小。
返回值:
        成功:返回一个指向分配内存的指针。
        失败:返回一个 NULL指针。

示例

#include 
#include 

int main() {
    int *ptr;
    int n;

    printf("请输入要分配的整数个数: ");
    scanf("%d", &n);

    ptr = (int *)calloc(n, sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 使用分配的内存
    for(int i = 0; i < n; i++) {
        printf("ptr[%d] = %d\n", i, ptr[i]); // 初始值为0
    }

    // 释放内存
    free(ptr);
    return 0;
}

输出:

C语言动态内存分配_第2张图片

 3. realloc()

realloc()函数用于调整之前分配的内存块的大小。如果之前分配的内存块不足以满足需求,realloc()会尝试在堆上分配更大的内存块,并将旧内存块的内容复制到新内存块中。

void *realloc(void *ptr, size_t size);

参数:
        ptr:指向之前分配的内存块的指针。
        size:新的内存块大小。
返回值:
        成功:返回一个指向新内存块的指针。
        失败:返回 `NULL` 指针(原有内存块保持不变)。

示例

#include 
#include 

int main() {
    int *ptr;
    int n, new_n;

    printf("请输入要分配的整数个数: ");
    scanf("%d", &n);

    ptr = (int *)malloc(n * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 初始化
    for(int i = 0; i < n; i++) {
        ptr[i] = i + 1;
    }

    printf("当前数组大小: %d\n", n);
    printf("请输入新的数组大小: ");
    scanf("%d", &new_n);

    ptr = (int *)realloc(ptr, new_n * sizeof(int));
    if (ptr == NULL) {
        printf("内存重新分配失败\n");
        return 1;
    }

    // 初始化新分配的部分
    for(int i = n; i < new_n; i++) {
        ptr[i] = i + 1;
    }

    printf("新数组大小: %d\n", new_n);
    for(int i = 0; i < new_n; i++) {
        printf("ptr[%d] = %d\n", i, ptr[i]);
    }

    // 释放内存
    free(ptr);
    return 0;
}

输出:

C语言动态内存分配_第3张图片

4. free()

free() 函数用于释放之前通过 malloc(), calloc() 或 realloc() 分配的内存。释放内存后,程序不能再访问该内存区域,否则会导致未定义行为。

void free(void *ptr);

参数:
        ptr:指向要释放的内存块的指针。
返回值:
         无

注意

避免内存泄漏: 每次使用 malloc(), calloc()或 realloc()分配内存后,必须使用 free()释放内存,否则会导致内存泄漏。
避免悬挂指针:释放内存后,应将指针设置为 NULL,以避免悬挂指针(指向已释放内存的指针)带来的问题。

示例

#include 
#include 

int main() {
    int *ptr = (int *)malloc(5 * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 使用内存
    for(int i = 0; i < 5; i++) {
        ptr[i] = i + 1;
    }

    // 释放内存
    free(ptr);
    ptr = NULL; // 避免悬挂指针

    return 0;
}

输出:

C语言动态内存分配_第4张图片

 5. 动态内存分配的应用场景

1. 可变大小的数据结构:如链表、动态数组、树、图等。
2. 处理大型数据集: 当数据量在运行时确定时,动态分配内存可以节省内存空间。
3. 文件处理: 读取文件内容到内存中时,可能需要动态分配内存。
4. 网络编程:处理网络数据包时,可能需要动态分配内存。

 6. 动态内存分配的常见错误

1. 内存泄漏:分配的内存没有被释放,导致内存逐渐耗尽。
2. 悬挂指针:释放内存后未将指针设置为 NULL,导致后续访问无效内存。
3.多次释放:对同一指针多次调用 free(),导致未定义行为。
4. 分配失败未处理: 未检查 malloc(), calloc() 或 realloc() 的返回值是否为 NULL。

7. 内存管理最佳实践

1. 总是检查分配结果: 每次调用 malloc(), calloc() 或 realloc() 后,检查返回值是否为 NULL。
2. 释放所有分配的内存:确保每个 malloc(), calloc() 或 realloc() 对应一个 free()。
3. 避免悬挂指针:释放内存后,将指针设置为 NULL。
4. 使用工具检测内存错误: 使用诸如 Valgrind 等工具检测内存泄漏和悬挂指针。

8. 高级内存管理

C语言还提供了其他内存管理函数,如 alloca(),用于在栈上分配内存。

alloca()函数用于在栈上分配内存,分配的内存会在函数返回时自动释放,不需要调用 free()。

void *alloca(size_t size);

参数:

         size:要分配的内存字节数。
返回值:
        成功:返回一个指向分配内存的指针。
        失败:返回 NULL指针。

 注意

        栈空间限制:栈空间有限,过大的分配可能导致栈溢出。
        不可移植性:alloca()不是标准C的一部分,行为可能因平台而异。

9. 示例:动态数组的实现

#include 
#include 

int main() {
    int *array = NULL;
    int n, i;

    printf("请输入数组的大小: ");
    scanf("%d", &n);

    array = (int *)malloc(n * sizeof(int));
    if (array == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    // 输入数组元素
    for(i = 0; i < n; i++) {
        printf("请输入元素 %d: ", i);
        scanf("%d", &array[i]);
    }

    // 输出数组元素
    printf("数组元素为: ");
    for(i = 0; i < n; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // 释放内存
    free(array);
    array = NULL;

    return 0;
}

输出:

C语言动态内存分配_第5张图片

 10. 总结

动态内存分配是C语言中一个强大的特性,能够在运行时灵活地分配和管理内存。

你可能感兴趣的:(c语言,算法,开发语言)