个人主页:_麦麦_
今日名言:生活不能等待别人来安排 ,要自己去争取和奋斗;而不论其结果是喜是悲,但可以慰藉的是,你总不枉在这世界上活了一场。有了这样的认识,你就会珍重生活,而不会玩世不恭;同时,也会给人自身注入一种强大的内在力量。——《平凡的世界》
目录
一、前言
二、正文
4. 错误信息报告
♥错误信息
♥strerror
♥fopen(额外赠送)
5.字符分类函数
6.字符转换【只针对字母】
♥tolower
♥toupper
7.内存操作函数
♥memcpy
♥ memmove
♥memcmp函数
♥memset
三、结语
不知不觉中,关于字符函数和字符串函数的讲解步入了尾声,在今天这一部分我们主要讲解三大类:错误信报告、字符操作和内存操作函数。大家一定要搬来小板凳好好听讲呀!为小伙伴们送上迟到的元宵节快乐。
在正式开始介绍strerror在这个函数之前,我们需要先对错误码与错误信息有一个大致的了解。
C语言的库函数在运行的时候,如果发生错误,就会将错误码存在一个变量中,这个变量是:errno,而这些错误码通常是一些数字 :1、 2、 3、 4、 5。
而这些错误码就分别对应着错误信息,那么我们该如何翻译错误码呢,这就用到了strerror函数。
char * strerror(int errnum);
●功能:用于返回错误码所对应的错误信息
●包含的头文件:
//strerror函数使用演示
#include
#include
#include
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
printf("%s\n", strerror(5));
return 0;
}
那么在什么场景下我们会用到strerroe函数,就字面意义而言,就是当我们使用库函数失败时,可以采用strerroe函数来帮助我们认识到使用该库函数失败的原因,从而对此进行有针对性的修改。下面我就以“fopen”函数为例,来让小伙伴更具体地认识strerror的使用场景。
PFILE * fopen(const char * filename,const char * mode)
●功能:打开文件
●参数: 指向所打开文件的指针,指向打开方式的指针
●头文件:
●返回值:如果打开成功,就返回一个有效指针;如果打开失败,就返回一个NULL指针。
fopen函数使用演示
#include
#include
int main()
{
//采用阅读的方式打开文件
FILE* pFile;
pFile = fopen("text.ext", "r");
if (pFile==NULL)
{
printf("打开文件失败\n");
return 1;
}
//读文件(略)
//关闭文件
fclose(pFile);
return 0;
}
当我们运行该段代码的时候,屏幕上会打印“打开文件失败”,但是如果我们想解决这个问题,就会发现无从下手,我们并不知道为什么文件会打开失败,自然也就无从下手。这个时候,strerror函数就起到了一个很好地报告错误信息的效果。
//strerroe使用场景演示
#include
#include
#include
int main()
{
//采用阅读的方式打开文件
FILE* pFile;
pFile = fopen("text.ext", "r");
if (pFile==NULL)
{
printf("%s\n",strerror(errno));
return 1;
}
//读文件(略)
//关闭文件
fclose(pFile);
return 0;
}
函数 如果它的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格' '、换页'\f'、换行'\n'、回车'\r'、制表符'\t'或垂直制表符'\v'
isdigit 十进制数字0-9
isxdigit 十六进制数字,包括所有十进制数字,小写字母a-f,大写字母A-F
islower 小写字母a-z
issupper 大写字母A-Z
isalpha 字母a-z或A-Z
isalnum 字母或者数字,a-z、A-Z、0-9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空格字符
//字符分类函数使用示例
#include
#include
int main()
{
int ret = islower('A'); //判断是否为小写字母
printf("%d\n", ret);
return 0;
}
int tolower (int c);
●功能:转换成小写字母
int tolower (int c);
●功能:转换成大写字母
//字符转换函数使用示例
#include
#include
int main()
{
printf("%c\n", tolower('A')); //转换成小写字符
printf("%c\n", toupper('a')); //转换成大写字符
return 0;
}
在介绍完上述函数后,我们为什么继续介绍内存操作函数呢,是因为上述函数确实能对字符和字符串进行很好的操作,但如果换做是整形数组,或者结构体呢。上述函数就显得捉襟见肘,难以下手了。这也是内存操作函数存在的意义。
⑴函数介绍
void * memcpy(void * destination, const void *source, size_t)
●功能:函数从courcede的位置开始向后复制num个字节的数据到destination的内存位置
●这个函数在遇到'\0'的时候并不会停下来
●如果source和destination有任何的重叠,复制的结果都是未定义的
//memcpy函数使用演示
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5] ={0};
memcpy(arr2, arr1 + 3, 40);
return 0;
}
//memcpy函数的模拟实现
#include
void* my_memcpy(void* dest, void* sorc, size_t num)
{
assert(dest && sorc);
char* ret = (char *)dest;
while (num--)
{
*(char*)dest = *(char*)sorc;
dest=(char*)dest+1;
sorc=(char*)sorc+1;
}
return ret;
}
通过对memcpy函数的介绍,我们发现该函数仍存在一定缺陷,就是source与destination若过有重叠,那么可能得不到我们想要的结果,代码如下:
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1 + 4, arr1 + 3, 9);
return 0;
}
//理论上:1 2 3 4 4 5 6 8 9 10
//实际上:1 2 3 4 4 4 4 8 9 10
⑴函数介绍
void * memmove(void * destnation, const void * source, size_t);
●memmove与memcpy的差别就是memmove处理的源内存块和目标内存块是可以重叠的
●如果源空间和目标空间出现重叠,就得使用memmove函数处理
/memmove函数使用示例
#include
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 4, arr1 + 3, 9);
return 0;
}
⑵模拟实现
在实现memmove的模拟实现之前,我们需要先梳理下实现思路。首先,为什么memcpy不能对重叠空间进行拷贝,是因为在进行拷贝的时候,由于源空间与目标空间具有重叠部分,会将源空间的原本的内容进行修改,导致无法实现想要的拷贝结果。在知道这个原因之后,接下来就是对拷贝过程的优化。拷贝其实有两种方式,一种是从前往后拷贝,另一种则是从后向前拷贝。采用后者确实能解决部分的源空间与目标空间的重叠的拷贝,但是有的重叠拷贝它却无法解决。因此最好的拷贝方式应该是将二者结合,针对不同情况采用不同的拷贝方式。以下只采用一种方法进行模拟实现。
//memmove的模拟实现
#include
#include
void* my_memmove(void* dest, const void* sorc, size_t num)
{
assert(dest && sorc);
char* ret = (char *)dest;
if (((char *)dest-(char *)sorc) < 0) //目标空间指针位于源空间指针之前
{
while (num--)
{
*(char*)dest = *(char*)sorc; //前->后
dest = (char*)dest + 1;
sorc = (char*)sorc + 1;
}
}
else //目标空间指针与源空间指针重合或之后
{
while (num--)
{
*((char*)dest + num ) = *((char*)sorc + num ); //后->前
}
}
return ret;
}
int memcmp(const void * ptr1, const void * ptr2 ,size_t num);
●功能:比较从ptr1和ptr2开始的n个字节
//memcmp函数使用示例
#include
int main()
{ //VS小端存储
int arr1[] = { 1, 2, 3 }; //01 00 00 00 02 00 00 00 03 00 00 00
int arr2[] = { 1, 2, 5 }; //01 00 00 00 02 00 00 00 05 00 00 00
int ret = memcmp(arr1, arr2, 9);
return 0;
}
void * memset(void * ptr , int value, size_t num);
●功能:内存设置函数
●以字节为单位来设置内存函数
//memset函数使用示例
#include
int main()
{
char arr[] = "welcome to mt blog!";
memset(arr, 'x', 7);
return 0;
}
关于字符串函数和字符函数的讲解就已经全部结束了,如果对库里其他的函数感兴趣的同学可以通过一下网站继续学习:https://cplusplus.com/
关注我 _麦麦_分享更多干货:_麦麦_的博客_CSDN博客-领域博主
大家的「关注❤️ + 点赞 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下期见!