动态内存分配

来源:互联网 发布:linux上telnet源端口 编辑:程序博客网 时间:2024/05/14 22:00

当一个数组被声明时,它所需要的内存在编译时就被分配。但是也可以通过使用动态内存分配在运行时为它分配内存。
一、为什么要使用动态内存分配?
在声明数组的时候,必须用一个编译时常量指定数组长度,但实际上,数组的长度常常在运行时才知道,这是由于它所需要的内存空间取决于输入数据。所以,有时候,我们开辟的空间可能不够用,这个时候,往往使用动态内存分配。
二、malloc和free以及calloc和realloc

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

工作大致过程:这两个函数维护一个可用内存池。当一个程序另外需要一些内存时,它就调用malloc,malloc从内存池中提取一块适合的内存,并向该程序返回一个指向这块内存的指针。这块内存并没有以任何方式进行初始化。但是初始化非常重要,所以程序员来动手初始化(也可以使用calloc函数)。当一块以前分配的内存不再使用时,程序调用free函数把它归还给内存池供以后之需。
注意:对每个从malloc返回的指针都进行NULL检查是非常重要的。因为当内存池是空的或者无法满足需要的时候,malloc一般会向操作系统请求得到更多的内存,并在这块新内存上执行分配任务。如果操作系统无法向malloc提供更多内存,malloc就会返回NULL指针。
从函数中表达式中,我们可以看出malloc返回的是一个void*指针,所以有时候我们需要类型转换。

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

malloc和calloc的区别:
calloc在返回指向内存的指针之前会把它初始化。calloc的参数包括所需元素的数量和每个元素的字节数。根据这些值,它能够计算出总共需要分配的内存。
realloc用于修改一个原先已经分配好的内存块的大小。可以增或删。
举个小例子:

int *pi;pi = malloc(25*sizeof(int));int *pi2,i;pi2 = pi;for(i = 0; i< 25;i++)/*初始化数组为0*/*pi2++ = 0; //pi[i] = 0;

三、常见错误
对NULL指针进行解引用操作、对分配的内存进行操作时越过边界、释放并非动态分配的内存、试图释放一块动态分配的内存的一部分以及一块动态内存被释放之后被继续使用等。
warning:
动态内存分配最常见的错误就是忘记检查所请求的内存是否成功分配,MALLOC宏接受元素的数目能及每种元素的类型,计算总共需要的内存字节数,并调用alloc获得内存。alloc调用malloc并进行检查,确保返回的指针不是NULL。
代码如下:

/*定义个不易发生错误的内存分配器alloc.h*/#include <stdlib.h>#define malloc  //不要直接使用malloc/*用于防止由于其他代码块直接塞入程序而导致的偶尔直接调用malloc的行为,增加这个指令以后,如果程序偶尔调用了malloc,程序将由于语法错误而无法编译,在alloc中必须加入#undef指令,这样才能调用malloc而不至于出错。*/#define MALLOC(num,type)(type*)alloc((num)*sizeof(type))extren void *alloc(size_t size);/*不易发生错误的内存分配器的实现alloc.c*/#include <stdio.h>#include "alloc.h"#undef mallocvoid *alloc(size_t size){void *new_mem;/*请求所需的内存,并检查确实分配成功*/new_mem = malloc(size);if(new_mem == NULL){printf("out of memory!");exit(1);}return new_mem;}/*一个使用很少引起错误的内存分配器的程序a_client.c*/#include "alloc.h"void function(){int *new_memory;/*获得一串整型空间*/new_memory = MALLOC(25,int);}

内存泄露:申请的内存用完了却不释放,将会引起内存泄漏。内存泄露会榨干操作系统的内存,直到整个程序无法工作,甚至会引起其他工作的丢失。是非常危险的。
四、程序分析
以下给出一个使用malloc的例子:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#define malloc#define MALLOC(num,type) (type *)alloc((num) * sizeof(type))extern void *alloc(size_t size);#undef mallocvoid *alloc(size_t size){    void *new_mem;    new_mem = malloc(size);    if(new_mem == NULL){    printf("out of memory!\n");    exit(1);    }    return new_mem;}int compare_integers(void const* a,void const* b){    register int const* pa = a;    register int const* pb = b;    return *pa > *pb ? 1 : *pa < *pb ? -1 : 0;}int main(){    int *array;    int n_values;    int i;    printf("How many values are there?");    if(scanf("%d",&n_values) != 1 || n_values <= 0){        printf("Illegal number of values.\n");        exit(EXIT_FAILURE);    }    array = MALLOC(n_values,int);    /*array = malloc(n_values * sizeof(int));    if(array == NULL){        printf("Can't get memory for that many values.\n");        exit(EXIT_FAILURE);    }*/    printf("输入:\n");    for(i = 0;i < n_values;i++){        //printf("?");        if(scanf("%d",array + i) != 1){            printf("error reading value #%d\n",i);            free(array);            exit(EXIT_FAILURE);        }    }    qsort(array,n_values,sizeof(int),compare_integers);    printf("结果为:\n");    for(i = 0;i < n_values; i++)        printf("%d ",array[i]);    printf("\n");    free(array);    return EXIT_SUCCESS;}

input:1 5 3 4 2
output:1 2 3 4 5

0 0