IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 手撕内存拷贝函数 memmove、memcpy -> 正文阅读

[C++知识库]手撕内存拷贝函数 memmove、memcpy

memcpy

??C 和 C++ 使用的内存拷贝函数,函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源 source 中拷贝 n 个字节到目标 destin 中。

函数原型

#include <string.h>		// C语言包含该函数的头文件
#include <cstring>		// C++包含该函数的头文件

void *memcpy(void *str1, const void *str2, size_t n)

参数说明
str1 —— 指向用于存储复制内容的内存起始地址,函数调用时类型强制转换为 void* 指针
str2 —— 指向要复制的数据源的内存起始地址,函数调用时类型强制转换为 void* 指针
n ?? —— 要被复制的内存长度(字节数)
?
关于 void* 指针
??void* 指针,即不定类型指针。C 语言中指针仅占 4 个字节,即存储了一个内存地址,因此编译器在编译指针时必须知道它的类型(即 * 号前的部分),才能决定读取数据的长度。如 char* 指针,即 char 类型指针,编译器会从它指向的内存地址起只读取 1 个字节进行编译;而对于 int* 指针,即 int 类型指针,编译器则会从它指向的内存地址起读取 4 个字节。
??在 C 语言中 void 一般表示 “空”、“无” 的意思,因此,void* 指针即为 “无类型指针”,正式称呼为 “不定类型指针”。大家也可以将其理解为 C 语言中指针的默认类型。因为不知道指针类型,编译器无法直接对 void* 指针操作,程序员在使用 void* 指针时必须将其转换为其他类型的指针来使用,具体用法可以看下面的代码示例。
??至于为什么 memcpy 参数和返回值要用 void* 指针,个人理解一方面是为了标准化,规范化,提高普适性,统一输入输出接口;另一方面也是防止程序员忘记进行类型转换吧,毕竟返回的 void* 不转类型就会报错。
?
关于 size_t 类型
??简单理解,C语言中,它底层就是一个 unsigned int 。使用 size_t 主要还是为了提高代码的可移植性、有效性或者可读性。在不同的语言中,不同的平台上,size_t 的定义也许不一样,但这都不是当前程序员关心的问题,我只需要开放接口给后来人就行了。

memcpy

实现思路

  • 一句话概括:按照一定顺序,逐字节拷贝。
  1. 函数接口:
    · 用两个 void* 指针接收目标内存地址和源内存地址,一个无符号整型接收内存拷贝长度
    · 注意给源内存地址的形参加 const(加在数据类型左边,保护指向的内容),防止篡改原始数据
    · 返回值类型也是 void* 指针(保证接口的通用性)
    · 得到函数接口 void* memcpy(void* dst, const void* src, unsigned int count)
  2. 主体部分:
    · 先定义返回值 void* ret = dst; return ret;(返回的是目标内存区域的首地址)
    · 拷贝顺序就用简单的正序拷贝实现,即从头开始,逐字节拷贝 count 次
    · 用 while 循环实现迭代操作,while ( count-- ) 正好可以跑 count 次
    · 循环内部:先赋值,再偏移。( void* 无法直接运算或解引用,需要先转换类型)
    · 赋值操作:(char *)dst = *(char *)src;
    · 偏移操作:dst = (char *)dst + 1; src = (char *)src + 1;

手撕代码

void* memcpy(void* dst, const void* src, unsigned int count)
{
    void* ret = dst;
    while ( count-- )
    {
        *(char *)dst = *(char *)src;
        dst = (char *)dst + 1;
        src = (char *)src + 1;
    }
    return ret;
}

面试注意要点

  • 第 1 行:函数接口必须不能错!尤其是 src 前必须加 const 修饰,进行保护。
  • 第 3 行:先写返回值,即将目标内存地址保存下来用于返回。
  • 第 4 行:循环条件,根据拷贝长度逐字节循环拷贝,必须用 count-- 不能 --count。
  • 第 6 行:void* 指针每次使用时要先进行类型转换。
  • 第 7-8 行:指针偏移操作,这也是为什么第 3 行要先写返回值。

memmove

函数原型

#include <string.h>		// C语言包含该函数的头文件
#include <cstring>		// C++包含该函数的头文件

void *memmove(void *str1, const void *str2, size_t n)

memmove 和 memcpy 的区别

  • memmove 会检查内存重叠是否,但 memcpy 不会
  • 当源内存区域的尾部与目标内存区域的头部重叠时,memmove 会采用倒序拷贝的策略
  • 即如下图所示,前两种情况 memmove 采用正序拷贝,第三种情况采用倒序拷贝

memcpy_vs_memmove

实现思路

  • 一句话概括:检测内存是否重叠,无重叠则正序逐字节拷贝,重叠则倒序逐字节拷贝。
  1. 函数接口:
    · 跟 memcpy 思路一样,void* memmove(void* dst, const void* src, unsigned int count)
  2. 内存重叠判断:
  3. 主体部分:
    ·

手撕代码

void* memmove(void* dst, const void* src, unsigned int count)
{
    void* ret = dst;
    if ( dst <= src || dst >= (char *)src + count )
    {
        while (count--)
        {
            *(char *)dst = *(char *)src;
            dst = (char *)dst + 1;
            src = (char *)src + 1;
        }
    }
    else
    {
        dst = (char *)dst + count - 1;
        src = (char *)src + count - 1;
        while ( count-- )
        {
            *(char *)dst = *(char *)src;
            dst = (char *)dst - 1;
            src = (char *)src - 1;
        }
    }
    return ret;
}

面试注意要点

  • 第 4 行:内存重叠的检查条件必须不能写错!
  • 其余手撕代码重点与 memcpy 相同

?

总结

??memcpy 和 memmove 是程序员面试的经典考题,属于底层代码的复现,外企尤其爱考这些题。这两个函数代码非常短,思想也很简单,短短几行却包含了很多细节考点,很容易考察出程序员的基本功。建议务必背熟,最好能做到行云流水,一气呵成!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-08 13:38:17  更:2021-12-08 13:39:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:23:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码