C语言之内存函数

内存函数:通常指的是在编程中用于处理内存操作的函数,这些函数可以用来分配、释放、复制、比较等内存相关的操作。在C语言中,这些内存函数 memcpy()memmove()memset()memcmp() 都需要引用头文件 <string.h>

1.memcpy函数

memcpy() 函数的原型如下:

cpp 复制代码
void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标内存地址,即要将数据复制到的位置。
  • src:源内存地址,即要复制数据的起始位置。
  • n:要复制的字节数。

memcpy() 函数会从源内存地址 src 复制 n 个字节的数据到目标内存地址 dest,并返回目标内存地址 dest

cpp 复制代码
#include <stdio.h>

void *memcpy_custom(void *dest, const void *src, size_t n) {
    // 将源地址src的内容复制到目标地址dest
    // 注意:此处假设目标地址和源地址不会重叠

    // 将void指针转换为char指针,方便按字节进行操作
    char *p_dest = (char *)dest;
    const char *p_src = (const char *)src;

    // 逐字节复制数据
    for (size_t i = 0; i < n; i++) {
        p_dest[i] = p_src[i];
    }

    return dest;
}

int main() {
    char src[] = "Hello, world!";
    char dest[20];

    // 调用自定义的memcpy函数
    memcpy_custom(dest, src, sizeof(src));

    // 输出复制后的字符串
    printf("Copied string: %s\n", dest);

    return 0;
}

假设存在两片这样的空间由两个指针"dest"和"src"维护,解引用赋值过去相当于copy过去一个字节

然后"dest++"和"src++"就指向下一内存单元,重复之前的操作直至来到最后一个内存单元,也就是第n个,至此操作完成返回目标内存的起始地址

2.memmove函数

memmove() 类似于 memcpy(),但更安全,可以处理内存块重叠的情况,内存块重叠情况就是当我们

src所指向的内存块和dest所指向的内存块发生重叠的情况,如下图

当我们如果想进行像memcpy() 那样操作时就会篡改src所指向的内存块从而达不到copy效果当我们走到最后变成这样

而memmove就是避免这种情况而造就的,实现原理也很简单当src的起始位置大于dest的起始位置,我们就从后往前复制,当src的起始位置小于dest的起始位置,就从前向后复制,至此实现正确复制,这样做的原理就是先把重合部分拿出来复制,这样就可以避免篡改源内存块

memmove实现

cpp 复制代码
#include <stdio.h>

void *memmove_custom(void *dest, const void *src, size_t n) {
    // 将源地址src的内容复制到目标地址dest
    // 处理重叠情况时,从后往前复制

    // 将void指针转换为char指针,方便按字节进行操作
    char *p_dest = (char *)dest;
    const char *p_src = (const char *)src;

    // 处理重叠情况时,从后往前复制
    if (p_dest > p_src && p_dest < p_src + n) {
        for (size_t i = n - 1; i < n; i--) {
            p_dest[i] = p_src[i];
        }
    } else {
        // 普通情况下,从前往后复制
        for (size_t i = 0; i < n; i++) {
            p_dest[i] = p_src[i];
        }
    }

    return dest;
}

int main() {
    char src[] = "Hello, world!";
    char dest[20];

    // 调用自定义的memmove函数
    memmove_custom(dest, src, sizeof(src));

    // 输出复制后的字符串
    printf("Copied string: %s\n", dest);

    return 0;
}

3.memcmp函数

memcmp() 是C语言中用于比较内存区域的函数,类似于strncmp函数但是memcmp更加通用,因为它比较的是内存中的值而不只限于字符串

其原型如下:

cpp 复制代码
int memcmp(const void *s1, const void *s2, size_t n);
  • s1:指向要比较的第一个内存区域的指针。
  • s2:指向要比较的第二个内存区域的指针。
  • n:要比较的字节数。

memcmp() 函数会比较 s1s2 所指向的内存区域的前 n 个字节,并返回一个整数来表示比较结果。

  • 如果第一个区域的字节值小于第二个区域的字节值,则返回负值。
  • 如果第一个区域的字节值大于第二个区域的字节值,则返回正值。
  • 如果两个区域的字节值都相等,则返回0。

实现:

cpp 复制代码
#include <stdio.h>

int memcmp_custom(const void *s1, const void *s2, size_t n) {
    // 将void指针转换为char指针,方便按字节进行比较
    const unsigned char *p1 = (const unsigned char *)s1;
    const unsigned char *p2 = (const unsigned char *)s2;

    // 逐字节比较数据
    for (size_t i = 0; i < n; i++) {
        if (p1[i] != p2[i]) {
            // 如果有不相等的字节,则返回它们的差值
            return (p1[i] > p2[i]) ? 1 : -1;
        }
    }

    // 如果所有字节都相等,则返回0
    return 0;
}

int main() {
    char s1[] = "Hello";
    char s2[] = "Hella";

    // 调用自定义的memcmp函数
    int result = memcmp_custom(s1, s2, 5);

    if (result == 0) {
        printf("s1 和 s2 相等\n");
    } else if (result > 0) {
        printf("s1 大于 s2\n");
    } else {
        printf("s1 小于 s2\n");
    }

    return 0;
}

4.memset函数

memset() 是C语言中用于设置内存块的函数,其原型如下

cpp 复制代码
void *memset(void *s, int c, size_t n);
  • s:指向要设置的内存块的指针。
  • c:要设置的值,以整数形式给出,通常是一个字节的值。
  • n:要设置的字节数。

memset() 函数将指定的值 c 复制到 s 所指向的内存块的前 n 个字节中。通常情况下,c 是一个无符号字符或整数(0~255),会被转换成无符号字符并复制到内存块中。

memset() 主要用于初始化内存块,可以用来快速将一段内存区域填充为指定的值。它经常用于数组初始化、清除内存等操作。

实现:

cpp 复制代码
#include <stdio.h>

void *memset_custom(void *s, int c, size_t n) {
    // 将指定的值c复制到s所指向的内存块的前n个字节中

    // 将void指针转换为char指针,方便按字节进行操作
    unsigned char *p = (unsigned char *)s;

    // 将指定的值复制到内存块中
    for (size_t i = 0; i < n; i++) {
        p[i] = (unsigned char)c;
    }

    return s;
}

int main() {
    char arr[10];

    // 调用自定义的memset函数,将数组arr的前5个字节设置为'a'的ASCII码值
    memset_custom(arr, 'a', 5);

    // 输出设置后的数组内容
    for (int i = 0; i < 10; i++) {
        printf("%c ", arr[i]);
    }
    printf("\n");

    return 0;
}
相关推荐
唐 城9 分钟前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
嵌入式科普31 分钟前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
码银2 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python
从善若水2 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
lqqjuly2 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
2401_858286113 小时前
115.【C语言】数据结构之排序(希尔排序)
c语言·开发语言·数据结构·算法·排序算法
Jelena技术达人3 小时前
Java爬虫获取1688关键字 item_search接口返回值详细解析
java·开发语言·爬虫
数据小爬虫@3 小时前
Java爬虫:速卖通(AliExpress)商品评论获取指南
java·开发语言
waterme1onY3 小时前
Spring AOP 中记录日志
java·开发语言·笔记·后端
2401_879103683 小时前
24.12.25 AOP
java·开发语言·笔记