我们对于内存操作需要依赖于string.h
头文件中相关的库函数。
#include
void* memset(void* s, int c, size_t)
s
的前n
个字节填充为c
,一般用于初始化或者清零操作s
:目标内存首地址c
:填充值(以unsigned char
形式处理0~255)n
:填充字节数s
的指针#include
#include
#include
int main()
{
// 在堆内存中申请4个int的连续空间
int *p = (int*)malloc(4 * sizeof(int));
// 非空校验
if (p == NULL)
{
perror("内存申请失败!");
return -1;
}
// 初始化堆内存,填充0
memset(p, 0, 4 * sizeof(int));
// 测试输出
printf("%d\n", p[1]); // p[1] 的底层 *(p+1) 我们可以将p[1]看作是*(p+1)语法糖
// 内存使用完毕,释放
free(p);
// 对指针赋值NULL
p = NULL;
return 0;
}
头文件:#include
函数原型:
void* memcpy(void* dest, const void* src, size_t n);
void* memmove(void* dest, const void* src, size_t n);
函数功能:将src
的前n
个字节拷贝倒dest
参数说明:
dest
: 目标内存首地址src
:源内存首地址size_t n
:拷贝的字节数返回值
dest
的首地址注意内存:
memmove
能正确处理内存重叠,推荐优先使用示例:
#include
#include
int main()
{
// 准备两个数组,用来存护源和目标
int src[4] = {11,22,33,44};
int dest[6] = {111,222,333,444,555,666};
// 进行拷贝
memcpy(dest+1, src+1, 2 * sizeof(int));
memmove(dest+1, src+1, 2 * sizeof(int)); // 从src拷贝22,33倒dest的222的位置
printf("源数组:");
register int i;
for(i = 0; i < 4; i++) printf("%-6d", src[i]);
printf("\n目标数组:");
for(i = 0;i < 6; i++) printf("%-6d", dest[i]);
return 0;
}
思考:什么是内存重叠?
内存重叠指在内存操作(如拷贝、移动数据)时,源区域和目标区域的内存地址范围存在部分或完全重叠,导致操作结果出现不确定性。
典型例子:
memcpy
与memmove
memcpy
的隐患
假设拷贝
10字节
从地址p
到p+2
:char str[] = "abcdefgh"; memcpy(str + 2, str, 5); // 源和目标重叠,行为未定义!
memcpy
不检查重叠,可能因逐字节拷贝导致数据被意外覆盖(如先覆盖a
到c
,后续操作又读取被修改的值)。
memmove
的解决方案
同样的操作,使用
memmove
会检测重叠方向:
- 若目标地址在源之前(正向拷贝),或地址不重叠,直接拷贝。
- 若目标地址在源之后(反向拷贝),则从尾部开始倒序拷贝,避免覆盖未读取的数据。
memmove(str + 2, str, 5); // 安全处理重叠
#include
int memcmp(const void* s1, const void* s2, size_t n);
s1
和s2
的前n
个字节0
:内存内容相同>0
:s1
中第一个不同字节大于s2
<0
:s1
中第一个不同字节小于 s2
#include
#include
#include
int main()
{
// 准备比较的数据
int* arr1 = (int*)mallco(3 * sizeof(int)); // 3个元素
int* arr2 = (int*)callco(4 * sizeof(in1t)); // 4个元素
// 清零
memset(arr1, 0, 3 * sizeof(int));
// 赋值
arr[0] = 60; arr[1] = 66;
arr[0] = 70; arr2[1] = 5;
// 比较
int cmp_result = memcmp(arr2, arr1, 2 * sizeof(int)); // 双方参与比较的字节数完全一致
printf("比较结果:%d-(%s)\n", cmp_result, cmp_result > 0 ? "大于" : cmp_result < 0 ? "小于" : "等于");
// 释放内存
free(arr1);
free(arr2);
arr1 = arr2 = NULL;
return 0;
}
头文件:#include
函数原型:
void* memchr(const void* s, int c, size_t n);
void* memrchr(const void* s, int c, size_t n);
函数功能:在s
的前n
个字节中查找字符c
返回值:
注意事项:
memrchr
是GNU扩展函数,需手动声明(只要不是C语言标准提供,编译的时候都需要手动声明或链接)示例:
#include
#include
// memrchr是GUN扩展函数,需要外部声明
extern void* memrchr(const void*, int, size_t);
int main()
{
// 准备一个测试数组
char str[] = {'A','B','C','B'};
// 查找字符'B'
char * first = (char*) memchr(str, 'B', sizeof(str));
char * last = (char*) memrchr(str, 'B', sizeof(str)); // GUN扩展函数
printf("first = %p, last=%p\n", first, last);
printf("第1个B的位置, %ld\n", first -str); // 1
printf("最后1个B的位置, %ld\n", last -str); // 3
}
``