C语言自学--C语⾔内存函数
目录
1、memcpy 的使用与模拟实现
1.1、memcpy 的使用
1.2、memcpy 的模拟实现
2、memmove 的使用与模拟实现
2.1、memmove 的使用
2.2、memmove 的模拟实现
3、memset 函数的使用
3.1、memset 函数的基本介绍
3.2、memset 的常见用途
3.3、注意事项
3.4、示例代码
3.5、总结
4、memcmp 函数的使用
4.1、memcmp 函数的基本用法
4.2、示例代码
4.3、注意事项
1、memcpy 的使用与模拟实现
1.1、memcpy 的使用
memcpy 是 C 标准库中的一个函数,用于将源内存区域的内容复制到目标内存区域。其函数原型如下:
void *memcpy(void *dest, const void *src, size_t n);
dest
:目标内存区域的指针。src
:源内存区域的指针。n
:要复制的字节数,遇到‘\0’的时候并不会停下来,也就是说,n是多少就复制多少字节。
注意事项:
- 目标内存区域必须足够大,以避免缓冲区溢出。
- 源和目标内存区域不应重叠,否则行为未定义。若存在重叠,应使用
memmove
。
#include <stdio.h>
#include <string.h>int main() {char src[] = "Hello, World!";char dest[20];memcpy(dest, src, strlen(src) + 1); // 复制字符串,包括空字符printf("Copied string: %s\n", dest);return 0;
}
#include <stdio.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };memcpy(arr2,arr1,20);return 0;
}
在arr数组中一个int元素占4个字节,20就是复制五个元素到arr2中。
1.2、memcpy 的模拟实现
//memcpy的模拟实现
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src,size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;//不能写为dest++,原因在下方给出!!src = (char*)src + 1; }return ret;
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 8);for (int i = 0; i < 10; i++){printf("%d ",arr2[i]);}return 0;
}
为什么不能写为dest++呢?
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;//不能写为dest++,原因在下方给出!!
src = (char*)src + 1;
指针运算的核心差异
-
类型决定步长 (int*)dest + 1: 将dest转换为int类型后,+1操作会移动sizeof(int)个字节(通常为4字节)。 示例:int指针从地址0x1000递增到0x1004。 dest++(void类型): void作为通用指针,编译器无法确定增量步长,因此直接报错(C/C++禁止void*的算术运算)。
-
void的特殊性质 void表示"无类型指针",编译器无法解析++操作(缺乏类型信息)。 必须显式转换为具体类型(如int*、char*)才能执行指针运算。
int arr[10];
void* p = arr;// 合法:明确按int步长移动
p = (int*)p + 1; // 移动4字节// 非法:void*无法自增
p++; // 编译错误
2、memmove 的使用与模拟实现
2.1、memmove 的使用
memmove 是 C 标准库中的一个函数,用于复制内存块。其原型如下
void* memmove(void* dest, const void* src, size_t n);
- dest:目标内存地址。
- src:源内存地址。
- n:需要复制的字节数。
memmove 的特点是可以处理内存重叠的情况。当源内存和目标内存有重叠时,memmove 会确保数据正确复制,而不会因覆盖导致错误。
#include <stdio.h>
#include <string.h>int main() {char str[] = "Hello, World!";memmove(str + 7, str, 5); // 将 "Hello" 复制到 "World!" 的位置printf("%s\n", str); // 输出: Hello, Hello!return 0;
}
2.2、memmove 的模拟实现
void * memmove ( void * dst, const void * src, size_t count){void * ret = dst;if (dst <= src || (char *)dst >= ((char *)src + count)) {/** Non-Overlapping Buffers* copy from lower addresses to higher addresses*/while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}}else {/** Overlapping Buffers* copy from higher addresses to lower addresses*/dst = (char *)dst + count - 1;src = (char *)src + count - 1;while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst - 1;src = (char *)src - 1;}}return(ret);}
3、memset 函数的使用
3.1、memset 函数的基本介绍
memset
是 C 标准库中的一个函数,用于将指定内存区域的前 n
个字节设置为特定值。其原型定义在 <string.h>
头文件中:
void *memset(void *s, int c, size_t n);
s
:指向要填充的内存区域的指针。c
:要填充的值(以int
形式传递,但实际填充时会被转换为unsigned char
)。n
:要填充的字节数。
3.2、memset 的常见用途
初始化数组或结构体
常用于将数组或结构体的内存区域初始化为 0 或其他特定值:
char buffer[100];
memset(buffer, 0, sizeof(buffer)); // 将 buffer 全部初始化为 0
3.3、注意事项
填充值的行为
memset
按字节填充,因此对非字符类型的数组填充时需谨慎。例如,将 int
数组填充为 1 时,每个 int
的 4 字节会被设置为 0x01,而非整体值为 1:
int arr[10];
memset(arr, 1, sizeof(arr)); // 每个 int 的值为 0x01010101,而非 100000001 00000001 00000001 00000001 //一个int四个字节,每个字节八位
0000 0001 0000 0001 0000 0001 0000 0001 //二进制转换十六进制,四位一组0 1 0 1 0 1 0 1 //memset是每个字节都要改
性能优化
memset
通常由编译器优化为高效的底层指令(如 rep stosb
),适合大规模内存初始化。但对于小内存块,直接赋值可能更快。
3.4、示例代码
初始化字符数组
#include <stdio.h>
#include <string.h>int main() {char str[50] = "Hello, World!";printf("Before memset: %s\n", str);memset(str, '*', 5); // 将前 5 个字符替换为 '*'printf("After memset: %s\n", str);return 0;
}
输出结果
Before memset: Hello, World!
After memset: *****, World!
结构体初始化
#include <stdio.h>
#include <string.h>typedef struct {int id;char name[20];
} Person;int main() {Person p;memset(&p, 0, sizeof(Person)); // 将结构体所有成员初始化为 0printf("ID: %d, Name: %s\n", p.id, p.name);return 0;
}
3.5、总结
memset
是高效的内存初始化工具,但需注意其按字节填充的特性。适用于字符数组、清空内存或结构体初始化等场景,但对于非字符类型的数据初始化需谨慎使用。
4、memcmp 函数的使用
4.1、memcmp 函数的基本用法
memcmp
是 C/C++ 标准库中的内存比较函数,用于比较两块内存区域的内容是否一致。
函数原型:
int memcmp(const void *s1, const void *s2, size_t n);
-
参数:
s1
:指向第一块内存区域的指针。s2
:指向第二块内存区域的指针。n
:需要比较的字节数。
-
返回值:
- 返回值为
0
,表示两块内存区域内容完全相同。 - 返回值
< 0
,表示s1
在第一个不匹配字节处的值小于s2
。 - 返回值
> 0
,表示s1
在第一个不匹配字节处的值大于s2
。
- 返回值为
4.2、示例代码
#include <stdio.h>
#include <string.h> int main() { char buffer1[] = "Hello"; char buffer2[] = "World"; int result; result = memcmp(buffer1, buffer2, 5); if (result == 0) { printf("内容相同\n"); } else if (result < 0) { printf("buffer1 小于 buffer2\n"); } else { printf("buffer1 大于 buffer2\n"); } return 0;
}
4.3、注意事项
- 比较时按字节逐个进行,直到发现不匹配或比较完
n
个字节。 - 适用于任意数据类型(如结构体、数组等),但需确保内存区域合法且可读。
- 不检查字符串结束符(
\0
),与strcmp
不同。