为什么使用动态内存分配

malloc 和 free

malloc 和 free 分别用于执行动态内存分配和释放.

malloc 从内存池中提取一块合适的内存, 并向该程序返回一个指向这块内存的指针.

当一块以前分配的内存不再使用时, 程序调用 free 函数把它归还给内存池供以后 使用.

它们都在头文件 stdlib.h 中

void *malloc(size_t size);
void free(void *p);

malloc 的参数就是需要分配内存字节(字符)数.

malloc 所分配的是一块连续的内存. 同时 malloc 实际分配的内存可能比你请求的 稍微多一点.

如果内存无法满足需求, malloc 就返回一个 NULL 指针.

free 的参数必须要么是 NULL, 要么是从前从 malloc,calloc或realloc返回的值.

向 free 传递一个 NULL 参数不会产生任何效果.

malloc 由于不知道所请求的内存存储类型, 所以 malloc 返回一个 void * 指针.

对于要求边界对齐的机器, malloc 所返回的内存起始位置将始终能够满足边界对齐 最严格的类型的要求.

calloc 和 realloc

calloc 和 realloc 原型如下

void *calloc(size_t num_elements, size_t element_size);
void realloc(void *ptr, size_t new_size);

malloc 和 calloc 之间的主要区别是后者在返回指向内存的指针之前把它初始化为0.

calloc 的参数主要包括所需元素的数量和每个元素的字节数.

realloc 函数用于修改原先已经分配的内存块的大小. 可以使一块内存扩大或缩小. 如果用于扩大一个内存块, 那么这块内存原先的内容依然保留, 新增加的内存添加到 原先内存块的后面, 新内存并未以任何方法进行初始化.

如果它用于缩小一个内存块, 该内存块尾部的部分内存被拿掉, 剩余部分内存原先的 内容依然保留.

如果原先的内存块无法改变大小, realloc 将分配另一块正确大小的内存, 并把原先 那块内存的内容复制到新的块上.

因此使用 realloc 后不能再使用指向旧内存的指针, 应该使用 realloc 返回的 新指针.

如果 realloc 函数的第1个参数是 NULL, 那么它的行为就和 malloc 一模一样.

使用动态分配的内存

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

int main(void)
{
    int *pi, i, *pi2;
    pi = malloc(25 * sizeof(int));
    if (pi == NULL){
        printf("Out of memory!\n");
        exit(1);
    }
    pi2 = pi;
    for (i = 0; i < 25; i++){
        pi2++ = 0;
        pi[i] = 0;
    }
    free(pi);
    return;
}

上面那个内存将被当做25个整型元素的数组, 因为 pi 是一个指向整型的指针.可以使 用间接访问指针运算来访问数组的不同整数位置.不仅可以使用指针, 也可以使用下 标.

常见的动态内存错误

使用动态分配的程序中, 常常会出现许多错误

动态内存分配最常见的错误就是 忘记检查所请求的额呢次是否成功分配

内存泄漏

分配内存使用完毕后不释放将引起内存泄漏(memory leak).

内存泄漏将一点点的榨干可用内存, 最终一无所有.

复制字符串

当拷贝一个字符串时, 内存的容量应该比字符串的长度多一个字节, 以便存储 字符串结尾的 NUL 字节.

总结

动态内存分配允许称为为一个长度在运行时才知道的数组分配内存空间