您的位置:首页 > 其它

ANSI C动态内存分配与管理函数详解

2015-06-02 15:45 253 查看
在C语言程序当中,数据对象可以使用静态(即数据段, BSS)和动态(堆)的方式分配内存空间.

静态内存分配: 编译器在编译程序源代码期间进行分配, 如全局变量和静态变量. 静态内存分配所得对象称为静态对象,静态对象为有名字的对象,可以直接对其进行操作. 所以静态对象所占用内存的分配与释放都是由编译器完成的.

动态内存分配: 动态内存分配为在程序运行期间, 由malloc等内存分配函数在堆上进行分配, 由此得到的对象为动态对象, 动态对象没有名字, 必须由指针间接地对其进行操作. 动态对象的分配与释放都是由程序员手动进行分配和释放的, 用完之后需要调用free或delete进行释放, 否则会产生内存泄露.

一. 动态内存分配与释放函数:

#include <stdlib.h>

①动态内存分配:

extern void *malloc(size_t __size);

该函数为在堆中分配大小为size个字节的连续内存空间, 成功则返回一个指向所分配的连续内存空间首地址的指针, 失败(内存空间不足)则返回NULL.

extern void *realloc (void *__ptr, size_t size)

realloc为对一块之前分配了内存空间的内存块进行重新分配 ptr为原有内存块, size为希望新分配的内存块的大小, 有三种情况:

1. 若size比ptr原有内存块大小小, 则仅改变索引信息, 但是后面的内存块仍然是不能被访问了的, 已经被交回给了内存分配子程序.

2.当size的大小比原来大时, 则若该内存块后的空闲空间如果足够, 则直接拓展这段内存空间, 返回原指针; 若后面的空闲空间不足, 则内存分配子程序需要在堆中寻找第一块(最先适配)足够大的内存块, 然后将原内存块的内容复制过去, 释放原内存空间, 即ptr指向的内存空间, 返回新内存块的首地址;注意之后不需要也不能再对原指针指向的内存块进行释放了!

3.若分配失败, 则原指针指向的内存块保持不变, 仍有效, 返回NULL

void calloc (size_t nmemb, size_size)

calloc为对malloc进行了封装, 对新分配的内存块进行了初始化为0; nmemb为内存单元的个数, size为内存单元的大小.

如: ptr = (struct data *) calloc (count, sizeof(struct data))

extern void *alloca (size_t __size)

该函数为在栈中分配size个字节的内存空间, 函数返回时会自动释放该空间. 成功返回指针, 失败返回NULL.

②动态内存释放:

extern void free (void *__ptr)

该函数为释放由ptr指向的内存空间, 注意不是指针, 释放后仍可以访问该指针,但是这样是不合法的. 释放后, 该指针所指向的内存将交回给内存分配子程序, 此时内存分配子程序可以将这块内存重新分配给其他内存申请, 这块内存不再属于原有应用程序. 所有最好的实践为: 调用free释放某块内存之后, 将该指针置为null:

free(ptr)

ptr = NULL

好处: 后面对ptr的访问都将立即失败; 后面对ptr的第二次释放不会造成程序崩溃.

同时, 对于内存释放, 还要注意不能对一块内存释放两次, 这种情况通常出现在当两个或多个指针指向同一块内存时, 如:

char *ptr = (char *) malloc(10 * sizeof(char));

char *ptr2 = ptr;

此时ptr与ptr2指向同一块内存, 当调用:

free(ptr)后, 对ptr2不能再调用free(ptr2), 否则会引起程序崩溃.

另外对于指向动态分配的内存的指针不能进行自增操作, 否则之后在释放的时候, 可能会引起错误, 因为此时指针可能指向了其他应用程序的内存空间.

二. 内存管理函数

ANSI C提供的内存管理函数包括逐字节复制memcpy(), memmove(), memccpy(), 内存赋值函数memset(); 还有常用于网络编程中的bcopy()和bzero()

extern void *memcpy (void *__restrict __dest, __const void *__restrict __src, size_t __n)

表示将n个字节从src所指的位置复制到dest所指的位置, 返回目的地址. 注意该函数没有对目的地址可能多余的目的空间进行处理, 同时也没有考虑源空间和目的空间可能重叠的情况. strcpy函数与memcpy类似, 但是strcpy只能用于字符串, 而memcpy是逐字节的复制, 可以用于任何内存的复制(需要进行强制转换). 另外bcopy功能与memcpy类似.

extern void bcopy (__const void *__src, void *__dest, size_t n)

extern void *memmove (__const void *__src, void *__dest, size_t __n)

memmove功能与memcpy类似, 但是在复制之前会检测源地址与目的地址是否重叠, 若是, 则进行处理后在拷贝, 否则直接拷贝.

extern void *memset ( void *__s, int __c, size_t __n)

memset将自s开始后面的n位初始化为值c, 成功返回s的首地址, bzero完成类似的功能, 但初始化为'\0'

extern void *memchr (__const void *__s, int __c, size_t __n)

memchr在一段由s开始的n个字符的内存空间中, 查找某个字符c第一次出现的位置, 找到返回其在字符串中的位置, 失败返回NULL

extern int memcmp (__const void *__s1, __const void *__s2, size_t __n)

比较内存单元s1和s2的前n个字节是否相等; 相等则返回0, s1 < s2则返回-1, s1 > s2则返回1.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: