ZICONG

梓聪的个人主页

0%

C语言动态分配内存

动态存储分配

  • C语言的数据结构通常是固定大小的,即使是变长数组,虽然其长度在运行时确定,但在其声明周期时依然是固定长度的。

  • 动态存储分布即是在程序执行期间分配内存,可以根据需要扩大或缩小数据结构。

  • 动态存储分布只要用于字符串、数组和结构,通常应用于构建表、树等其它数据结构。

内存分配函数

  • 以内存声明函数通过<stdlib.h>获取。

    • malloc:分配内存块,但不对内存块进行初始化——更高效

      void *malloc(size_t size);
    • calloc:分配内存块,并对内存块清零

      void *calloc(size_t num, size_t size);
    • realloc:调整先前分配的内存块大小

      void *realloc(void *ptr, size_t size);
  • 内存分配函数返回一个通用指针类型void *, 存储着指向内存块的指针。

  • 空指针:当分配失败时,函数返回空指针。需要认为检验指针变量是否为空:

    ptr = malloc(1000);
    if (p == NULL) {
        /* 分配失败 */
    }

动态分配字符串

  • 使用malloc函数为字符串分配内存。

  • C语言保证char类型需要一个字节的内存(sizeof(char)1)。给n个字符的字符串分配内存空间可以写成:

    p = (char *) malloc(n + 1);   // 为空字符\n分配空间
  • 虽然在给p赋值时,原来的通用指针*void会自动转化为对应的字符指针*char。但这里我们进行强制的类型转换。

  • 对上述字符串进行初始化的一种方法:

    #include <string.h>
    
    strcpy(p, "abc");
  • 下面这个函数将接受两个字符串,在不改变原来的字符串的前提下,合并字符串并且存储起来。

    #include <string.h>
    #include <stdlib.h>
    
    char *concat(const char *s1, const char *s2)
    {
        char *result;
    
        result = malloc(strlen(s1) + strlen(s2) + 1);
        if (result == NULL) {
            printf("Error: malloc failed in concat\n");
            exit(EXIT_FAILURE);
        }
        strcpy(result, s1);
        strcat(result, s2);
        return result;
    }

动态分布数组

使用malloc函数为数组分配存储空间

  • 由于不确定每个元素所需要的内存空间,所以需要使用sizeof()函数计算。

  • 假设数组需要包含n个整数,则需要如此分配内存空间。

    int *a;
    
    a = malloc(n * sizeof(int));
  • 一旦a指向动态分配的内存块,就可以忽略a是指针的事实,可以把它当作数组名来用。

calloc函数

  • 此函数需要传入元素的数量和每个元素的长度。

    int a;
    a = calloc(n, sizeof(int))    // 分配内存给n个整型变量
  • 分配内存后会把所有位置设置为0.

  • 通过此函数,为数据类型分配内存,并且初始化其元素为0.

    struct point {
        int x;
        int y;
    } *p;
    
    p = calloc(1, sizeof(struct point));    // 为一个结构体分配内存

realloc函数

  • 改变已经动态分配的内存块的大小。

  • 需要传入已分配内存块的指针,以及新的内存大小。

  • 不会对添加的内存块字节进行初始化。

  • 如果对被调用时以0为第二个实际参数,则函数将会释放内存块

释放存储空间

  • 频繁地调用内存分配函数,或者调用过大,有可能耗尽可分配空间。

  • 分配了的内存空间,却丢失了对这些内存空间的记录,就会造成浪费:

    p = malloc(...);     p -> 内存块1
    q = malloc(...);     q -> 内存块2
    ---------------------------------
    p = q;                 -> 内存块1
                      p, q -> 内存块2
  • 使用free函数释放内存:

    void free(void *ptr);
  • 只能对指向动态分配的内存块的指针使用free函数。

  • 以上代码的正确用法:

    p = malloc(...);
    q = malloc(...);
    
    free(p);   // 将p的内存释放掉
    p = q;     // 将p指向另外一个内存块
  • 如果释放了内存,那么指向该内存的指针将成为悬空指针。此时使用该指针将导致严重错误。最好将该指针重置为空指针。