📜  C |动态内存分配|问题7(1)

📅  最后修改于: 2023-12-03 15:13:46.402000             🧑  作者: Mango

C语言 动态内存分配问题

什么是动态内存分配?

动态内存分配是指在程序运行时根据需求动态地分配和释放内存空间,而不是在编译时就确定了内存的大小。

在C语言中,动态内存分配与malloc、calloc、realloc函数密切相关。

malloc函数

malloc函数(memory allocation的缩写),用于动态内存分配,原型如下:

void* malloc(size_t size);
  • 参数size表示需要分配的字节数,单位是byte。
  • 返回值是一个void指针,指向所分配的内存空间的开始地址。如果分配失败,则返回一个空指针NULL。

用法示例:

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

int main() {
    int *ptr;
    ptr = (int*) malloc(10 * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    for (int i = 0; i < 10; i++) {
        *(ptr + i) = i;
    }
    for (int i = 0; i < 10; i++) {
        printf("%d ", *(ptr + i));
    }
    printf("\n");
    free(ptr);
    return 0;
}

在上面的示例中,我们使用malloc函数分配了10个int类型变量的内存空间,并将它们的值赋为0~9。在使用完毕后,我们使用free函数释放了分配的内存空间。

需要注意的是,在使用指针ptr访问内存空间时,需要将它当作数组来使用,即使用*(ptr + i)访问ptr所指向的第i个int类型变量。

calloc函数

calloc函数的作用与malloc函数基本相同,只是它会在分配内存空间的同时将该空间的值全部初始化为0。

calloc函数的原型如下:

void* calloc(size_t num, size_t size);
  • 参数num表示需要分配的元素个数。
  • 参数size表示每个元素的大小。
  • 返回值是一个void指针,指向所分配的内存空间的开始地址。如果分配失败,则返回一个空指针NULL。

用法示例:

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

int main() {
    int *ptr;
    ptr = (int*) calloc(10, sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    for (int i = 0; i < 10; i++) {
        printf("%d ", *(ptr + i));
    }
    printf("\n");
    free(ptr);
    return 0;
}

在上面的示例中,我们使用calloc函数分配了10个int类型变量的内存空间,并将它们全部初始化为0。在使用完毕后,我们使用free函数释放了分配的内存空间。

realloc函数

realloc函数用于重新分配已经分配的内存空间的大小。

realloc函数的原型如下:

void* realloc(void* ptr, size_t size);
  • 参数ptr为原来分配的内存空间的指针。
  • 参数size表示需要重新分配的内存空间的大小,单位是byte。
  • 返回值为一个指向新分配的内存空间的指针。如果重新分配失败,则返回一个空指针NULL。

需要注意的是,在重新分配内存空间后,原来的内存空间就不存在了,新分配的内存空间的初始值是未定义的。如果新分配的内存空间比原来的小,则被截断的数据会丢失。

用法示例:

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

int main() {
    int *ptr;
    ptr = (int*) malloc(10 * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    for (int i = 0; i < 10; i++) {
        *(ptr + i) = i;
    }
    ptr = (int*) realloc(ptr, 20 * sizeof(int));
    if (ptr == NULL) {
        printf("内存重新分配失败\n");
        return 1;
    }
    for (int i = 0; i < 20; i++) {
        printf("%d ", *(ptr + i));
    }
    printf("\n");
    free(ptr);
    return 0;
}

在上面的示例中,我们首先使用malloc函数分配了10个int类型变量的内存空间,并将它们的值赋为0~9。然后我们使用realloc函数将内存空间的大小重新分配为20个int类型变量,并输出它们的值。在使用完毕后,我们使用free函数释放了分配的内存空间。

动态内存分配的问题

由于动态内存分配需要程序员手动管理内存空间的释放,因此容易产生以下问题:

1.内存泄漏(memory leak)

内存泄漏是指在程序中动态分配的内存空间没有被及时释放,在程序运行过程中不断占用内存空间,最终导致程序崩溃的现象。在程序较小的情况下,内存泄漏的影响不太明显,但在大规模的程序中,内存泄漏会导致程序的性能严重下降,甚至使程序崩溃。

如何避免内存泄漏?只需要在动态分配内存空间后,及时使用free函数释放掉不再使用的内存空间即可。

2.空指针错误(null pointer)

空指针错误是指在使用指针时,该指针未被初始化,或者已经被释放掉,导致其指向一个无效的内存地址,进而导致程序崩溃。

如何避免空指针错误?只需要在使用指针之前,确保指针已经正确地被初始化,并在释放内存空间后,将指针置为空指针即可。

3.内存越界(out of bounds)

内存越界是指在使用数组时,访问了数组的边界之外的内存,导致程序崩溃。这种错误通常是由于程序员没有正确计算数组的大小或者没有检查数组的下标是否越界而引起的。

如何避免内存越界?只需要在使用数组时,正确地计算数组的大小,检查数组的下标是否越界即可。

小结

动态内存分配是C语言中的一项重要功能,主要涉及到malloc、calloc、realloc等函数。程序员在使用动态内存分配的过程中,需要注意内存泄漏、空指针错误、内存越界等问题,才能编写出稳定可靠的程序。