C 语言内存秘籍:memcpy 等四函数的实用指南与底层解析

目录

一、memcpy函数

  • 定义与功能
    • memcpy函数用于从源内存区域复制一定数量的字节到目标内存区域。这是一个字节级别的复制操作,它不关心数据的类型,只是简单地按照字节进行复制。
    • 函数原型为void *memcpy(void *dest, const void *src, size_t n);,其中dest是目标内存区域的起始地址,src是源内存区域的起始地址,n是要复制的字节数。
  • 参数说明
    • dest:目标内存区域的指针,必须是一个有效的可写内存地址。它可以指向数组、结构体等各种数据结构的内存空间。
    • src:源内存区域的指针,必须是一个有效的可读内存地址。通常指向要被复制的数据所在的内存位置。
    • n:要复制的字节数量,这个参数决定了复制操作的范围。
  • 返回值 :返回目标内存区域的起始地址(dest),这样可以方便地进行链式调用。
  • 使用示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[20];
    memcpy(dest, src, strlen(src)+1);
    printf("%s\n", dest);
    return 0;
}

在这个例子中,memcpy函数将src字符串中的内容复制到dest数组中。注意,因为字符串是以'\0'结尾的,所以复制的字节数是strlen(src)+1,这样才能完整地复制整个字符串。

  • 模拟实现思路及代码示例
    • 模拟实现memcpy主要是通过逐个字节地将源内存区域的数据复制到目标内存区域。可以使用字符指针来遍历源地址和目标地址,实现字节级别的复制。
c 复制代码
void *my_memcpy(void *dest, const void *src, size_t n) {
    char *d = (char *)dest;
    const char *s = (const char *)src;
    for (size_t i = 0; i < n; i++) {
        d[i] = s[i];
    }
    return dest;
}

在这个模拟实现中,首先将destsrc指针转换为字符指针,这样可以方便地按照字节进行操作。然后通过一个循环,逐个字节地将源内存区域的数据复制到目标内存区域,最后返回目标内存区域的起始地址。

二、memmove函数

  • 定义与功能
    • memmove函数的功能和memcpy类似,也是用于将一定数量的字节从源内存区域复制到目标内存区域。但是,memmove函数能够处理源内存区域和目标内存区域重叠的情况,保证复制的结果是正确的。
    • 函数原型为void *memmove(void *dest, const void *src, size_t n);
  • 参数说明
    • memcpy函数的参数相同,dest是目标内存区域的起始地址,src是源内存区域的起始地址,n是要复制的字节数。
  • 返回值 :返回目标内存区域的起始地址(dest)。
  • 使用示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "abcdefg";
    memmove(str + 2, str, 4);
    printf("%s\n", str);
    return 0;
}

在这个例子中,memmove函数将str字符串的前4个字符(abcd)移动到从第3个字符开始的位置,实现了字符串内容的移动。因为memmove能够正确处理重叠区域,所以得到的结果是正确的。

  • 模拟实现思路及代码示例
    • 当源内存区域和目标内存区域不重叠时,memmove的实现可以和memcpy一样。当它们重叠时,需要根据源地址和目标地址的相对位置来决定复制的方向。如果源地址在目标地址之后,应该从后往前复制,以避免覆盖还没有复制的数据。
c 复制代码
void *my_memmove(void *dest, const void *src, size_t n) {
    char *d = (char *)dest;
    const char *s = (const char *)src;
    if (s < d) {
        // 从后往前复制,处理重叠且源地址在目标地址之后的情况
        s += n - 1;
        d += n - 1;
        for (size_t i = 0; i < n; i++) {
            *d-- = *s--;
        }
    } else {
        // 从前往后复制,包括不重叠和源地址在目标地址之前的重叠情况
        for (size_t i = 0; i < n; i++) {
            *d++ = *s++;
        }
    }
    return dest;
}

在这个模拟实现中,首先将destsrc指针转换为字符指针。然后通过比较源地址和目标地址的大小来判断是否重叠以及重叠的情况。如果源地址在目标地址之后,就从后往前复制字节;否则,从前往后复制字节。最后返回目标内存区域的起始地址。

三、memset函数

  • 定义与功能
    • memset函数用于将一段内存区域的每个字节设置为指定的值。它通常用于初始化内存区域,比如将数组的元素全部初始化为0或者其他特定的值。
    • 函数原型为void *memset(void *s, int c, size_t n);,其中s是要设置的内存区域的起始地址,c是要设置的值(会被转换为无符号字符型),n是要设置的字节数。
  • 参数说明
    • s:目标内存区域的指针,必须是一个有效的可写内存地址。
    • c:要设置的值,这个值会被截断为一个无符号字符型(unsigned char)的值,然后用于设置内存区域中的每个字节。
    • n:要设置的字节数量,决定了操作的范围。
  • 返回值 :返回目标内存区域的起始地址(s)。
  • 使用示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char buffer[10];
    memset(buffer, 'A', 5);
    buffer[5] = '\0';
    printf("%s\n", buffer);
    return 0;
}

在这个例子中,memset函数将buffer数组的前5个字节设置为字符'A',然后手动添加字符串结束符'\0',最后打印出这个部分初始化的字符串。

  • 模拟实现思路及代码示例
    • 模拟实现memset主要是通过将指定的值转换为无符号字符型,然后逐个字节地将目标内存区域的字节设置为这个值。
c 复制代码
void *my_memset(void *s, int c, size_t n) {
    unsigned char *p = (unsigned char *)s;
    for (size_t i = 0; i < n; i++) {
        p[i] = (unsigned char)c;
    }
    return s;
}

在这个模拟实现中,首先将目标指针s转换为无符号字符指针p,这样可以方便地按照字节进行操作。然后通过一个循环,将c转换为无符号字符型后逐个字节地设置目标内存区域的值,最后返回目标内存区域的起始地址。

四、memcmp函数

  • 定义与功能
    • memcmp函数用于比较两个内存区域的内容,按照字节逐个进行比较,直到发现不相等的字节或者比较完指定数量的字节。它返回一个整数值来表示比较的结果。
    • 函数原型为int memcmp(const void *s1, const void *s2, size_t n);,其中s1s2是要比较的两个内存区域的起始地址,n是要比较的字节数。
  • 参数说明
    • s1s2:要比较的两个内存区域的指针,必须是有效的可读内存地址。
    • n:要比较的字节数量,决定了比较的范围。
  • 返回值
    • 如果s1所指向的内存区域在字典序上小于s2所指向的内存区域,返回一个小于0的值。
    • 如果s1s2所指向的内存区域相等,返回0。
    • 如果s1所指向的内存区域在字典序上大于s2所指向的内存区域,返回一个大于0的值。
  • 使用示例
c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "abc";
    char str2[] = "abd";
    int result = memcmp(str1, str2, 3);
    printf("%d\n", result);
    return 0;
}

在这个例子中,memcmp函数比较str1str2的前3个字节。因为str1中的c小于str2中的d,所以返回一个小于0的值(具体的值根据编译器和平台可能会有所不同,但一定是小于0的)。

  • 模拟实现思路及代码示例
    • 模拟实现memcmp主要是通过逐个字节地比较两个内存区域的内容。可以使用字符指针来遍历两个地址,比较每个字节的值。
c 复制代码
int my_memcmp(const void *s1, const void *s2, size_t n) {
    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 -1;
        } else if (p1[i] > p2[i]) {
            return 1;
        }
    }
    return 0;
}

在这个模拟实现中,首先将s1s2指针转换为无符号字符指针,这样可以方便地按照字节进行比较。然后通过一个循环,逐个字节地比较两个内存区域的内容。如果发现不相等的字节,根据大小关系返回相应的值(小于0或大于0)。如果比较完指定数量的字节后都相等,返回0。

相关推荐
思捻如枫38 分钟前
C++数据结构和算法代码模板总结——算法部分
数据结构·c++
嘉陵妹妹43 分钟前
深度优先算法学习
学习·算法·深度优先
GalaxyPokemon1 小时前
LeetCode - 53. 最大子数组和
算法·leetcode·职场和发展
小猫咪怎么会有坏心思呢1 小时前
华为OD机考 - 水仙花数 Ⅰ(2025B卷 100分)
数据结构·链表·华为od
乖乖是干饭王1 小时前
Linux系统编程中的_GNU_SOURCE宏
linux·运维·c语言·学习·gnu
weixin_478689762 小时前
C++ 对 C 的兼容性
java·c语言·c++
hn小菜鸡2 小时前
LeetCode 1356.根据数字二进制下1的数目排序
数据结构·算法·leetcode
zhuiQiuMX2 小时前
分享今天做的力扣SQL题
sql·算法·leetcode
待什么青丝2 小时前
【TMS570LC4357】之相关驱动开发学习记录2
c语言·arm开发·驱动开发·单片机·学习
小柯博客2 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
c语言·stm32·单片机·嵌入式硬件·物联网