目录
前言:
1.内存函数
memcpy()
memmove()
memcmp()
memset()
2.错误信息报告函数
strerror()
perror()
作用:内存拷贝
注意:count:要拷贝的字节数
函数memcpy从src位置开始向后赋值count个字节的数据到dest的内存位置,
遇到 ‘\0’ 的时候不停下来
如果source和destination有任何的重叠,复制的结果都是未定义的
使用样例:
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memcpy(arr2, arr1, sizeof(int) * 10);
int i = 0;
for (i = 0;i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
模拟实现:
void* my_memcpy(void* dest,const void* src,size_t count )
{
assert(dest&&src);
void* ret = dest; //为了返回目标空间起始地址
//共拷贝n个字节
while(count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;//这样写是防止编译器报错
src = (char*)src + 1;
}
//若写成 dest = (char*)dest++; //有些编译器可能跑不过去
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, sizeof(int) * 10);
int i = 0;
for (i = 0;i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
注意:我们这种模拟实现的方法,不能处理重叠的内存拷贝,
如:想要将数组的1234拷贝到3456中,
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest; //为了返回目标空间起始地址
//共拷贝n个字节
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;//这样写是防止编译器报错
src = (char*)src + 1;
}
//若写成 dest = (char*)dest++; //有些编译器可能跑不过去
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr+2, arr, 16);
int i = 0;
for (i = 0;i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
想要的效果:1212347890
使用my_memcpy得到的结果:1 2 1 2 1 2 7 8 9 10
但是使用库函数memcpy函数,可以实现拷贝
但是C语言只要求memcpy函数可以实现不重叠的内存拷贝即可,要实现重叠内存拷贝的话,实现memmove函数
作用:内存拷贝-可处理重叠的内存拷贝
函数原型:
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
使用样例:
int main()
{
int arr[] ={1,2,3,4,5,6,7,8,9,10};
memmove(arr+2,arr,16);
int i = 0;
for(i = 0;i <10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
打印结果:1 2 1 2 3 4 7 8 9 10
模拟实现:
以dest
注意:由于不知道传过来的是什么类型的数据,所以可以使用void*类型接收参数
返回目标空间的起始地址
由于只知道拷贝的字节数,不知道拷贝的类型->使用char*类型,每次拷贝一个字节
从前向后拷贝:dest和src强转为char*类型,然后+1,共拷贝n次即可
如何从后向前拷贝
->原数据的最后拷贝到目标位置的最后,然后二者不断往前拷贝
从后往前拷贝:dest和src强转为char*类型后,+count,跳过count个字节,指向要拷贝的最后一个字节,不断拷贝,count--
void* my_memmove(void* dest, void* src, size_t count)
{
assert(dest && src);
void* tmp = dest;//后序返回目标空间的地址
if (dest < src)
{
//共拷贝count次
while (count--)
{
//从前往后拷贝
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后往前拷贝
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return tmp;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//my_memmove(arr+2,arr,16);
my_memmove(arr , arr+2, 16);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
作用:内存比较
使用strcmp()只能比较字符串,而memcmp()可以比较整形,也可以比较字符串
使用样例:
int main()
{
int arr1[] = {1,2,3,4};
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
int arr2[] = {1,2,3,5};
//01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00
int ret = memcmp(arr1,arr2,12);
//比较前12个字节,二者相同,返回0
printf("%d\n",ret);//0
ret = memcmp(arr1,arr2,13);
//比较前13个字节,arr1中的04比arr2中的05小,返回-1
printf("%d\n",ret); //-1
}
模拟实现memcmp()
注意:由于不知道传过来的是什么类型->使用void*类型接收,由于要比较的字节数恒大于0,所以用size_t接收,
由于只知道要比较的字节数,不知道是什么类型->所以使用char* 一个字节一个字节的向后比较,直到找到二者中字节对应内容不相等时,比较此时二者字节内容
int my_memcmp(const void* p1, const void* p2, size_t count)
{
assert(p1 && p2);
while (count--)
{
//如果二者指向的一个字节内容相等->指向下一个字节
if (*(char*) p1 == *(char*)p2)
{
p1 = (char*)p1+1;
p2 = (char*)p2+1;
}
else
{
//此时二者指向的字节内容不相同
//通过强转为char* 比较此时二者指向的一个字节内容
if ((*(char*)p1 - *(char*)p2) > 0)
{
return 1;
}
else
{
return -1;
}
}
}
//跳出循环时,count = 0,说明二者要比较的字节的内容都相同
return 0;
}
int main()
{
int arr1[] = { 1,2,3,4 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
int arr2[] = { 1,2,3,99 };
//01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00
int ret = my_memcmp(arr1, arr2, 12);
//比较前12个字节,二者相同,返回0
printf("%d\n", ret); //0
ret = my_memcmp(arr1, arr2, 13);
//比较前13个字节,arr1中的04比arr2中的05小,返回-1
printf("%d\n", ret); //-1
char* p1 = "Mangopp";
char* p2 = "Mangoppp";
ret = memcmp(p1, p2, 8);
printf("%d\n", ret); //-1
}
作用:内存设置函数
将缓冲区设置为指定的字符
以字节为单位进行初始化
-----------------
使用样例:
int main()
{
int arr[] = {1,2,3,4,5};
memset(arr,0,20); //初始化20个字节内容为0
memset(arr,1,20); //初始化20个字节内容为1
return 0;
}
注意点:以字节为单位进行初始化
模拟实现
注意:由于不知道传过来的是什么类型->使用void*类型接收,由于要设置的字节数恒大于0,所以用size_t接收,
由于只知道要设置的字节数,不知道是什么类型->所以使用char* 一个字节一个字节的向后设置
返回目标空间的起始地址
写法1:接收类型为整形
memset:将缓冲区设置为指定的字符,所以要把整形强转为字符型,再把每一个字节设置为整形对应ascii的字符
void* my_memset(void* dest, int c, size_t count)
{
assert(dest);
void* tmp = dest;
char set_c = (char)c;
//内存设置,共设置count个字节
while (count--)
{
*(char*)dest = set_c;
dest = (char*)dest + 1;
}
return tmp;
}
int main()
{
int arr[] = { 1,2,3,4,5 };
my_memset(arr, 0, 20); //初始化20个字节内容为0
my_memset(arr, 1, 20);//初始化20个字节的内容为1
return 0;
}
写法2:接收类型为字符
若直接设置字符,要设置的是其对应的值 1 而不是其对应的ascii码值。所以要减去‘0’
‘1’ - ‘0’ -> 1 所以接收的字符还要减上字符0
void* my_memset(void* dest, char c, size_t count)
{
assert(dest);
void* tmp = dest;
//内存设置,共设置count个字节
while (count--)
{
*(char*)dest = c - '0';
dest = (char*)dest + 1;
}
return tmp;
}
int main()
{
int arr[] = { 1,2,3,4,5 };
my_memset(arr, '0', 20); //初始化20个字节内容为0
my_memset(arr, '1', 20);
return 0;
}
作用:可以返回C语言内置的错误码对应的错误信息
返回错误码对应的错误信息
参数传错误码,翻译成错误信息,返回的是错误码对应的错误信息的字符串的首字符地址
C语言库函数调用失败的时候,会把错误码存储到errno变量中
使用样例:
#include
int main()
{
printf("%s\n",strerror(0));
printf("%s\n",strerror(1));
printf("%s\n",strerror(2));
printf("%s\n",strerror(3));
return 0;
}
打印结果:
No error
Operation not permitted
No such file or directory
No such process
应用:
int main()
{
FILE* pf = fopen("test.txt","r");
if(pf == NULL)
{
printf("%s\n",strerror(errno)); //C会把错误码放到errno变量,打印错误码对应的错误信息
}
else
{
printf("打开成功\n");
}
return 0;
}
//fopen():打开文件的函数,如果打开成功,返回指向该文件的文件指针FILE* 如否则返回NULL
//r:只读方式打开
由于我们没有此文件:所以打印结果
No such file or directory
作用:
函数原型:
string:自定义字符
使用样例:
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("测试");
perror("测试:\n");
perror("\n");
}
else
{
printf("打开成功\n");
}
return 0;
}
测试: No such file or directory
测试:
: No such file or directory
: No such file or directory
如果perror中有内容,先打印内容,然后自动在后面加上冒号: 然后打印错误信息
缺点:不想打印时也打印了
最后,感谢你能看到这里!如果感觉此文对你有所帮助的,欢迎留个三连呀!感谢