C语言部分内存函数详解
- 前言
- 1.`memcpy`
- 1.1基本用法
- 1.2注意事项
- **目标空间与原空间不能重叠**
- **目标空间原数据会被覆盖**
- **目标空间要够大**
- **拷贝字节数需小于原空间大小**
- 1.3模拟实现
- 2.`memmove`
- 2.1基本用法
- 2.2注意事项
- 2.3模拟实现
- 3.`memset`
- 3.1基本用法
- 4.`memcmp`
- 4.1基本用法
- 4.2注意事项
- **按字节比较**
前言
在我的C语言-部分字符串函数详解 1-4和C语言-部分字符串函数详解 5-10中,函数的操作对象为字符串,如果想处理其他类型的数据,则需用到内存函数
本文将介绍<string.h>
头文件下的部分内存函数:
- 1.
memcpy
- 2.
memmove
- 3.
memset
- 4.
memcmp
1.memcpy
函数原型:
void * memcpy ( void * destination, const void * source, size_t num );
简介:Copy block of memory
——拷贝一块内存
1.1基本用法
会从source
向后拷贝num
字节的内容至destination
。
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 5*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);
运行结果:
1.2注意事项
目标空间与原空间不能重叠
如果重叠,拷贝的结果未定义,需使用memmove
处理重叠的情况。
在VS2022上,重叠对拷贝结果无影响:
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1+3, arr1, 5*sizeof(int));
for (int i = 0; i < 10; i++)printf("%d ", arr1[i]);
运行结果:
但C语言标准中拷贝的结果未定义,因此仍不建议使用memcpy
拷贝有重叠的情况。
目标空间原数据会被覆盖
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 9,9,9,9,9 };
memcpy(arr2, arr1, 5*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);
运行结果:
目标空间要够大
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5];
memcpy(arr2, arr1, 10*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);
运行结果:
VS2022给出了相应的警告:
拷贝字节数需小于原空间大小
int arr1[5] = { 1,2,3,4,5 };
int arr2[10];
memcpy(arr2, arr1, 10 * sizeof(int));
for (int i = 0; i < 10; i++)printf("%d ", arr2[i]);
运行结果:
VS2022给出了相应的警告:
1.3模拟实现
void* my_memcpy(void* dst, const void* src, size_t num)
{
assert(dst && src);
void* ret = dst;
while (num--)*((char*)dst)++ = *((char*)src)++;
return ret;
}
为了处理多种类型的数据,我们传入void*
的指针,在强转成char
,这样在拷贝时可以按字节依次拷贝。
2.memmove
函数原型:
void * memmove ( void * destination, const void * source, size_t num );
简介:Move block of memory
——拷贝一块内存
2.1基本用法
memmove
与memcpy
的用法基本一致,且memmove
可处理有重叠的空间。
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 3, arr1, 5 * sizeof(int));
for (int i = 0; i < 10; i++)printf("%d ", arr1[i]);
运行结果:
2.2注意事项
与memcpy
的基本一致,且memmove
可处理有重叠的空间。
2.3模拟实现
在memcpy
的模拟实现中,我只是单方向的进行拷贝,完成了C语言对memcpy
的基本要求。
而在memmove
的模拟实现中,如果单方向进行拷贝,会在空间重叠时出现拷贝了新数据的现象,因此需判断拷贝方向。
void* my_memmove(void* dst, const void* src, size_t num)
{
assert(dst && src);
void *ret = dst;
if (dst < src)
{
while (num--)*((char*)dst)++ = *((char*)src)++;
return ret;
}
else
{
while (num--)*(((char*)dst) + num) = *(((char*)src) + num);
return ret;
}
}
3.memset
函数原型:
void * memset ( void * ptr, int value, size_t num );
简介:Fill block of memory
——填充内存块
3.1基本用法
按字节设置内存,可用于初始化
typedef struct Peo
{
char name[20];
int age;
char tele[12];
}Peo;
typedef struct Contact
{
struct Peo peo[100];
int num;
}Contact;
int main()
{
Contact con;
Contact* p = &con;
memset(p->peo, 0, sizeof(p->peo));
return 0;
}
这段代码是我写的通讯录里的。
定义了两个结构体类型 Peo
和 Contact
。Peo
结构体包含姓名、年龄和电话号码。而 Contact
结构体则包含一个 Peo
类型的数组,以及一个整型变量 num
,用于记录实际存储了多少个联系人。
在 main
函数中,首先创建了一个 Contact
类型的变量 con
,接着定义了一个指向 Contact
类型的指针 p
并将其指向 con
。然后使用 memset
函数将 p->peo
数组中的所有元素初始化为0
。
初始化效果:
对于 char
类型的数组,这会使它们只包含空字符。
对于 int
类型的成员,这会将它们初始化为0
。
数组大小:sizeof(p->peo)
返回的是整个 peo
数组的大小,即100个 Peo
结构体的总大小。
4.memcmp
函数原型:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
简介:Compare two blocks of memory
——比较两个内存块
4.1基本用法
char ch1[] = "aaaa";
char ch2[] = "aaab";
int n= memcmp(ch1, ch2, 4);
if (n > 0)printf(">");
else if (n < 0)printf("<");
else printf("=");
运行结果:
4.2注意事项
按字节比较
不管什么类型的数据,memcmp
都是按字节比较,这使得有时候不能得到预期结果:
int arr1[10] = { 1 };
int arr2[10] = { 256 };
int n = memcmp(arr1, arr2, 4);
if (n > 0)printf(">");
else if (n < 0)printf("<");
else printf("=");
运行结果:
1
肯定比256
小,但我们比的规则是逐字节
在小端存储的机器上:
1
在内存:
256
在内存:
由于是逐字节比较,所以结果是1
>256
希望本篇文章对你有所帮助!
本人仅仅是个C语言初学者,如有任何意见,欢迎各位提出!
相关文章:
C语言指针详解-上
C语言指针详解-下