1、memcpy函数
1.1 语法形式和注意事项
语法形式类似于strncpy函数,但是memcpy的num是传入字节大小,而不是数字
void * memcpy ( void * destination, const void * source, size_t num );
- 头文件***string.h***
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置
- 这个函数在遇到 ‘\0’ 的时候并不会停下来
- 如果source和destination有任何的重叠,复制的结果都是未定义的
1.2 示例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//类似于strncpy,但是针对内存块进行拷贝
memcpy(arr2, arr1, 40);
for (int i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
输出的结果为:
1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0
1.3 模拟实现
>1模拟(不同数组)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>//使用assert包含的头文件
void* my_memcpy(void* arr2, void* arr1, int num)
{
//判断是否为空指针
assert(arr1 && arr2);
void* n = arr2;
//交换40个字节,交换1次就减1个
//num = 0,跳出循环,也可以使用for循环
while (num--)
{
//强转成char*类型,因为只占一个字节
//让arr2的单字节=arr1的单字节
*(char*)arr2 = *(char*)arr1;
//交换后(在char*类型的前提下)都往后移一个字节
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
return n;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
void* ret = my_memcpy(arr2, arr1, 40);//传入实参
//打印数组arr2
for (int i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
地址交换时可使用for循环,如下:
for (int i = 0; i < num; i++)
{
*(char*)arr2 = *(char*)arr1;
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
2>模拟(同个数组)
2.1>代码分析如图:
2.2>正确用法(使用memcpy函数)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
memcpy(arr1 + 2, arr1, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
//结果:1 2 1 2 3 4 5 8 9 10
}
return 0;
}
2.3>错误示例:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>//使用assert包含的头文件
void* my_memcpy(void* arr2, void* arr1, int num)
{
assert(arr1 && arr2);
//将指针n指向arr1首地址
void* n = arr1;
while (num--)
{
*(char*)arr2 = *(char*)arr1;
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
return n;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
void* ret = my_memcpy(arr1+1, arr1, 20);//传入实参
//打印数组arr2
for (int i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
//结果:1 2 1 2 1 2 1 8 9 10
}
return 0;
}
接下来介绍memmove函数时,会具体分析是怎么出错的!!!
3、memmove函数
3.1 语法形式和注意事项
与memcpy形式一模一样
void * memmove ( void * destination, const void * source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理
3.2 示例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//算出数组长度
int len = sizeof(arr) / sizeof(arr[0]);
//memmove语法使用
memmove(arr + 3, arr, 5 * sizeof(int));
//打印
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
打印出来为:
1 2 3 1 2 3 4 5 9 10
3.3 模拟实现(重要部分!!!)
1>代码分析如图
这就是为什么**[[内存函数#错误示例:|前面代码]]**错误的原因
2>代码实现
2.1>错误代码版本
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>//使用assert包含的头文件
void* my_memcpy(void* arr2, void* arr1, int num)
{
assert(arr1 && arr2);
//将指针n指向arr1首地址
void* n = arr1;
while (num--)
{
*(char*)arr2 = *(char*)arr1;
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
return n;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
void* ret = my_memcpy(arr1+1, arr1, 20);//传入实参
//打印数组arr2
for (int i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
//结果:1 2 1 2 1 2 1 8 9 10
}
return 0;
}
2.2>正确代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
//不希望src被修改,前面加const
void* my_memmove(void* dest,const void* src, int sz)
{
assert(dest && src);
void* s = src;
if (dest < src)
{
while (sz--)
{
//前 > 后
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//前 < 后
while (sz--)
{
*((char*)dest + sz) = *((char*)src + sz);
}
}
return s;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(arr[0]);
void* set = my_memmove(arr + 3, arr, 5 * sizeof(int));
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
4、memset函数
4.1 语法形式和注意事项
void * memset ( void * ptr, int value, size_t num);
- 对于字符串来说,可以以字符为单位来设置
- 对于整形来说,是以字节为单位来设置,不能以元素为单位来设置
4.2对字符串
1>从头开始
char arr1[] = "hallo world";
size_t sz = strlen(arr1);
memset(arr1, 'x', 5);
for (int i = 0; i < sz; i++)
{
printf("%c", arr1[i]);
}
打印为:
xxxxx world
2>不从头开始
char arr1[] = "hallo world";
size_t sz = strlen(arr1);
//让指针指向第4个字符
memset(arr1+3, 'x', 5);
for (int i = 0; i < sz; i++)
{
printf("%c", arr1[i]);
}
打印为:
halxxxxxrld
4.3 对整形数组
1>让value为0,可直接设置
int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr2) / sizeof(arr2[0]);
memset(arr2, 0, 5 * sizeof(int));
for (int i = 0; i < len; i++)
{
printf("%d ", arr2[i]);
}
打印为:
0 0 0 0 0 6 7 8 9 10
2>让value不为0,不可直接设置
int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr2) / sizeof(arr2[0]);
memset(arr2, 1, 5 * sizeof(int));
for (int i = 0; i < len; i++)
{
printf("%d ", arr2[i]);
}
打印为:
5、memcmp函数
5.1 语法形式与注意事项
//头文件
#include<string.h>
int memcmp ( const void * ptr1, const void * ptr2, size_t num);
- 比较ptr1和ptr2指针指向的位置开始,向后的num个字节
返回值如下: - 如果ptr1指向的内容比ptr2指向的内容大,返回值大于0
- 如果ptr1指向的内容和ptr2指向的内容一样,返回值为0
- 如果ptr1指向的内容比ptr2指向的内容小,返回值小于0
5.2示例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>//头文件
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8 };
int arr2[] = { 1,2,3,4,8,8,8,8 };
int num1 = memcmp(arr1, arr2, 4 * sizeof(int));
int num2 = memcmp(arr1, arr2, 5 * sizeof(int));
printf("%d\n", num1);
printf("%d", num2);
return 0;
}
输出结果:
0
-1