C语言第九章字符函数和字符串函数

一.字符分类函数

1.字符分类函数总览

C语言规定字符有很多种类型,比如:数字字符,空白字符,转义字符等。当我们需要将这些不同类型的字符进行分类时,就应该了解C语言为我们提供的字符分类函数。下面对字符分类函数做进一步的了解。

|----------|-------------------------------------------------------------------|
| 函数 | 参数符合下列情况就返回真 |
| iscntrl | 任何控制字符 |
| isspace | 空白字符:空格:' ',换页符:'\f',换行符:'\n',回车符:'\r',水平制表符:'\t',垂直制表符:'\v' |
| isdigit | 十进制数字字符:0-9 |
| isxdigit | 十六进制数字字符:0-9和A-F(a-f) |
| islower | 小写字母字符:a-z |
| isupper | 大写字母字符:A-Z |
| isalpha | 所有字母字符:a-z 和A-Z |
| isalnum | 字母或者数字字符:a-z 和A-Z和0-9 |
| ispunct | 标点符号字符:任何不属于数字或字母的可打印图形字符 |
| isgraph | 任何图形字符 |
| isprint | 任何可打印字符:包括图形字符和空白字符 |
[字符分类函数概要]

2.字符分类函数详细解释

字符分类函数使用时均需要包含头文件:<ctype.h>。字符分类函数都是依赖字符的ASCII码值进行字符的分类。上述多种字符分类函数的用法极为相似,下面给出全部函数的介绍:

上述iscntrl函数的解释:函数参数为整型,返回类型也为整型。此函数的作用是:判断参数字符是否为控制字符(control character)。根据上方图片的解释,函数通过ASCII码值来判断参数字符是否为控制字符。当函数参数为控制字符时,函数返回真(非0整数);否则函数返回假0。

上述isspace函数的解释:该函数参数类型为整型,且函数的返回类型也为整型。函数的作用是判读参数字符是否为空白字符。并且上述图片也举例了一些空白字符。函数参数为空白字符时,返回真(非0整数);否则函数返回假0。

上述isdigit函数的解释:函数参数为和返回类型均为整型。该函数的作用为:判断参数字符是否为十进制数字字符。当函数参数为十进制数字字符时,函数返回真(非0整数);否则函数返回假0。

上述isxdigit函数的解释:函数的参数和返回值的类型均为整型。该函数的作用:判断函数参数字符是否为十六进制的数字字符。在这里要知道十六进制的数字字符包括0-9、a-z、A-Z。如果函数参数字符为十六进制的数字字符,那么函数返回真(非0整数);否则函数返回假0。

上述islower函数的解释:该函数的参数和返回值类型均为整型。该函数的作用是:判断函数参数字符是否为英语的小写字母字符。当将函数参数为英语小写字母字符时,函数返回真(非0整数);否则函数返回假0。下面的每个函数的作用顶部表格均有涉及,并且这些字符分类函数的用法极为相似,所以最后只举例一种字符分类函数的用法。

3.字符分类函数使用方法

通过上述函数的详细解释,我们可以发现字符分类函数具有极大的相似之处。每个字符分类函数的参数和函数返回值类型都为整型。函数参数为整型的原因是为了得到需要判断字符的ASCII码值,通过与特殊字符的ASCII码值进行比较,从而达到判断字符类型的目的。函数返回值为整型的原因是:当字符满足该函数的判段的字符类型,则返回一个非0的整数;否则返回0。这样定义返回值,可以直观的得到判断结果。下面我们使用其中一个字符分类函数,作为例子来理解。

题目要求:将给出的小写字符转换为大写,其他字符不变。

cpp 复制代码
#include <stdio.h>
#include <ctype.h>    //调用字符分类函数需要的头文件
int main ()
{
 int i = 0;
 char str[] = "Test String.\n";    //定义需要转换的字符数组
 char c;
 while (str[i])    //当字符数组没有到字符串末尾时,循环继续
 {
     c = str[i];    
     if (islower(c))     //调用判断字符是否为小写的函数
         c -= 32;    //如果为小写,利用ASCII码值,将其转换为大写
     putchar(c);    //进行完上述操作,下面逐一进行字符的打印
     i++;
 }
 return 0;
}

上述代码的具体解释:定义了字符串数组用于接下来的大小写转换,用while循环,当字符数组没到字符串结尾的\0时,循环一直进行,当进行到字符串末尾的\0时,循环终止。在循环的内部,先判断字符是否为小写,调用islower函数,灵活运用函数的返回值,当函数的返回值为非0值时,进行if语句,将小写转换为大写。当字符不为小写字母时,函数返回0,不进行ASCII码值的变换。最后逐一打印字符,完成题目的要求。

在上述代码实践中,我们用的是ASCII码值进行字符的大小写转换,其实字符函数也有相关的字符转换函数,其作用就是字符的英语大小写转换。下面我们来学习字符转换函数:

二.字符转换函数

在C语言中,总共为我们提供了两种字符转换函数。

int tolower ( int c ); //将参数传进去的大写字母转为小写字母

int toupper ( int c ); //将参数传进去的小写字母转为大写字母

下面我们详细解释上述两字符转换函数:

上述两个函数的参数部分和函数的返回值均为整型,函数参数部分是为了接收字符的ASCII码值,方便进一步进行大小写的转换。函数返回值是为了返回转换之后的字符ASCII码值,方便后续的使用。下面举字符转换函数的使用例子:

cpp 复制代码
#include <stdio.h>
#include <ctype.h>    //调用字符分类和转换函数的头文件
int main ()
{
 int i = 0;
 char str[] = "Test String.\n";
 char c;
 while (str[i])
 {
     c = str[i];
     if (islower(c))         //判断该字符是否为小写
         c = toupper(c);    //当字符为小写时,调用字符转换函数,将小写转换为大写
     putchar(c);
     i++;
 }
 return 0;
}

上述代码的具体解释:在字符分类函数的例子里,我们利用了ASCII码值进行大小写的转换。现在我们学习了字符转换函数,就可以直接使用 tolower 函数。从而达到预期的效果。

这里需要注意的是:字符转换函数同样需要<ctype.h>头文件,在字符转换函数调用时,其本质是通过ASCII码值转换大小写的。

三.字符串函数

1.strlen函数的使用和模拟实现

(1)函数的使用

在原先的学习中,我们了解了字符串函数中的strlen,并且知道了该函数的两种模拟实现方法。下面将对strlen函数进行复习和深层次的理解。

上述为strlen函数的图片介绍,根据上述图片得知:函数的参数类型为const char *;函数的返回值类型为无符号整型。函数参数类型经过const修饰,防止误将传来的字符串修改,char *类型指针接收字符串的首地址。函数的作用是从函数参数的地址处往后找 \0,找到后返回从字符串起始地址到 \0位置的字符串长度,因为是长度,所以函数的返回值是无符号整型。

这里需要注意的是:字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' );参数指向的字符串必须要以 '\0' 结束; 注意函数的返回值为size_t,是无符号的( 易错 );strlen的使需要包含头文件<string.h>。

下面举一个例题,强化一下对注意事项的理解:

cpp 复制代码
#include <stdio.h>
#include <string.h>    //字符串函数需要的头文件
int main()
{
 const char* str1 = "abcdef";    //定义两个字符串
 const char* str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)    //利用strleen函数判断两者的大小,打印相关的信息
 {
     printf("str2>str1\n");
 } 
 else
 {
     printf("srt1>str2\n");
 }
 return 0;
}

上述代码的具体解释:明显的第一个字符串比第二个字符串要长一些,所以我们会认为上述代码的输出结果为srt1>str2,实际上述代码的输出结果为str2>str1。这是为什么呢?

不要忘记了,strlen函数的返回类型为无符号整型,两个无符号整型类型的数据进行计算,得到的结果一定也是无符号整型。在上述代码中,字符串2的长度减去字符串1的长度结果为-3。但是我们要明白这里的-3应该是无符号整型。在系统中,数据存储的方式是以补码的形式,所以-3的补码为11111111 11111111 11111111 11111101。左侧32位数字就是-3的补码,但是现在被认为是无符号整型,那么首位的符号位就会被认为是数值位,这样原本结果应该是-3,现在却是一个特别大的整数,该数具体十六进制表示形式为:0xFFFFFFFD。可见此数非常之大。

(2)函数的模拟实现

在先前的学习中,我们学习了两种strlen函数的模拟实现的方法,下面进行复习和更深层次的学习:

<1>方法一:计数器法
cpp 复制代码
//计数器⽅式 
int my_strlen(const char * str)    //模拟实现strlen函数
{
 int count = 0;    //定义计数器
 assert(str);    //调用assert函数,防止函数参数指针为空
 while(*str)    //当函数参数不为 \0进入循环
 {    
     count++;    //每一次循环,计数器++
     str++;        //将指针指向的位置后移,直至移到 \0处
 }
 return count;
}

上述strlen函数的实现手法为计数器法,从函数参数地址处开始,指针通过while循环的方式进行后移查找字符串末尾的 \0 ,直到找到 \0,函数返回计数器的数值。

<2>方法二:指针相减法
cpp 复制代码
//指针-指针的⽅式 
int my_strlen(char *s)    
{
 assert(str);    //防止函数参数指针为空指针
 char *p = s;    //创建新的指针变量,用于循环中指针的移动
 while(*p != '\0' )
     p++;    //利用循环,将指针变量p进行后移,直至移到 \0的前面
 return p-s;        //返回两指针的差值
}        

上述strlen函数的实现手法主要是运用了指针运算的法则,指针减法我们说过,当同类型指针相减时,得到的结果是两指针变量之间元素的个数。上述函数的实现中,通过创建新的指针变量,使函数参数的指针变量一直指向字符串的首地址,让创建的新指针变量进行后移,直至指向 \0前面的位置,最后函数返回两指针变量的差值。得到的结果就是字符串的长度。

<3>方法三:函数递归

我们在不久前了解了函数递归的法则,现在我们可以尝试用函数递归的方法模拟实现该函数。

根据上方图片的分析,我们可以知道:我们的my_strlen函数可以求出字符串的长度,求字符串长度时,当首字符不为 \0时,可以将此类大问题化为1+my_strlen(后面的字符串);当首元素为 \0时,函数返回0。

cpp 复制代码
//不能创建临时变量计数器 
int my_strlen(const char * str)
{
 assert(str);        //防止str为空指针时解引用出现错误
 if(*str == '\0')        //当字符串开头为 \0时,函数返回0
     return 0;
 else
     return 1 + my_strlen(str+1);    //当字符串不是 \0,则函数递归调用进一步求出字符串长度
}

上方代码的具体解释:当字符串首字符为 \0时,函数返回0;当函数首字符不为 \0时,函数自己调用自己,进行函数递归,进一步求出字符串长度。

2.strcpy函数的使用和模拟实现

(1)函数的使用

在C语言学习过程中,有时候需要对字符串进行遍历或者进行某些计算,但是我们不想将该字符串内的字符破坏掉。这时候就会再创建一个新的字符串,保存旧字符串的数值,这样就可以不用担心改掉原字符串的内容(可以随便霍霍了)。但是这样显然很麻烦,于是C语言为我们提供了字符串复制函数,下面我们一起来了解一下吧!

根据上方图片得知,该函数的作用是:将字符串进行复制。函数的参数为两个 char *类型的变量,用于接收字符串的首地址;函数的返回值是char *,目的是返回复制好的字符串首地址,方便后续直接使用函数返回值,进行字符串的打印等之类的操作。

这个函数需要注意的是:源字符串必须以 '\0' 结束,这样才能知道字符串是否复制完毕。会将源字符串中的 '\0' 拷贝到目标空间,方便后续对复制好的字符串进行直接的使用。 目标空间必须足够大,以确保能存放源字符串,防止因为空间不够导致程序报错。 目标空间必须可修改,否则就不可以将需要复制的字符串的值赋值给目标空间,进而达不到预期的效果。

(2)函数的模拟实现

cpp 复制代码
char* my_strcpy(char *dest, const char*src)
{ 
 char *ret = dest;    //创建指针变量保存字符串的首地址,防止因为计算而丢失首地址,这样就可以放心计算了
 assert(dest != NULL);        //防止两指针变量为空指针
 assert(src != NULL);
 while((*dest++ = *src++))
 {
     ;
 }
 return ret;
}

在上述代码中,while循环语句运用了较为高级的写法:将字符串内容和末尾的 \0一同复制给了目标空间。目标空间首位置指针和源头字符串首字符指针一同进行后移,在指针变量指向的位置后移同时进行了内容的赋值,最后当源头指针变量进行到 \0位置处时,因为是后置++,所以再进行最后的赋值,这样就达成了预期的效果:将源头字符串的内容和末尾的 \0进行复制到目标空间。

3.strcat函数的使用和模拟实现

(1)函数的使用

该函数介绍:根据上述图片可以得出,该函数的作用是:将一个字符串追加到另一个字符串的后面。该函数的参数为两个char *类型的指针变量,用于接收两个字符串的首字符地址;该函数的返回类型为char *类型,方便后续直接使用返回值进行打印或其它操作。

这个函数需要注意的是:源字符串必须以 '\0' 结束,否则找不到追加的起始位置。目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。目标空间必须有足够的大,能容纳下源字符串的内容 。目标空间必须可修改,

(2)函数的模拟实现

cpp 复制代码
char *my_strcat(char *dest, const char*src)
{
 char *ret = dest;        //创建新的指针变量保存字符串的首地址,防止因计算数值变化而无法返回
 assert(dest != NULL);    //防止两指针为空指针
 assert(src != NULL);
 while(*dest)    //while循环,使dest指针指向\0的位置,方便后续字符串的覆盖
 {
     dest++;
 }
 while((*dest++ = *src++))    //进行字符串的追加
 {
     ;
 }
 return ret;
}

根据上述图片的解析:我们可以得出:实现该函数只需要将源字符串的内容覆盖在目标空间字符串末尾的 \0位置处即可,这里我们不要忘记还要将原字符串的末尾 \0覆盖过去。

上述函数模拟实现的过程中,首先利用while循环找到目标空间字符串末尾的 \0,方便后续原字符串的覆盖,在找到末尾的 \0后,将原字符串复制到目标空间处(和strcpy函数实现的逻辑相同)。这样就完成了预期的效果:将原字符串追加到目标空间字符串的后面。

这里我们有个疑问?字符串是否可以对自己使用该函数?

首先dest指针会利用while循环找到该字符串的末尾 \0,然后src会覆盖掉目标空间的 \0,将src的内容逐步赋值给目标空间,但是因为src将 \0覆盖掉了,字符串末尾没有了 \0结尾,这样就会无限循环的进行追加,永不停息。这也是为什么原字符串末尾必须有 \0的原因。所以字符串不可以对自己使用该函数。

4.strcmp函数的使用和模拟实现

(1)函数的使用

该函数的介绍:该函数的作用是判断两字符串的大小关系。函数的参数为 const char *类型,是为了接收字符串的首字符地址,并且防止修改数据;函数的返回值为整型,当第一个字符串大于第二个字符串,则函数返回大于0的数字;当第一个字符串小于第二个字符串,则函数返回小于0的数字;当两字符串相等时,函数返回数字0。

此函数需要知道背后的原理,字符串的比较本质上比较的是每个字符的ASCII码值的大小。这里需要注意的是:该函数判断字符串的大小时,是逐一比较字符的ASCII码值,而不是比较字符串的长度。(也就是说:如果第一个字符串前面的字符ASCII码值比第二个字符串要大,那么第一个字符串就大于第二个字符串)。

例如字符串一:ts;第二个字符串为:abcdef。明显的第二个字符串的长度比第一个字符串的长度要长,但是第一个字符串的首字符ASCII码值大于第二个字符串首字符的ASCII码值,所以第一个字符串大于第二个字符串。

(2)函数的模拟实现

cpp 复制代码
int my_strcmp (const char * str1, const char * str2)
{
 int ret = 0 ;    
 assert(str1 != NULL);        //防止两指针为空指针
 assert(str2 != NULL);
 while(*str1 == *str2)    //当两指针解引用内容相同时,进入循环
 {
 if(*str1 == '\0')        //如果两指针的解引用内容均为\0,则说明两字符串相等,返回数字0
 return 0;
 str1++;        //如果不为\0,表示前面的字符相等,但是后面还没有比较,于是指针++
 str2++;
 }
 return *str1-*str2;        //当两指针解引用内容不同时,不进入循环,直接返回指针解引用内容的差值
}

根据上述图片描述可得到,当两指针解引用相同时,进入while循环。当两指针解引用内容相同并且都为 \0,说明两字符串相同,则函数返回0;当两指针解引用内容相同,但是不为 \0时,将两指针指向的位置后移,判断下一个位置解引用的内容;当两指针解引用内容不相等时,不再进入while循环,直接返回两指针解引用内容的差值(刚好满足C语言规定的strcmp函数返回值的规则)。

5.strncpy函数的使用

根据上面的图片解析可以得到该函数的作用是:将目标字符串的前num个字符复制到目标空间中。如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。该函数和strcpy函数极为类似,只是函数参数多了一个无符号整型,目的是控制复制字符串的字符个数。

6.strncat函数的使用

根据上方的图片可以得出,该函数的作用是将将source指向字符串的前num个字符追加到destination指向的字符串末尾,最后再追加一个 \0 。如果source指向的字符串的长度小于num时,便会将字符串中到 \0 的全部内容追加到destination指向的字符串末尾。该函数和strncat函数类似,只不过多了一个num参数,为了控制追加字符的个数。

下面举一个该函数使用的例子:

cpp 复制代码
#include <stdio.h>
#include <string.h>
int main ()
{
 char str1[20];        //创建了两个字符串,但是没有初始化
 char str2[20];
 strcpy (str1,"To be ");    //调用strcpy函数,将第二个参数复制给str1
 strcpy (str2,"or not to be");        //调用strcpy函数,将第二个参数复制给str1
 strncat (str1, str2, 6);        //调用strncat函数,在str1后面追加str2字符串的前6个字符
 printf("%s\n", str1);    
 return 0;
}

上方代码首先创建了两个没有进行初始化的字符串,然后调用strcpy函数,进行别样的初始化。(将"To be "复制给str1;将"or not to be"复制给str2),然后调用strncat函数,通过函数的参数可以得知,本代码的目的是将str2字符串前6个字符追加到str1字符串后。所以最后输出的内容为:To be or not。

7.strncmp函数的使用

比较str1和str2的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不相等,就提前结束,大的字符所在的字符串大于另外⼀个。如果num个字符都相等,则函数返回数字0;如果前面的字符串大,则函数返回大于0的数字;如果后面的字符串大,则函数返回小于0的数字。该函数和strcmp函数相似,只不过多了num参数,为了控制比较字符串的范围。

8.strstr函数的使用和模拟实现

(1)函数的使用

在C语言学习过程中,无论是数字还是字符串,我们都会遇到查找相关的问题。在一个给定的字符串查找另一个字符串。这种问题在学习过程中很常见,不错,strstr函数就是为了解决该问题而诞生的。下面我们进行该函数的学习。

通过上方的图片可以得出,函数的参数为char *类型的,用于接收两个字符串的首字符的地址;函数的返回值依然是char *类型的,用于返回字符串str2在字符串str1中第一次出现的位置。字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志。

下面是该函数的使用举例:

cpp 复制代码
#include <stdio.h>
#include <string.h>
int main ()
{
 char str[] ="This is a simple string";    //创建字符数组用于查找内容
 char * pch;    //定义指针变量,用于接收strstr函数的返回值
 pch = strstr (str,"simple");//调用strstr函数,在str找sample,并返回第一次在str数组找到位置处的指针
 strncpy (pch,"sample",6);    //调用strncpy函数将sample前6个字符复制到pch处
 printf("%s\n", str);    //打印字符数组现在的情况
 return 0;
} 

上述代码的具体解释:首先创建了字符数组和指针变量,字符数组是需要查找内容的字符串,而指针变量是为了接收strstr函数的返回值。在上面调用strstr函数时,参数表明此次调用的目的是:在str字符串数组中找到字符串"simple",并且返回第一次在str数组找到时的地址。然后pch就是str数组的simple string字符串的首字符的地址。最后调用strncpy函数,让sample字符串的前6个字符复制到pch空间中,就会覆盖掉simple。最后打印str数组结果为:"This is a sample string"。

(2)函数的模拟实现

cpp 复制代码
char * strstr (const char * str1, const char * str2)
{
 char *cp = (char *) str1;
 char *s1, *s2;
 if ( !*str2 )
     return((char *)str1);
 while (*cp)
 {
     s1 = cp;
     s2 = (char *) str2;
     while ( *s1 && *s2 && !(*s1-*s2) )
         s1++, s2++;
     if (!*s2)
         return(cp);
     cp++;
 }
 return(NULL);
}

上述代码的具体解释:当需要查找的字符串为空时,返回原字符串(对特殊情况的处理)。当需要查找的字符串不为空时,进入外层while循环,创建指针变量保存两字符串的首地址,方便后续计算,防止因为计算丢失字符串的首地址。当两指针不为空且两指针相等,则有可能匹配成功,两指针将指向的位置后移。一直到str2为空时,匹配成功,则返回第一次找到的指针cp。

上述图片的例子,当第一次s1等于s2时,s1和s2继续向后移动,但是此时s1不等于s2了。不进入内层while循环,cp指针后移,继续进行下一次匹配。这时候通过了匹配,就返回保存的第一次查找到的str2首地址cp。

9.strtok函数的使用

该函数的介绍:该函数的作用:在一个字符串中去掉包含另一个字符串内容的字符。函数第一个参数为已知的字符串,第二个函数参数为需要去掉的分隔符。函数的返回值为char *类型,返回指向当前子串的指针,若无可分割字串则返回NULL。

delimiters参数指向一个字符串,定义了用作分隔符的字符集合。第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记。strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。 strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 如果字符串中不存在更多的标记,则返回 NULL 指针。

cpp 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
 char arr[] = "192.168.6.111";    //创建了字符数组,准备去掉其中的分隔符
 char* sep = ".";        //创建了需要分割的字符串数组
 char* str = NULL;    
 for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
 {//通过for循环,分批次打印去掉分隔符的每个字符串
 printf("%s\n", str);
 }
 return 0;
}

上述代码通过for循环,打印去掉分隔符的每个字符串。当第一个参数变为NULL时。循环停止,打印完毕。

上述代码的输出结果为:

192

168

6

111

10.strerror函数的使用

在我们书写代码时,难免会碰到一些问题,编译器报错会为我们提示这些问题所在,但是有些问题,编译通过了,但是没有报出问题所在,这个时候我们就需要strerror函数来接收错误信息了。

strerror函数可以把得到参数部分错误码对应的错误信息的字符串地址。在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 头文件中。C语言程序启动的时候就会使用一个全局的变量errno,来记录程序的当前错误码,只不过程序启动的时候errno的值是0,表示没有错误。当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

下面我们尝试打印0-10错误码的错误信息:

cpp 复制代码
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{
 int i = 0;
 for (i = 0; i <= 10; i++)     //利用循环,打印错误码为0-10的错误信息
 printf("%s\n", strerror(i));
 return 0;
}

在Windows11和VS2022环境下输出的结果如下:

No error

Operation not permitted

No such file or directory

No such process

Interrupted function call

Input/output error

No such device or address

Arg list too long

Exec format error

Bad file descriptor

No child processes

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
 FILE * pFile;        //创建文件流,用于接收下方操作的返回值
 pFile = fopen ("unexist.ent","r");    //打开文件,进行只读操作
 if (pFile == NULL)    //当文件不存在时,打印下方错误信息
 printf ("Error opening file unexist.ent: %s\n", strerror(errno));
 return 0;
}

Error opening file unexist.ent: No such file or directory

也可以了解一下perror函数,perror函数相当于一次将上述代码中的第9行完成了,直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。所以可以理解perror=printf+strerror。

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
 FILE * pFile;
 pFile = fopen ("unexist.ent","r");
 if (pFile == NULL)
 perror("Error opening file unexist.ent");        //利用perror函数直接打印错误信息
 return 0;
}

Error opening file unexist.ent: No such file or directory

上面分别展示了perror函数和strerror函数的使用,可以看出区别在于:perror函数可以直接将错误信息打印在屏幕上;而strerror函数可以得到错误信息的地址,可以进行打印等其它一系列操作。

相关推荐
老虎062736 分钟前
JavaWeb前端02(JavaScript)
开发语言·前端·javascript
Python私教1 小时前
YggJS RLogin暗黑霓虹主题登录注册页面 版本:v0.1.1
开发语言·javascript·ecmascript
carver w1 小时前
MFC,C++,海康SDK,回调,轮询
开发语言·c++·mfc
王廷胡_白嫖帝2 小时前
Qt猜数字游戏项目开发教程 - 从零开始构建趣味小游戏
开发语言·qt·游戏
一个会的不多的人2 小时前
C# NX二次开发:操作按钮控件Button和标签控件Label详解
开发语言·c#
DokiDoki之父3 小时前
多线程—飞机大战排行榜功能(2.0版本)
android·java·开发语言
whatever who cares3 小时前
Java 中表示数据集的常用集合类
java·开发语言
xy_recording3 小时前
Day08 Go语言学习
开发语言·学习·golang
EndingCoder3 小时前
测试 Next.js 应用:工具与策略
开发语言·前端·javascript·log4j·测试·全栈·next.js