现在的位置: 首页 > 综合 > 正文

内存动态分配

2013年04月22日 ⁄ 综合 ⁄ 共 3270字 ⁄ 字号 评论关闭

 

数组的元素存储于内存中连续的位置上。当一个数组被声明时,它所需要的内存在编译时就被分配。但是,你也可以使用动态内存分配在运行时为它分配内存。

malloc所分配的是一块连续的内存。例如,如果请求它分配100个字节的内存,那么它实际分配的内存就是100个连续的字节,并不会分开位于两块或多块不同的内存。同时malloc实际分配的内存有可能比你请求的稍微多一点。但是,这个行为是由编译器决定的,所以你不能指望他肯定会分配比你的请求更多的内存。

如果内存池是空的,或者它的可用内存无法满足你的要求。在这种情况下,malloc函数向操作系统请求,要求得到更多的内存,并在这块新内存上执行分配任务。如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针。因此,对每个malloc返回的指针都进行检查,确保它并非NULL是非常重要的。

free的参数必须要么是NULL,要么是一个先前从malloc、calloc或realloc返回的值。向free传递一个NULL参数不会产生任何效果。

malloc返回一个类型为void*的指针,正是源于这个原因。标准表示一个void *类型的指针可以转换为其他任何类型的指针。但是,有些编译器,尤其是那些老式的编译器,可能要求你在转换时使用强制类型转换。

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

 

calloc也用于内存分配。malloc和calloc之间的主要区别是后者在返回指向内存的指针之前把它初始化为0.这个初始化常常能带来方便,但如果你的程序只是想把一些值存储到数组中,那么这个初始化过程纯属浪费时间。calloc和malloc之间另一个较小的区别是他们请求内存数量的方式不同。calloc的参数包括所需元素的数量和每个元素的字节数。根据这些值,它能够计算出总共需要分配的内存。

 

realloc函数用于修改一个原先以及你给分配的内存块的大小。使用这个函数,你可以使一块内存扩大或缩小。如果它用于扩大一个内存块,那么这块内存原先的内容依然保留,新增加的内存添加到原先内存块的后面,新内存并未以任何方式进行初始化。如果它用于缩小一个内存块,该内存块尾部的部分内存便被拿掉,剩余部分内存的原先内容依然保留。

 

如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上。因此,在使用realloc之后,你就不能再使用指向旧内存的指针,而是应该用realloc所返回的新指针。

 

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


常见的动态内存错误

在使用动态内存分配的程序中,常常会出现许多错误。这些错误包括对NULL指针进行解引用操作、对分配的内存进行操作时越过边界、释放并非动态分配的内存、试图释放一块动态分配的内存的一部分以及一块动态内存被释放之后被继续使用。

 

两大来源:

第一种错误显而易见:被访问的内存可能保存了其他变量的值,对它进行修改将破坏那个变量,修改那个变量将破坏你存储在那里的值。这种类型的Bug非常难以发现。(有时候Bug可以理解为特性,只要你能把它管理好)

第二种问题不是那么明显。在malloc和free的有些实现中,它们以链表的形式维护可用的内存池。对分配的内存之外的区域进行访问可能破坏这个链表,这有可能产生异常,从而终止程序。

 

一种不易发生错误的内存分配方案:

alloc.h

 

#include <stdlib.h>

#define malloc

#define MALLOC(num,type) (type *)alloc( (num) * sizeof(type))

extern void *alloc(size_t size);

 

alloc.c

#include <stdio.h>

#include "alloc.h"

#undef malloc

void *

alloc(size_t size)

{

    void *new_mem;

    new_mem = malloc(size);

    if(new_mem == NULL){

     printf("Out of memmory!/n")

}

    return new_mem;

}

 

a_client.c

 

#include "alloc.h"

void

function()

{

    int *new_memory;

    new_memory = MALLOC(25,int);

 

}

 

free产生的错误

当使用free时,可能出现各种不同的错误。传递给free的指针必须是一个从malloc、alloc或realloc函数返回的指针。传给free函数一个指针,让它释放一块并非动态分配的内存可能导致程序立即终止或在晚些时候终止。试图释放一块动态分配内存的一部分也有可能引起类似的问题。

 

释放一块内存的一部分是不允许的。动态分配的内存必须整块一起释放。但是,realloc函数可以缩小一块动态分配的内存,有效的释放它尾部的部分内存。

 

内存泄露

当动态分配的内存不再需要使用时,它应该被释放,这样它以后可以被重新分配使用。分配内存但在使用完毕后不释放将引起内存泄露(memory leak)。在那些所有执行程序共享一个通用内存池的操作系统中,内存泄露将以点点的榨干可用内存,最终使其一无所有。要摆脱这个困境,只有重启系统。

其他操作系统能够记住每个程序当前拥有的内存段,这样当一个程序终止时,所有分配给他但未被释放的内存都归还给内存池。但即使在这类系统中,内存泄露仍然是一个严重问题,因为一个持续分配却一点不释放内存的程序最终将耗尽可用的内存。此时,这个有缺陷的程序将无法继续执行下去,它的失败有可能导致当前已经完成的工作统统丢失。

 

scanf的返回值

scanf("%d%d", &a, &b);

如果a和b都被成功读入,那么scanf的返回值就是2
如果只有a被成功读入,返回值为1
如果a和b都未被成功读入,返回值为0
如果遇到错误或遇到end of file,返回值为EOF。

排序程序


抱歉!评论已关闭.