内存操作函数:memcmp、memcpy、memmove、memset 的使用与模拟。

这些函数使用前先在 MSDN 上查看一下该函数的使用。

先提前介绍一下下来看到的 void* 、const void*、void const*,const 是为了保证不改变修饰的东西(比如整型,指针等等,看具体修饰是什么吧)。

而 void 是什么意思呢?

我们知道如果返回值是 int 类型的话,那么最后返回必须是 int 类型,返回值是 char 类型的话,返回也必须是 char,还有很多类型!当然参数也是如此,什么类型参数,就用什么类型参数。

那么 void 类型是不是返回就是 void 类型呢?参数也就是 void 类型呢? 答案:当然不是!

因为编写这个函数的程序员,他们也不知道将来我们具体用这个函数到底是要用到什么类型,所以用 void 编写了这个函数(如果说错了请指正)。

我这么举例吧:

现在的垃圾桶是不是都分类了,有可回收、不可回收、厨余垃圾等等,这些垃圾桶对应的也是相应的垃圾。但是我们不能把不可回收的垃圾扔进可回收垃圾桶或者别的垃圾桶里去(但是你要是强行杠,说我就扔不对应的垃圾桶怎么了,那我也没办法)。而这些垃圾桶相当于是一些类型,比如 int、char、double 等等,他们只能接收对应的类型。

然而 void 相当于一个什么类型的垃圾都可以放的垃圾桶,没有限制,这么说懂了吗?

但是我们在使用的时候要强转为要使用的类型就好了,每次用什么类型做,就强转为什么类型。

这就是 void 的介绍,void* 亦是如此。

1. memcmp 函数的使用。

如下,memcmp 函数的返回类型是 int ,参数1 和 参数2 是比较的两个 void const* 类型的,参数3 是 size_t 类型的,比较的是字节数(以字节为单位比较)。

之所以 参数1 和 参数2 是 void const* 是因为 memcmp 函数只是做比较,不改变参数内部内容,所以加 const 修饰。

memcmp函数简单使用一下,代码如下:

#include <stdio.h>
#include <string.h>
 
// 以字节为单位比较大小
 
int main()
{
    int arr1[5] = { 1,2,3,4,5 };
                           // 05 00 00 00
    int arr2[5] = { 1,2,3,4,0x01020405 };
                           // 05 04 02 01
                           // 所以前 17 个字节都相等
    // int ret = memcmp(arr1, arr2, 16); // 相等
    // int ret = memcmp(arr1, arr2, 17); // 相等
    int ret = memcmp(arr1, arr2, 18); // 不相等
 
    if(0 == ret)
    {
        printf("=\n");
    }
    else if(ret > 0)
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
 
    printf("%d\n", ret);
    return 0;
}

2. memcpy 函数的使用。

如下,memcpy 函数的返回类型是 void* ,参数1 是 void* 类型的指针,参数2 是const void * 类型的,参数3 是 size_t 类型的,是以字节为单位拷贝。

参数2 加 const 是因为 参数2 是被拷贝的不改变,而 参数1 是接收拷贝的要改变参数1,所以 参数1 不加 const。

memcpy函数简单使用一下,代码如下:

#include <stdio.h>
#include <string.h>
 
// 以字节为单位拷贝 任何类型
 
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
    
    memcpy(arr2, arr1, 20);
    
    for(int i = 0; i < 10; i++)
    {
        printf("%d ", arr2[i]);
    }
    printf("\n");
 
 
    // int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    // memcpy(arr1+2, arr1, 20);
    // // 理想输出 1 2 1 2 3 4 5 8 9 10
    // // memmove 函数重叠内存拷贝
    // // memcpy 虽然也可以 但是仅限有的编译器
    // for(int i = 0; i < 10; i++)
    // {
    //     printf("%d ", arr1[i]);
    // }
    // printf("\n");
 
    return 0;
}

模拟使用 memcpy 函数,如下: 

#include <stdio.h>
#include <assert.h>


void* My_memcpy(void* dest, const void* src, int count)
{
    assert(dest && src);
    char* ret = (char*)dest;
    while(count--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest+1;
        src = (char*)src+1;
    }
    return ret;
}

int main()
{
    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };

    My_memcpy(arr2, arr1, 20);
    for(int i = 0; i < 10; i++)
    {
        printf("%d ", arr2[i]);
    }
    printf("\n");

    My_memcpy(arr1+2, arr1, 20);
    // 理想输出 1 2 1 2 3 4 5 8 9 10
    // 实际输出 1 2 1 2 1 2 1 8 9 10
    // 因为 1 2 拷贝过去就把后面的数字覆盖了
    // 所以有个 memmove 函数可以覆盖拷贝
    for(int i = 0; i < 10; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");

    return 0;
}

3. memmove 函数的使用。

如下,memmove 函数的返回类型是 void* ,参数1 是 void* 类型的指针,参数2 是const void * 类型的,参数3 是 size_t 类型的,是以字节为单位拷贝,但是 memmove 函数可以实现重叠内存拷贝。(下一篇我会模拟 memcpy函数 与 memmove函数)

参数2 加 const 是因为 参数2 是被拷贝的不改变,而 参数1 是接收拷贝的要改变参数1,所以 参数1 不加 const。

memmove函数简单使用一下,代码如下:

#include <stdio.h>
#include <string.h>
 
// memmove 可以实现重叠内存拷贝
// 以字节为单位拷贝
 
int main()
{
    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    memmove(arr1+3, arr1, 20);
 
    for(int i = 0; i < 10; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");
 
    return 0;
}

memmove函数的模拟,如下:

 

#include <stdio.h>
#include <assert.h>

#define N 10

// 原数组是              1  2  3  4  5  6  7  8  9  10
// 重叠拷贝              3  4  5  6  7  6  7  8  9  10
// 或者                  1  2  3  4  3  4  5  6  7  10
// 或者                  1  2  3  4  5  1  2  3  4  5
//
// 第 1 种:
// ↓ 我应该从前往后放, 从 3 往前拿往 1 那里放, 然后给后走
// 3  4  5  6  7  6  7  8  9  10
//             ↓  如果我从后往前放 7 开始往 5 这里放, -那么就会出现被覆盖的数            
// 6  7  6  7  6  7  7  8  9  10
//
// 第 2 种:
//                         ↓  我应该从后往前放, 从 7 开始往 9 这里放, 然后往前走
// 1  2  3  4  3  4  5  6  7  10
//             ↓ 如果从前往后放, 从 3 开始往 5 那里放, 那么就会出现被覆盖的数 
// 1  2  3  4  3  4  3  4  3  10
//
// 还有比如
// 1  2  3  4  5  6  7  8  9  10
// 1  2  3  4  5  1  2  3  4  5
// 那么从前往后、从后往前都可以


void* My_memmove(void* dest, const void* src, int count)
{
    assert(dest && src);
    void* ret = dest;

    // 1. 前->后; 后->前; 后->前 
    if(dest < src)
    {
        // 前->后
        while(count--)
        {
            (*(char*)dest) = *(char*)src;
            dest = (char*)dest+1;
            src = (char*)src+1;
        }
    }
    else
    {
        // 后->前
        while(count--)
        {
            ( *((char*)dest+count) ) = ( *((char*)src+count) );        
        }
    }

    // 2. 前->后; 后->前; 前->后  
    // if( src < dest && dest < ((char*)src+count) )
    // {
    //     // 后->前

    // }
    // else
    // {
    //     // 前->后

    // }
    return ret;
}

int main()
{
    int arr1[N] = { 1,2,3,4,5,6,7,8,9,10 };
    // My_memmove(arr1+3, arr1, 20);
    My_memmove(arr1, arr1+3, 20);
    for(int i = 0; i < N; i++)
    {
        printf("%d ", arr1[i]);
    }
    printf("\n");

    return 0;
}

4. memset 函数的使用。

如下,memset 函数的返回类型是 void* ,参数1 是 void* 类型的指针,参数2 是 int 类型的,参数3 是 size_t 类型的,是以字节为单位初始化内存单元。

memset 函数简单使用一下,如下:

#include <stdio.h>
#include <string.h>
 
// memset 以字节为单位初始化内存单元
 
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    memset(arr, 1, 12);
    // 相当于把 01 00 00 00 02 00 00 00 03 00 00 00 这 12 个字节
    // 初始化为了 01 01 01 01 01 01 01 10 01 01 01 01 
    // 是以字节为单位初始化
    for(int i = 0; i < 10; i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
 
    return 0;
}

以上就是内存操作函数的使用与模拟,如果有错误的请指正。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值