您的位置:首页 > 其它

动态申请内存及相关补充

2017-04-18 10:06 148 查看
转载前注明出处 欢迎转载分享
void*malloc(int size);
对于malloc来说,如果不能分配空间,那么返回NULL,如果请求空间大小为0即malloc(0),则返回NULL或一个有效的指针。

void*calloc(int n, int size);
函数返回值为void型指针。如果执行成功,函数从堆获得size*n的字节空间,并返回该空间的首地址。若执行失败,函数返回NULL。该函数与malloc的显著不同是,calloc函数得到的内存空间是经过初始化的,其内容全为0,calloc函数适合为数组申请空间,可以将size设置为数组元素的空间长度,将n设置为数组的容量。注意:calloc分配的内存也需要自行释放。

void*realloc(void *ptr, int size);
使用realloc函数,把原内存空间的指针ptr传给realloc,通过参数size指定新的大小(字节数),realloc返回新内存空间的首地址,并释放原内存空间。新内存空间中的数据尽量和原来保持一致,如果size比原来小,则前size个字节不变,后面的数据被截断,如果size比原来大,并且要多申请的空间在原空间后面足以连续申请,则原来的数据全部保留,后面长出来的一块内存空间未初始化(realloc不负责清零),但若多出来要申请的空间在原空间后无法连续申请时,则重新找出一片size字节的空间,将原来的数据拷贝过来,并且自动释放掉realloc之前的旧空间。注意,参数ptr要么是NULL,要么必须是先前调用malloc、calloc或realloc返回的指针,不能把任意指针传给realloc要求重新分配内存空间。作为两个特例,如果调用realloc(NULL,size),则相当于调用malloc(size),如果调用realloc(ptr,0),ptr不是NULL,则相当于调用free(ptr)。

浅谈sbrk函数
sbrk允许我们操作堆,sbrk(0)会返回指向当前堆顶部的指针,sbrk(foo)会增加foo字节的堆空间并返回指向当前堆顶部的指针,当调用sbrk不成功时则返回-1。

以下是malloc运用sbrk的简单实现:

 C Code 
1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include < assert.h >
#include < string.h >
#include < sys/types.h >
#include < unistd.h >

void *malloc(size_t size)

{

    void *p = sbrk(0);

    void *request = sbrk(size);

    if(request == (void *) - 1)

        return NULL;//sbrk failed
    else

    {

        assert(p == request);//Not thread safe
        return
 p;

    }

}


堆栈帧:
堆栈帧保存的是一个函数调用所需要维护的所有信息。它主要包含三个内容:

函数的返回地址和参数
临时变量:包含函数的非静态局部变量以及编译器自动生成的其它临时变量
保存的上下文:包括在函数调用前后需要保存不变的寄存器值

在i386中,一个函数的活动记录用ebp和esp这两个寄存器来划定范围。esp始终指向栈的顶部,同时也指向当前活动记录的顶部,相对的,ebp指向函数活动记录的一个固定位置,ebp又被称为帧指针。

程序中的栈有其堆栈帧(活动记录)如图:







参数及参数之后的数据是当前的活动记录,ebp固定在上图的位置,不随函数的执行而改变,相反地,esp始终指向栈顶,因此随着函数的执行,它总是变化的。ebp+4是这个函数的返回地址,ebp+8、ebp+12等是这个函数的参数。ebp指向的是调用该函数前ebp的值,这样在函数返回的时候,ebp就可以通过这个恢复到调用前的值。ebp下面的值是要保存的寄存器的值和函数中的局部变量,当然也可以不保存ebp的值,不过这样会减慢帧上寻址速度和无法准确定位函数的调用轨迹。

参考资料http://www.cnblogs.com/chengxuyuancc/archive/2013/05/28/3104769.html

系统对堆空间的管理方式:空闲链表法
空闲链表如图:





假设我们malloc(sizeof(int)),系统不会去将12Bytes大小的空间分为3个4Bytes然后再将其中一个分给我们,系统会找到节点为5Bytes的空间,将其空间地址返回,也就是说系统会找到最小并且能容纳我们所申请空间大小的空间来返回给我们这个空间的地址。如果我们的空间都申请完了,那么我们指向节点的指针就指向NULL了,所以返回的就是NULL,这就是为什么malloc动态申请内存不成功会返回NULL的原因,也提醒我们malloc后要free掉这片空间,以免内存泄露。

C中需要注意的的规则习惯:
1)用malloc申请内存后,应立即检查指针值是否为NULL,防止使用值为NULL的指针。 

1

2

3

4

5

6

int *p = (int *)malloc(5 * sizeof(int));
if(p != NULL)

{

    //do something here!
}

free(p);


2)牢记数组长度,防止数组越界操作,考虑使用柔性数组 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

typedef struct soft_array

{

    int len;

    int array[];

} SoftArray;

int i = 0;

SoftArray *sa = (SoftArray *)malloc(sizeof(SoftArray) + sizeof(int) * 10);

sa->len = 10;

for(i = 0; i < sa->len; i++)

{

    sa->array[i] = i + 1
;

}


3)动态申请的操作必须和释放操作匹配,防止内存泄露和多次释放

4)free指针之后必须立即赋值为NULL
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: