C语言内存操作函数

8/24/2023 C语言

# C 语言内存操作函数

# memcpy

先思考一个问题,字符串拷贝可以用strcpy,那如何拷贝数组呢?

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.

复制内存块

num 个字节的值从 source 指向的位置直接复制到 destination 指向的内存块。

使用如下。

#include <memory.h>

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

		memcpy(arr2, arr1, 20); // arr2 : {1, 2, 3, 4, 5 }
}

如何自己实现:

如果拷贝的数据只是整形,这样肯定赋值肯定没问题,但是这样逻辑不通用。

![image-20230824124817747](/Users/mac/Library/Application Support/typora-user-images/image-20230824124817747.png)

因为1个字节能组成的最小数据是char,如果我们把数据依次按照每个字节进行修改,则可以实现通用。

![image-20230824130031519](/Users/mac/Library/Application Support/typora-user-images/image-20230824130031519.png)

上面几点注意,void* 不能进行加减和解引用操作,需要先强转为 char *。

实现如下:

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

void printf_arr(const int *pa, int sz) {
    for (int i = 0; i < sz; i++) {
        printf("%d ", *(pa + i));
    }
}

void *my_memcpy(void *dest, const void *src, size_t count) {
    assert(dest && src);

    void *ret = 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[5] = {0};
    int sz1 = sizeof(arr1) / sizeof(arr1[0]);

//    memcpy(arr2, arr1, 20);
    my_memcpy(arr2, arr1, 20);

    int sz2 = sizeof(arr2) / sizeof(arr2[0]);
    printf_arr(arr2, sz2);
}

# memmove

先思考一个问题,数组拷贝可以用memcpy, 那如何实现重叠拷贝呢?(不用另外开辟空间)

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

移动内存块 将 num 个字节的值从源指向的位置复制到目标指向的内存块。 复制就像使用中间缓冲区一样进行,允许目标和源重叠。

使用如下。

#include <memory.h>

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

		// memmove(arr1, arr1 + 2, 20); // {3, 4, 5, 6, 5, 6, 7, 8, 9, 10}
  	memmove(arr1 + 2, arr1, 20); // {1, 2, 1, 2, 3, 4, 5, 8, 9, 10}
}

如何自己实现:

当 dest < src 时,依次从前往后进行拷贝,结果正确。

![image-20230824142055908](/Users/mac/Library/Application Support/typora-user-images/image-20230824142055908.png)

当 dest > src 时,依次从前往后进行拷贝,出现了覆盖,结果错误,如果从后往前拷贝,结果正确。

![image-20230824142250003](/Users/mac/Library/Application Support/typora-user-images/image-20230824142250003.png)

![image-20230824142818341](/Users/mac/Library/Application Support/typora-user-images/image-20230824142818341.png)

所以我们可以这样实现。

  • 当 dest < src 时,从前往后拷贝。
  • 当 dest > src 时,从后往前拷贝。

这里注意,当arr1 + 20,指向的是 arr1[5] 的第一个字节,arr1 + 19 指向的是 arr1[4] 的最后一个字节。

代码如下:

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

void printf_arr(const int *pa, int sz) {
    for (int i = 0; i < sz; i++) {
        printf("%d ", *(pa + i));
    }
}

void *my_memmove(void *dest, const void *src, size_t count) {
    assert(dest && src);

    void *ret = dest;

    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);
        }
    }

    return ret;
}

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

//    memmove(arr1, arr1 + 2, 20);
//    my_memmove(arr1, arr1 + 2, 20);
    my_memmove(arr1 + 2, arr1, 20);

    printf_arr(arr1, sz1);
}

# memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

Compare two blocks of memory

Compares the first num bytes of the block of memory pointed by ptr1 to the first num bytes pointed by ptr2, returning zero if they all match or a value different from zero representing which is greater if they do not.

比较两个内存块 将 ptr1 指向的内存块的前 num 个字节与 ptr2 指向的前 num 个字节进行比较,如果它们全部匹配,则返回零;如果不匹配,则返回一个不同于零的值,表示哪个更大。

使用如下:

#include <memory.h>
#include <stdio.h>

int main() {
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[] = {1, 2, 3, 4, 0x11223305};

    int ret1 = memcmp(arr1, arr2, 20); // <0
    int ret2 =  memcmp(arr1, arr2, 17); // 0

    printf("%d %d\n", ret1, ret2);// -51 0
}

内存分布如下:

![image-20230824144530736](/Users/mac/Library/Application Support/typora-user-images/image-20230824144530736.png)

![image-20230824144556364](/Users/mac/Library/Application Support/typora-user-images/image-20230824144556364.png)

# memset

void * memset ( void * ptr, int value, size_t num );

Fill block of memory

Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).

填充内存块 将 ptr 指向的内存块的前 num 个字节设置为指定值(解释为无符号字符)。

使用如下:

#include <memory.h>

int main() {
    int arr1[] = {0x11111111, 0x22222222, 3, 4, 5};

    memset(arr1, 0, 20); // 以字节为单位设置内存单元
}

内存分布如下:

![image-20230824145603511](/Users/mac/Library/Application Support/typora-user-images/image-20230824145603511.png)

![image-20230824145625752](/Users/mac/Library/Application Support/typora-user-images/image-20230824145625752.png)

Last Updated: 3/20/2024, 8:15:43 AM
강남역 4번 출구
Plastic / Fallin` Dild