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.
静态内存分配: 编译器在编译程序源代码期间进行分配, 如全局变量和静态变量. 静态内存分配所得对象称为静态对象,静态对象为有名字的对象,可以直接对其进行操作. 所以静态对象所占用内存的分配与释放都是由编译器完成的.
动态内存分配: 动态内存分配为在程序运行期间, 由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.
相关文章推荐
- solr搜索打分规制排序
- Android EditText 的属性
- /bin/bash^M: bad interpreter: No such file or dire
- iftop
- Java中的static关键字解析
- 程序员也有文艺的,分享最近读的好诗
- HTTP GET/POST方法对比
- log4j2 日志等级简洁版
- 黑马程序员_多级目录的复制
- android中TextView分段显示不同颜色,字体,时间
- android获取当前经纬度,并用地图显示跟踪
- 网络安全监测
- android的入门学习
- 一致性哈希算法原理设计
- 神经网络编程入门
- 总结GMAT阅读高分的五个解题方法
- PHP中isset与array_key_exists的区别实例分析
- quartz与spring整合实现动态任务增删改查
- C程序编译过程浅析
- [Android] ListView中getView的原理+如何在ListView中放置多个item