C语言中的内存函数有如下这些

  • memcpy
  • memmove
  • memcmp
  • memset

下面看看memcpy函数

memcpy

我们想想,之前有那个字符串拷贝的函数,即strcpy函数。都有拷贝的函数了,为什么还要这个内存拷贝函数呢?

C语言-字符串函数的实现(二)之strcpy

不能直接用strcpy吗?这是一个好问题,那下面就试试它。

我们准备两个整型数组,分别为arr1和arr2,然后通过strcpy函数把arr1的内容拷贝到arr2中,代码如下

int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
// 把arr1的内容拷贝到arr2中
strcpy(arr2, arr1);
return 0;
}

那么这里肯定会有警告,因为类型不同。

直接运行,通过Debug,看内存,可以发现实现不了完整的拷贝,strcpy只拷贝了一个字节

显然,strcpy函数不适用于其他类型的数据拷贝,所以呢,就出现内存拷贝了,使任意类型的数据都能进行拷贝

老规矩,我们还是看看文档是怎样说的,如下

memcpy文档

void * memcpy ( void * destination, const void * source, size_t num );

Copy block of memory

拷贝内存块(拷贝内存数据)

Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.

从source(源内存块位置)直接指向的地方开始复制num个字节的数据到destination指向的内存块位置。

The underlying type of the objects pointed to by both the source and destination pointers are irrelevant for this function; The result is a binary copy of the data.

这句话没看懂,不影响我们学这个。

The function does not check for any terminating null character in source - it always copies exactly num bytes.

这个函数不会检查'\0',不会遇到'\0'就停下来,它就只认识要复制的num个字节数据。

To avoid overflows, the size of the arrays pointed to by both the destination and source parameters, shall be at least num bytes, and should not overlap (for overlapping memory blocks, memmove is a safer approach).

为了避免溢出,这两个数组的大小至少为num个字节,而且这两个数组内存位置不应该重叠。

我们从文档中可以看出

  1. 参数中除了要复制的字节数num,其他的参数类型基本都是void*,返回值也是void*
  2. 该函数是从source的位置开始向后复制num个字节的数据到destination的内存位置。
  3. 该函数在遇到 '\0' 的时候并不会停下来。
  4. sourcedestination不能有有任何的重叠。

实现

void* 不能直接解引用,那么如何复制呢?答案是进行类型强转,转换成char*,一个一个字节地复制过去。

一开始得先搞一个指针变量*rest来存储dest,不然目的地址后面发生改变就不知道地址是哪里了。接下来就是主要操作了,把src指向的数据复制给dest,即*(char*)dest = *(char*)src,然后这两个指针都进行偏移,往后走,继续复制,就是循环下去了,直到num个字节复制完就结束,返回目的地址rest。代码如下

断言指针不为空是个好习惯~

void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest != NULL);
assert(src != NULL);
void* rest = dest;
// void* 不能直接解引用,那么如何复制呢?
// 给了num个字节,也就是需要复制num个字节
// 那就转换成char*,一个一个字节的复制过去
while (num--)
{
*(char*)dest = *(char*)src;
//++(char*)dest;
//++(char*)src;
((char*)dest)++;
((char*)src)++;
}
return rest;
}

以上,就是memcpy函数的实现。

测试代码

我们就使用下面的测试代码,测试下自己实现的my_memcpy函数,通过Debug来观察内存数据的变化。

struct S
{
char name[20];
int age;
}; int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 }; my_memcpy(arr2, arr1, sizeof(arr1)); struct S arr3[] = { {"LeBron", 36}, {"Kobe", 41} };
struct S arr4[3] = { 0 }; my_memcpy(arr4, arr3, sizeof(arr3)); return 0;
}

C语言-内存函数的实现(一)之memcpy的更多相关文章

  1. C语言-内存函数的实现(二)之memmove

    C语言中的内存函数有如下这些 memcpy memmove memcmp memset 下面看看memmove函数 memmove 为什么会需要memmove函数? int main() { int ...

  2. C语言内存函数

    http://see.xidian.edu.cn/cpp/u/hs3/ 函数 说明 calloc() 分配内存空间 free() 释放内存空间 getpagesize() 取得内存分页大小 mallo ...

  3. C语言 mmap()函数(建立内存映射) 与 munmap()函数(解除内存映射)

    mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和, 最后一个页不被使用的空间将会清零.mmap在用户空间映射调用系统中作用很大. 条件 mmap()必 ...

  4. C语言-自定义函数

    C语言自定义函数 --1-- 自定义函数定义 1.1 无参无返回值函数 1.2 无参有返回值函数 1.3 有参无返回值函数 1.4 有参有返回值函数 --2-- 函数的参数 2.1 形式参数介绍和使用 ...

  5. C语言的函数

    "函数"在英文的翻译是"function",无论在自然科学还是计算机科学都是这个词,而"function"的本意是"功能" ...

  6. 【转载】 c语言inline函数的使用

    c语言inline函数的使用 转载自:http://blog.chinaunix.net/uid-21843265-id-3056446.html 大学在教科书上学习过inline函数,定义为inli ...

  7. 【C语言】函数和自定义函数

    函数,我之前也提到过一点点内容.其实函数是很好理解的,但是写起来又十分麻烦. 一.     函数引入 我们知道,C源程序是由函数组成的.请看下面的简单函数例子 #include <stdio.h ...

  8. linux内核申请内存函数

    kmap函数:    把某块高端内存映射到页表,然后返回给用户一个填好vitual字段的page结构    建立永久地址映射,不是简单的返回virtual字段的pageioremap:    驱动程序 ...

  9. c语言内存模型

    文章一.C语言的内存分配模型 1.程序代码区:存放函数体的二进制代码. 2.全局区数据区:全局数据区划分为三个区域.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化 ...

随机推荐

  1. Element-UI远程搜索功能详解

    官方代码: <template> <div> <el-autocomplete v-model="state" :fetch-suggestions= ...

  2. CentOS7安装ElasticSearch7.9.2

    1:下载 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.2-linux-x86_64.tar. ...

  3. 将VMware工作站最小化到托盘栏

    目录 前言 将VMware最小化到托盘栏的方法 1.下载 Trayconizer 2.解压 trayconizerw.zip 3.创建 VMware 快捷方式 4.修改 VMware 快捷方式 5.运 ...

  4. 如何用Eggjs从零开始开发一个项目(2)

    在上一篇文章,我们已经使用Sequelize连接上了数据库,并能进行简单的数据库操作,在此基础上,我们试着来开发一个完整的项目.这篇文章我们从用户的注册.登录着手,试着开发用户模块的相关的代码. 用户 ...

  5. python中yield的用法详解——最简单,最清晰的解释

    转载自https://blog.csdn.net/mieleizhi0522 首先我要吐槽一下,看程序的过程中遇见了yield这个关键字,然后百度的时候,发现没有一个能简单的让我懂的,讲起来真TM的都 ...

  6. Omega System Trading and Development Club内部分享策略Easylanguage源码 (第二期)

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 我们曾经在前文(链接),为大家分享我们精心整理的私货:"System Trading and ...

  7. dubbo实战之一:准备和初体验

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. 设计模式之工厂方法模式(Factory Method Pattern)

    一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...

  9. Java 哈希表(google 公司的上机题)

    1 哈希表(散列)-Google 上机题 1) 看一个实际需求,google 公司的一个上机题: 2) 有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址..),当输入该 ...

  10. 测试平台系列(3) 给Hello World添加日志

    给Hello World添加日志 回顾 通过上篇内容,我们已经使用「Flask」完成了我们的第一个接口.我们可以看到,使用「Flask」来编写接口是十分简单的.那么接下来,我们丰富一下上面的例子. 需 ...