C语⾔内存函数

前言

本篇文章将讲解C语⾔内存函数知识的相关内容,为本章节知识的内容。

本篇文章涉及的C语⾔内存函数有:

1.memcpy函数

2.memmove函数

3.memset函数

4.memcmp函数

为本次讲解的知识。

**一、**memcpy函数

1.介绍

void * memcpy ( void * destination, const void * source, size_t num );
memcpy函数strcpy函数功能相似,不同的是memcpy 是完成内存块拷⻉的,不关注内存中存放的数据是什么,即将函数 memcpy 从source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。

注意:source 和 destination 有任何的重叠,复制的结果都是未定义的,更易懂的角度来说:

例:

int arr[5] = {1, 2, 3, 4, 5};

memcpy(arr+1, arr, 3*sizeof(int)); // 错误:目标区域 (arr+1) 与源区域 (arr) 重叠

memcpy不允许同名数组的复制。

destination :指针,指向⽬标空间,将拷⻉的数据存放在这⾥(归宿)。

source :指针,指向源空间,要拷⻉的数据从这⾥来(来源)。

num :从source要拷⻉的数据占据的字节数。

返回值: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);

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr2[i]);

}

return 0;

}

例子讲解:

本代码中,是将 arr1 的前20字节数据复制到 arr2 中,然后打印 arr2 的所有元素。

  • memcpy(arr2, arr1, 20) 表示复制 20字节 数据。由于每个 int 占4字节,因此实际复制 20 / 4 = 5 个元素。
  • arr1 的起始地址复制5个元素:1, 2, 3, 4, 5
  • arr2 初始化为全0,因此未被复制的后5个元素保持为0。

所以可知打印时后5个值为0.

2.模拟实现:

#include <stdio.h>

#include <string.h>

void * mymemcpy ( void * dst, const void * src, int n )

{ void *ret=dst;

while(n--)

{

*(char*)dst=*(char*)src;

dst=(char*)dst+1;

src=(char*)src+1;

}

return ret;

}

int main()

{

int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

int arr2[10] = { 0 };

mymemcpy(arr2, arr1, 20);

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr2[i]);

}

return 0;

}

对该实现的讲解:

首先模拟实现要满足原函数的参数,返回值等,所以要满足void * memcpy ( void * destination, const void * source, size_t num );的型状。

因为返回值:memcpy 函数返回的⽬标空间的起始地址。

所以用void *ret=dst;语句来接**⽬标空间的起始地址。**

memcpy 是完成内存块拷⻉的,不关注内存中存放的数据是什么,拷贝的是num个字节,但不同类对应着不同的字节数,所以存在拷贝不完全的情况,而char类型1个字节数,可以完成1个1个复制拷贝的情况,所以 *(char*)dst=*(char*)src; 拷贝完一个字符,就该向下拷贝,但二者均为void *类,所以应该通过强转之后移动地址,所以会有 dst=(char*)dst+1;

src=(char*)src+1; 语句,在结尾,完成返回值:memcpy 函数返回的⽬标空间的起始地址。 return ret;

运行结果一样的,看实现代码,我们可以发现,memcpy不能实现同名数组的复制,如果我们想实现,则可以靠二、memmove函数

二、memmove函数

1.介绍

void * memmove ( void * destination, const void * source, size_t num );
memmove函数也是完成内存块拷⻉的。

他与 memcpy函数功能一样,是完成内存块拷⻉的,不关注内存中存放的数据是什么,即将函数 memcpy 从source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。不过mommove可以正确处理目标空间与源空间重叠的情况。

源内存块和⽬标内存块是可以重叠的。
二者的参数相同,意义也一样的:

destination :指针,指向⽬标空间,将拷⻉的数据存放在这⾥(归宿)。

source :指针,指向源空间,要拷⻉的数据从这⾥来(来源)。

num :从source要拷⻉的数据占据的字节数。

返回值:memmove 函数返回的⽬标空间的起始地址。

使用例:

#include <stdio.h>

#include <string.h>

int main()

{

int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

memmove(arr1 + 2, arr1, 20);

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr1[i]);

}

return 0;

}

讲解:

与在memcpy中的使用方法一样,不同的是该例为同名数组的拷贝,即将该数组的前5个值拷贝从(arr1 + 2)即arr[2]开始。

2.模拟实现:

#include <stdio.h>

#include <string.h>

void * mymemmove ( void * dst, const void * src, int n )

{

void *ret=dst;

if(dst<src)

{

while(n--)

{

*(char*)dst=*(char*)src;

dst=(char*)dst+1;

src=(char*)src+1;

}

}

else

{

while(n--)

*((char*)dst+n)=*((char*)src+n);

}

return ret;

}

int main()

{

int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

mymemmove(arr1 + 2, arr1, 20);

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr1[i]);

}

return 0;

}

运行结果一样,接下来对该实现讲解一下:

核心逻辑分析

mymemmove 通过判断目标地址(dst)和源地址(src)的位置关系,选择不同复制方向:

  • dst < src(目标在源左侧):从低地址到高地址复制(避免覆盖未复制的源数据)。(对应图中的一情况)
  • dst >= src(目标在源右侧或重叠) :从高地址到低地址复制(从 n-1 反向遍历)。(对应图中的二情况)

输入参数

  • arr1 初始值:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • mymemmove(arr1 + 2, arr1, 20)
    • dst = arr1 + 2(目标起始地址:第3个元素)
    • src = arr1(源起始地址:第1个元素)
    • n = 20(复制20字节,int 占4字节 → 共复制 5个元素

关键判断

dst (arr1+2) > src (arr1) → 进入 else 分支(从高地址到低地址复制)。

else中拷贝。

while(n--)

*((char*)dst+n)=*((char*)src+n);

最后: return ret;完成返回值: memmove函数返回的⽬标空间的起始地址。

三、memset函数

1.介绍

void * memset ( void * ptr, int value, size_t num );
1.memset 函数是设置内存块的内容的,将内存中指定⻓度的空间设置为特定的内容。 2.memset 的使⽤需要包含<string.h>。
参数讲解:

1.ptr :指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。

2.value :要设置的值,函数将会把value值转换成unsigned char的数据进⾏设置的。也就是以字节为单位来设置内存块的。

3.num :要设置的内存⻓度,单位是字节。

4.返回值:返回的是要设置的内存空间的起始地址。

使用例:

#include <stdio.h>

#include <string.h>

int main ()

{

char str[] = "hello world";

memset (str,'x',6);

printf(str);

return 0;

}

对于该例的解释:

  1. 初始字符串char str[] = "hello world" 定义了一个字符数组,存储字符串 "hello world"(共11个字符 + 1个结束符 \0,总长度12字节)。

  2. memset 操作

    • 作用:将 str 起始的 6个字节 全部设置为字符 'x'
    • 原字符串前6个字符是 "hello "(注意第6个字符是空格),替换后变为 "xxxxxx"
  3. 剩余字符不变

    • memset 仅修改前6字节,原字符串从第7字节开始的内容("world\0")保持不变。
    • 拼接后结果为 "xxxxxxrld\0"(第7个字符是 'r',因此输出 xxxxxxrld)。

所以是这样的结果。

注意:当有⼀块内存空间需要设置内容的时候,就可以使⽤memset函数,值得注意的是memset函数对内存 单元的设置是以字节为单位的。

2.模拟实现:

#include <stdio.h>

#include <string.h>

void * mymemset ( void * p, int value,int n)

{ void *ret=p;

while(n--)

{

*(char*)p=value;

p=(char*)p+1;

}

return ret;

}

int main ()

{

char str[] = "hello world";

mymemset (str,'x',6);

printf(str);

return 0;

}

讲解:

  • mymemset执行流程
    • 保存原始指针ret = p,用于最终返回。
    • 循环6次(n--从6到0),每次将p指向的字节设为'x',并将p按字节递增((char*)p + 1)。
    • 原字符串前6字节("hello ")被替换为"xxxxxx",后续字符"world\0"保持不变,拼接后结果为"xxxxxxrld\0"
  • printf输出 :打印字符串至结束符\0,结果为 xxxxxxrld

四、memcmp函数

1.介绍

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

1.⽐较指定的两块内存块的内容,⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节 2.memcmp 的使⽤需要包含
ptr1 :指针,指向⼀块待⽐较的内存块

ptr2 :指针,指向另外⼀块待⽐较的内存块

num :指定的⽐较⻓度,单位是字节

使用例:

#include <stdio.h>

#include <string.h>

int main()

{

char s1[] = "abcdefg";

char s2[] = "abcdEFG";

int n;

n = memcmp(s1, s2, sizeof(s1));

if (n > 0)

printf("'%s'>'%s'.\n", s1, s2);

else if (n < 0)

printf("'%s' <'%s'.\n",s1,s2);

else

printf("'%s' =='%s' .\n", s1, s2);

return 0;

}

讲解:

  • 输出内容'abcdefg' < 'abcdEFG'.
  • 关键原因memcmp字节逐一比较 (区分大小写),在第5个字符处:
    • s1[4] = 'e'(ASCII值101)
    • s2[4] = 'E'(ASCII值69)
      101 > 69memcmp返回正数,n>0, 执行: if (n > 0) printf("'%s'>'%s'.\n", s1, s2);

注意:1.memcmp 函数是通过返回值告知⼤⼩关系的。

2.如果要⽐较2块内存单元的数据的⼤⼩,可以使⽤该函数,这个函数的特点就是可以指定⽐较长度。

2.模拟实现:

#include <stdio.h>

#include <string.h>

int mymemcmp ( const void * p1, const void * p2, int n )

{

const char* s1 = (const char*)p1;

const char* s2 = (const char*)p2;

while (n-- > 0)

{

if (*s1 != *s2)

{

return *s1 - *s2;

}

s1++;

s2++;

}

return 0;

}

int main()

{

char s1[] = "abcdefg";

char s2[] = "abcdEFG";

int n;

n = mymemcmp(s1, s2, sizeof(s1));

if (n > 0)

printf("'%s'>'%s'.\n", s1, s2);

else if (n < 0)

printf("'%s' <'%s'.\n",s1,s2);

else

printf("'%s' =='%s' .\n", s1, s2);

return 0;

}

结果一样,接下来,我将为大家讲解一下:

因为参数为void*类型,如果使用,需要 *(char*)p1 这种的强转,代码中每次比较和移动指针时都进行(char*)强制转换,可通过临时变量优化,const char* s1 = (const char*)p1;

const char* s2 = (const char*)p2;通过char*类型,便于比大小和向下移动。

while (n-- > 0)

{

if (*s1 != *s2)

{

return *s1 - *s2;

}

s1++;

s2++;

}

return 0;

  • 循环条件n-- > 0 表示从第 1 个字节开始,逐个比较 n 个字节(每轮循环后 n 减 1,直到 n=0 退出)。
  • 逻辑
    • 每次循环读取 s1s2 指向的当前字节(*s1/*s2)。
    • 若字节不同,直接返回两字节的 ASCII 码差值(例如 'e' - 'E' = 101 - 69 = 32,结果为正数)。
    • 若字节相同,指针后移(s1++/s2++),继续比较下一个字节。
    • 若循环结束后所有 n 字节均相同(未触发 return *s1 - *s2),则显式返回 0。

总结

以上就是今天要讲的内容,

本篇文章涉及的C语⾔内存函数有:

1.memcpy函数

2.memmove函数

3.memset函数

4.memcmp函数

知识的相关内容,为本章节知识的内容,希望大家能喜欢我的文章,谢谢各位。

相关推荐
人工干智能17 小时前
科普:Python 中,字典的“动态创建键”特性
开发语言·python
LGL6030A17 小时前
算法题实战积累(3)——方块转换(C语言)
c语言·算法
初听于你18 小时前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
长路归期无望20 小时前
C语言小白实现多功能计算器的艰难历程
c语言·开发语言·数据结构·笔记·学习·算法
是大强20 小时前
stm32摇杆adc数据分析
开发语言
口嗨农民工21 小时前
win10默认搜索APP和window设置控制命板
linux·服务器·c语言
蓝莓味的口香糖21 小时前
【JS】什么是单例模式
开发语言·javascript·单例模式
linux kernel21 小时前
第二十三讲:特殊类和类型转换
开发语言·c++
笨蛋少年派21 小时前
JAVA基础语法
java·开发语言
渡我白衣1 天前
深入剖析:boost::intrusive_ptr 与 std::shared_ptr 的性能边界和实现哲学
开发语言·c++·spring