一、内存申请函数
下面三个是C语言常用的三个内存申请函数,将分别对他们进行介绍。函数头文件“#include <stdlib.h>”。
void* malloc(unsigned size);
void* realloc(void* ptr, unsigned newsize);
void* calloc(size_t numElements, size_t sizeOfElement);
(1)malloc函数
函数的参数size是需要申请的内存长度,单位为字节,如果申请失败则返回NULL,申请成功返回申请到连续内存块的首地址,需要将返回的首地址指针强制转换成目标类型的指针,例如下面代码:
char *p = (char*)malloc(sizeof(char*)*10);
上面malloc申请的内存是没有进行初始化的。
(2)realloc函数
realloc函数是给一个已经申请了内存的指针重新分配内存,即当一个指针指向的内存块不够或有多余时可以使用realloc为其重新分配合适大小的内存,相对于可以根据需要调整内存块的大小。参数ptr为原有的空间地址,newsize是重新申请的地址长度。
char *p = (char *)malloc(10);
p = realloc(p, 20);
最终p指向的地址可能不变,也可能变了,但是p指向的内存块大小变大了,而且p原来内存块内的内容不变。
(重新分配内存后p指向的地址可能会变,变不变是根据实际情况而定的,如果重新分配的内存比原来的大,而且在内存中原来内存块紧跟着的后面有足够的空闲空间可供分配,则p的首地址不变,如果内存中原来内存块紧跟着的后面没有足够的空间可供分配,则系统会从其他地方寻找一段足够大的空闲空间来分配给p,这种情况下p指向的地址就会改变了,原因就是因为不管是malloc还是realloc,其申请的内存块都必须是连续的)。
(3)calloc函数
calloc跟malloc差不多,但calloc比malloc多做了一步操作,就是将申请到的内存块全部初始化为0。参数numElements表示元素个数,sizeOfElement表示每个元素的大小,即calloc申请的内存块大小是numElements * size_t sizeOfElement 字节。
char *p = (char*)calloc(10,sizeof(char*));
(4)内存的释放
free函数传入的参数就是上面申请内存的返回值,也是申请内存的首地址。
void free(void *ptr);
二、内存拷贝函数
函数的头文件:#include <string.h>
函数原型:void *memcpy(void *dest, const void *src, size_t n);
dest -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
src -- 指向要复制的数据源,类型强制转换为 void* 指针。
n -- 要被复制的字节数。
函数实现的功能就是,将src指向的内存的n个字节拷贝到dest指向的内存的位置。
三、驱动代码中内存分配函数
(1)kmalloc()
使用方式,以及原理都和malloc()函数是一样的。函数代码原型如下所示:
/**
* kzalloc - allocate memory. The memory is set to zero.
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate (see kmalloc).
*/
static inline void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
(2)kzalloc()
用kzalloc()申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0。
kzalloc()函数是调用kmalloc()函数实现的,只是增加了申请内存的标志的函数入口参数。
void *__kmalloc(size_t size, gfp_t flags)
{
struct kmem_cache *s;
void *ret;
if (unlikely(size > SLUB_MAX_SIZE))
return kmalloc_large(size, flags);
s = get_slab(size, flags);
if (unlikely(ZERO_OR_NULL_PTR(s)))
return s;
ret = slab_alloc(s, flags, -1, _RET_IP_);
trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
return ret;
}
#include <linux/slab.h> void *kmalloc(size_t size, int flags);
kzalloc()函数的内存申请的标志如下所示:
GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
GFP_KERNEL
内核内存的正常分配. 可能睡眠.
GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
GFP_NOIO
GFP_NOFS
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
本文介绍了C语言中用于内存动态分配的函数malloc,realloc和calloc,包括它们的使用方法和注意事项。malloc申请未初始化的内存,realloc调整已分配内存的大小,calloc则分配并初始化为零的内存。此外,还提到了内核中的内存分配函数kmalloc和kzalloc,其中kzalloc是在kmalloc基础上自动进行内存初始化的函数,涉及的内存分配标志如GFP_ATOMIC和GFP_KERNEL等。

9077

被折叠的 条评论
为什么被折叠?



