💓博主CSDN主页:杭电码农-NEO💓
⏩专栏分类:C语言学习分享⏪
🚚代码仓库:NEO的学习日记🚚
🌹关注我🫵带你学习更多C语言知识
🔝🔝

内存操作函数
- [1. 前言🚩](#1. 前言🚩 "#1__15")
- [2. memcpy介绍🚩](#2. memcpy介绍🚩 "#2_memcpy_40")
-
- [2.1 memcpy的缺点🏁](#2.1 memcpy的缺点🏁 "#21__memcpy_65")
- [3. memmove函数介绍🚩](#3. memmove函数介绍🚩 "#3_memmove_74")
-
- [3.1 memmove的缺陷🏁](#3.1 memmove的缺陷🏁 "#31_memmove_103")
- [4. memset函数介绍🚩](#4. memset函数介绍🚩 "#4_memset_112")
- [5. memcmp函数介绍🚩](#5. memcmp函数介绍🚩 "#5_memcmp_143")
- [6. memchr函数介绍🚩](#6. memchr函数介绍🚩 "#6_memchr_172")
- [7. 总结及拓展🚩](#7. 总结及拓展🚩 "#7__205")
1. 前言🚩
我最近在刷题的时候全然不知的写出了一个bug代码,它大概意思是这样的:
c
int a[]={1,2,3};
int b[]={0,0,0};
strcpy(a,b);
我想将b数组拷贝到a数组去,我第一时间想到了strcpy函数。
- 但是显然strcpy是操作字符串的
- 那么我们有没有什么办法能够像strcpy函数一样操作整型呢?
天空一声巨响,我们的内存操作函数闪亮登场!今天的主角有三个:
- 男主小帅:memcpy函数 😎
- 女主小美:memmove函数 😎
- 猛男丧彪:memset函数 😎
还附送两个配角:
- 友情出演: memcmp函数 ✔
- 群众演员: memchr函数 ✔
2. memcpy介绍🚩
memcpy的函数原型:
功能:从source的起始位置复制num个字节到destination的内存起始位置
用法示例:
c
#include<stdio.h>
#include<string.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
int b[3] = { 33,22,11 };
memcpy(a, b, sizeof(int) * 3);//将数组b往后12个字节(3个整型)的内容拷贝到数组a
for (int i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
return 0;
}
值得注意的是:memcpy函数返回void* 类型指针,并且接受变量的类型也是void *,如果你想了解void * 这个变量,可以跳转 C语言void*详解
2.1 memcpy的缺点🏁
memcpy函数中的两个参数在内存中的位置是不能发生重叠的.
什么意思?举个例子:
既然memcpy函数有缺陷,是时候让我们的女主:memmove函数出来解决问题了!
3. memmove函数介绍🚩
memmove的函数原型:
功能:从source的起始位置复制num个字节到destination的内存起始位置
memmove和memcpy函数的功能是一样的,只不过memmove函数的source和destination指向的空间可以重叠
用法示例:
c
#include<stdio.h>
#include<string.h>
int main()
{
int a[9] = { 1,2,3,4,5,6,7,8,9 };
memmove(a, a + 5, 16);
for (int i = 0; i < 9; i++)
{
printf("%d ", a[i]);
}
return 0;
}
这个结果符合我们的预期:
(覆盖了前面的1234后,后面的56789照常打印)
3.1 memmove的缺陷🏁
- memmove函数无法使用某些机器所提供的特殊字节-字符串处理指令来实现
👍 👍 👍 - 导致的结果:memmove会比memcpy的效率低一些
👍 👍 👍 - 如果源和目标参数真的可能存在重叠,就应该使用memmove!
4. memset函数介绍🚩
memset的函数原型:
功能:把从ptr开始的num个字节的值都设置为value
用法示例:
c
#include<stdio.h>
#include<string.h>
int main()
{
char a[6] = { 'a','b','c','d','e','f'};
memset(a, '-', 3);
for (int i = 0; i < 6; i++)
{
printf("%c ", a[i]);
}
return 0;
}
结果和我们预期的一样:
(将前三个字节的内容改成 ' - ' )

注意,这里内存操作函数中参数num的单位都是字节,如果你想要修改一个整型数组的前n个值,别忘了用n乘以整型的长度!
5. memcmp函数介绍🚩
memcmp的函数原型:
功能:memcmp对两段内存ptr1和ptr2的内容进行比较,共比较num个字节
用法示例:
c
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n = memcmp( buffer1, buffer2, sizeof(char)*5);
return 0;
}
memcmp的返回类型和strcmp一样:
- 负数代表ptr1小于ptr2. 👀
- 正数代表ptr1大于ptr2. 👀
- 0代表它们两个相同👀
值得注意的是:这些值是按照无符号字符逐字节比较,所以它用于比较不是单字节数据如整数,浮点数时可能给出不可预料的结果.
6. memchr函数介绍🚩
memchr的函数原型:
功能:
- 从ptr开始,查找value第一次出现的位置
- 共查找num个字节.
- 如果找到,返回一个指向该位置的指针
- 如果没找到,返回NULL.
用法示例:
c
#include<stdio.h>
#include<string.h>
int main()
{
char a[6] = { 'a','b','c','d','e','f'};
char* p = memchr(a, 'd', sizeof(char) * 6);//在数组a中查找字符d第一次出现的位置
for (int i = 0; i < 3; i++)//这里返回一个指针指向字符d,并将这个指针赋值给p
{
printf("%c ", p[i]);
}
return 0;
}
结果也符合我们的预期:

7. 总结及拓展🚩
总的来说这一板块还是没有难度的,所有的内存操作函数需要包含的头文件是:string.h.关于内存操作函数我们就完结撒花啦!
函数原型出处: C\C++字典:cplusplus
下面我给大家拓展一些字符操作函数:
(在做题时可以节省时间)
比如:
- 判断字符是否为0~9的数字
- 判断字符是不是字母
- 判断是否为大写字母(小写)
- 等等...
函数 | 满足下面条件就返回真 |
---|---|
isspace | 空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符'\t' |
isdigit | 十进制数字: 0 ~ 9 |
islower | 小写字母: a ~ z |
isupper | 大写字母: A ~ Z |
isalpha | 字母 : a ~ z 或 A ~ Z |
isalnum | 字母或者数字: a ~ z,A ~ Z,0 ~ 9 |
ispunct | 标点符号,任何不属于数字或字母的图形 |
两个转换函数:
- 大写字母转小写字母: tolower
- 小写字母转大写字母: toupper
如:
c
char x = tolower('A');//变量x存储的是字符 'a'
最后,看完这一节的内容后
下次遇见字符串拷贝
你会用什么函数来完成任务?
来参与一下投票吧!