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。

相关推荐
pzx_0013 分钟前
【集成学习】Boosting算法详解
人工智能·python·深度学习·算法·机器学习·集成学习·boosting
九离十18 分钟前
C语言教程——指针进阶(1)
c语言·开发语言
Channing Lewis18 分钟前
经典编程题:服务器广播
python·算法
Ritsu栗子37 分钟前
代码随想录算法训练营day27
c++·算法
小冯的编程学习之路37 分钟前
【LeetCode】:稀疏相似度【困难】
c++·算法·leetcode
羊小猪~~1 小时前
C/C++语言基础--C++STL库算法记录(质变算法、非质变算法、查找、排序、排列组合、关系算法、集合算法、堆算法等)
c语言·开发语言·数据结构·c++·算法·stl
qystca1 小时前
炸弹 (boom.c)(100分双端递推+分割线优化)
算法
NineData2 小时前
NineData云原生智能数据管理平台新功能发布|2024年12月版
数据库·sql·算法·云原生·oracle·devops·ninedata
bachelores2 小时前
数据结构-栈、队列和数组
数据结构·算法
AQin10123 小时前
【Leetcode·中等·数组】59. 螺旋矩阵 II(spiral matrix ii)
算法·leetcode·矩阵·数组