C语言中常用的内存申请和拷贝函数

本文介绍了C语言中用于内存动态分配的函数malloc,realloc和calloc,包括它们的使用方法和注意事项。malloc申请未初始化的内存,realloc调整已分配内存的大小,calloc则分配并初始化为零的内存。此外,还提到了内核中的内存分配函数kmalloc和kzalloc,其中kzalloc是在kmalloc基础上自动进行内存初始化的函数,涉及的内存分配标志如GFP_ATOMIC和GFP_KERNEL等。

一、内存申请函数

        下面三个是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 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值