详解C语言中内存分配函数

详解C语言中内存分配函数

很多新学C语言的童鞋在用到动态内存分配的时候,对选择哪种分配函数及其有何区别搞不清楚,那么下文就认真的讲讲它们的种种。

(1)C语言的内存分配方式

  • 从静态存储区域分配
    这些在程序编译的时候就已经分配好,且在程序的整个运行期间都固定不变。

使用这种方式分配内存空间的数据主要包括:
代码段(DATA Section)的程序自身语句文本(包括嵌在代码里的字符串常量),已经初始化的全局变量静态变量

.BSS段的未初始化的全局变量

  • 在栈stack上分配

这种方式由系统自动分配,函数退出时也由系统自动释放。

使用这种方式分配内存空间的数据主要包括:
本地变量函数参数

  • 从堆heap上分配,亦称动态内存分配

程序在运行的时候用malloc类或new动态申请的内存,由用户自己负责用free或delete释放。动态内存的生存期由用户决定,使用非常灵活,但问题也最多。

使用这种方式分配内存空间的数据主要包括:
自定义输入缓存用于接收用户输入数据的变量(数组、结构体等)

(2)跟内存申请相关的函数

void* malloc(size_t size)

作用:从堆中分配size个字节的空间,成功则返回空间首地址,失败则返回空指针。它的声明位于stdlib.h头文件中。

我们在编程中必须注意分配失败的情况,以使程序更加健壮和完备。所以一般会对其进行包装:

        void *
xmalloc (size_t size)
{
    void *value = malloc (size);
    if (value == 0)
        fatal ("virtual memory exhausted");
    return value;
}

      

同时,由于它并没有对分配的空间进行任何操作,因此基本上malloc之后,需要调用函数memset来初始化。

        struct foo *ptr;
...
ptr = (struct foo *) malloc (sizeof (struct foo));
if (ptr == 0) 
    abort ();
memset (ptr, 0, sizeof (struct foo));

      

void * calloc (size_t count, size_t eltsize)

作用:从堆中分配size个字节的已经清零的空间,成功则返回空间首地址,失败则返回空指针。它的声明位于stdlib.h头文件中。

它的实现等同于:

        void *
calloc (size_t count, size_t eltsize)
{
    size_t size = count * eltsize;
    void *value = malloc (size);
    if (value != 0)
        memset (value, 0, size);
    return value;
}

      

void * realloc (void *ptr, size_t newsize)

作用:用来对之前申请的动态内存重新进行分配大小(扩容或缩小)。

参数解释:ptr必须为之前通过malloc或calloc等函数申请的动态内存首地址;newsize为你现在需要的大小。

注意事项:
1 如果是扩容,它不能保证后加的空间一定是接在原来申请的内存空间之后的,因为有可能其之后的空间已经被使用了。此时系统会找一块大小符合你要求的连续空间,并同时把原来空间内容复制到新空间,最后再释放原空间。

2 如果扩容失败,则原空间内容不受影响。

3 如果参数ptr为空,则其动作同malloc。

但是当我们使用时,为了程序的健壮性和完备性,在使用时我们需要包装一下:

        void *
xrealloc (void *ptr, size_t size)
{
    void *value = realloc (ptr, size);
    if (value == 0)
        fatal ("Virtual memory exhausted");
    else
        return value;

      

void * reallocarray (void *ptr, size_t nmemb, size_t size)

该函数作用及各参数同realloc,唯一的不同是当发生乘法溢出时,会进行错误提示。

void * aligned_alloc (size_t alignment, size_t size)

作用:函数分配一个地址alignment对齐的大小为size的内存空间。

参数解释:alignment代表地址对齐参数,必须为2的倍数,且size也必须是alignment的倍数。
如果分配成功则返回内存首地址,否则返回空,同时依据错误原因设置错误代码errno为ENOMEN或EINVAL