• 【C语言】字符函数和字符串函数(1)


    #国庆发生的那些事儿#

    大家好,我是苏貝,本篇博客带大家了解字符函数和字符串函数,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
    在这里插入图片描述


    1.本章重点

    • 求字符串长度
      strlen
    • 长度不受限制的字符串函数
      strcpy
      strcat
      strcmp
    • 长度受限制的字符串函数介绍
      strncpy
      strncat
      strncmp
    • 字符串查找
      strstr
      strtok
    • 错误信息报告
      strerror

    以上函数的头文件都为


    2. strlen

    2.1函数介绍

    size_t strlen ( const char * str );

    注意:
    1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
    2.参数指向的字符串必须要以 ‘\0’ 结束,否则函数返回值为随机值
    3.注意函数的返回值为size_t,是无符号的( 易错 )
    点击该链接继续了解strlen

    问:下面代码输出的结果是什么?

    int main()
    {
    	const char* str1 = "abcdef";
    	const char* str2 = "bbb";
    	if (strlen(str2) - strlen(str1) > 0)
    	{
    		printf("str2>str1\n");
    	}
    	else
    	{
    		printf("srt1>str2\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    答案:str2>str1
    这和你想的是否一样?其实这蕴含的知识点在注意的第三条,函数的返回值为size_t,是无符号的,所以strlen(str2) 和 strlen(str1)的返回值都是无符号的,无符号数-无符号数=无符号数>=0,又strlen(str2) =3不等于 strlen(str1)=6,所以结果>0,因此输出的是str2>str1

    2.2 模拟实现

    strlen的模拟实现在之前就有写过,如果感兴趣的话,可点击下方链接直接跳转
    自定义实现strlen函数的3种方法


    3. strcpy

    3.1 函数介绍

    char* strcpy(char * destination, const char * source )

    strcpy函数的作业是拷贝字符串,即将源字符串拷贝到目标空间中,拷贝时会将源字符串中的 ‘\0’ 一起拷贝。所以目标空间必须可以改变,且其大小>=源字符串(包括’\0’)。函数的参数有2个,第一个是目标空间的起始地址,第二个是源字符串的起始地址,类型都为char *,又因为strcpy函数不会改变源字符串的内容,所以char * source左边用const修饰。函数的返回值是目标空间的起始地址,所以为char *

    示例1:
    源字符串必须要有’\0’,否则会一直访问arr2后面的元素直至找到’\0’,可能会越界,造成程序运行异常,如下:

    int main()
    {
    	char arr1[20] = "xxxxxxxxxx";
    	char arr2[] = { 'a','b','c' };
    	strcpy(arr1, arr2);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    示例2:
    目标空间必须可变,否则会造成程序运行异常,"abcdefg"是常量字符串,不可更改,p存储的是字符串的首元素地址即a的地址

    int main()
    {
    	char* p = "abcdefg";
    	char arr2[] = "hello";
    	strcpy(p, arr2);
    	printf("%s", p);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    示例3:
    会将源字符串中的 ‘\0’ 拷贝到目标空间。

    int main()
    {
    	char arr1[20] = "xxxxxxxxx";
    	char arr2[] = "hello";
    	strcpy(arr1, arr2);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    总结:
    1.源字符串必须以 ‘\0’ 结束。
    2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
    3.目标空间必须足够大,以确保能存放源字符串。
    4.目标空间必须可变。

    3.2 模拟实现

    my_strcpy函数参数依旧是2个,返回值仍然是目标空间的初识地址,所以char* my_strcpy(char * str1, const char * str2 )。下面开始拷贝,用while循环,当 * str2为’\0’时退出循环,否则将str2指针指向的值赋给str1指向的值,str1++,str2++。当退出循环时,* str2指向的是’\0’,再将’\0’赋给 * str1。

    char* my_strcpy(char* str1, const char* str2)
    {
    	char* ret = str1;
    	while (*str2)
    	{
    		*str1 = *str2;
    		str1++;
    		str2++;
    	}
    	*str1 = '\0';
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    我们发现,上面代码完全可以简化成下述代码:while循环中,str1和str2的自增都是后置++,即先使用再自增,将str2指针指向的值赋给str1指向的值,再自增。等到 * str2==‘\0’时,也会将’\0’赋值给*str1,两指针再自增,退出循环

    char* my_strcpy(char* str1, const char* str2)
    {
    	char* ret = str1;
    	//断言,如果str1或str2中有空指针,会在运行时报错并会显示错误在第几行
    	//头文件为
    	assert(str1 && str2);
    	while (*str1++ = *str2++)
    		;
    	return ret;
    }
    
    int main()
    {
    	char arr1[20] = "xxxxxxxxxx";
    	char arr2[] = "hello";
    	my_strcpy(arr1, arr2);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.strcat

    4.1 函数介绍

    char * strcat ( char * destination, const char * source );

    追加函数,即将源字符串追加到目标字符串后。比如目标字符串为“hello”,源字符串为“world”,使用strcat函数后,目标字符串变为“helloworld”。函数有2个参数,第一个是目标字符串的起始地址,第二个是源字符串的起始地址,类型都为char *,又因为strcat函数不会改变源字符串的内容,所以char * source左边用const修饰。函数的返回值是目标空间的起始地址,所以为char *。源字符串的第一个字符将会覆盖目标字符串末尾的’\0’。

    和strcpy函数相似,因为都需要访问源字符串,所以源字符串必须以’\0’结束,以免越界。目标空间也必须足够大,能容纳下源字符串的内容。目标空间必须可修改。

    示例1:

    int main()
    {
    	char arr1[20] = "hello";
    	char arr2[] = "world";
    	strcat(arr1, arr2);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    示例2:
    自己追加自己,虽然这可行,但最好还是不要这样写

    int main()
    {
    	char arr1[20] = "hhh";
    	strcat(arr1, arr1);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    总结:
    1.源字符串必须以 ‘\0’ 结束,在拷贝时将’\0’也拷贝过去
    2.目标空间必须足够大,能容纳下源字符串的内容。
    3.目标空间必须可修改。
    4.目标空间中必须有’\0’,保证能找到目标空间的末尾
    5.字符串可以自己追加自己

    4.2 模拟实现

    在模拟实现之前,我们想到strcat函数是先找到目标空间的末尾即’\0’位置处,再将源字符串的字符逐个追加到目标空间中,包括源字符串的’\0’,追加的第一个字符会覆盖目标空间原本的’\0’。所以我们模拟实现的思路与它一致,先找到目标空间的末尾,只需用while循环,当 * str1=='\0’时退出循环,就找到了目标空间的末尾。第二步,追加,与strcpy相似,上面有详细介绍,这里就不再赘述了

    char* my_strcat(char* str1, const char* str2)
    {
    	char* ret = str1;
    	assert(str1 && str2);
    	//1.找到目标空间的'\0'
    	while (*str1)
    		str1++;
    	//2.追加
    	while (*str1++ = *str2++)
    		;
    	return ret;
    }
    
    int main()
    {
    	char arr1[20] = "hello";
    	char arr2[] = "world";
    	my_strcat(arr1, arr2);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    写完上面代码后,我们不禁想起来strcat函数还能自己追加自己,那我们写的这串代码可以吗?答案是不可以。刚开始时,str1和str2都指向首元素h
    在这里插入图片描述
    在找到目标空间的’\0’后,str1指向’\0’
    在这里插入图片描述
    开始追加,将 * str2赋值给 * str1,所以str1指向的内容变为h
    在这里插入图片描述
    继续追加,当str2指向下图所在位置时,该位置的元素已经从’\0’变为h,再将h赋值给 * str1,所以整个过程中 * str1都不会被赋值为’\0’,所以会一直循环下去,程序会崩溃
    在这里插入图片描述


    5. strcmp

    5.1 函数介绍

    int strcmp ( const char * str1, const char * str2 );

    strcmp是string compare的缩写,即字符串比较,不过不是比较长度,而是比较对应位置上字符的大小(ASCII码值)。strcmp函数的参数是两字符串的首元素地址。若 * str1> * str2,返回一个正数;若相等,返回0;若 * str1< * str2,返回一个负数。比如用strcmp函数比较字符串“abcdefg”和“abqa”,第一二个位置上字符的大小相等,比较第3个字符的大小,ASCII码值中c

    int main()
    {
    	char arr1[] = "abc";
    	char arr2[] = "abaa";
    	char arr3[] = "abc";
    	char arr4[] = "abq";
    
    	int ret1 = strcmp(arr1, arr2);
    	int ret2 = strcmp(arr1, arr3);
    	int ret3 = strcmp(arr1, arr4);
    
    	printf("%d %d %d", ret1, ret2, ret3);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    5.2 模拟实现

    strcmp函数的原理很简单,就是从两个字符串第一位开始比,若相同则比下一位,不同就返回值。来模拟实现,当 * str1和 * str2相等时,用while循环,相等则str1和str2都自增。如果进入循环时有一个的值为’\0’,那么另一个的值也为’\0’,说明两个字符串完全相等,返回0;若因为两个值不同退出循环,比较两值大小

    int my_strcmp(const char* str1, const char* str2)
    {
    	assert(str1 && str2);
    	while (*str1 == *str2)
    	{
    		if (*str1 == '\0')
    			return 0;
    		str1++;
    		str2++;
    	}
    	if (*str1 > *str2)
    		return 1;
    	else
    		return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    上面代码也可简化为:两值相减,若左>右,则返回正数;反正返回一个负数

    int my_strcmp(const char* str1, const char* str2)
    {
    	assert(str1 && str2);
    	while (*str1 == *str2)
    	{
    		if (*str1 == '\0')
    			return 0;
    		str1++;
    		str2++;
    	}
    	return *str1 - *str2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6.strncpy

    上面我们了解了strcpy,strcat,strcmp三个函数,它们是长度不受限制的字符串函数。下面我们再来了解一下长度受限制的3个字符串函数strncpy,strncat,strncmp

    6.1 函数介绍

    char * strncpy ( char * destination, const char * source, size_t num );
    strncpy和strcpy函数及其相似,只不过前者多了一个参数size_t num,表示只从源字符串中拷贝前面num个字符到目标空间中

    那么拷贝的时候是否会拷贝‘\0’呢?不会。如下图,拷贝的时候没有拷贝‘\0

    int main()
    {
    	char arr1[20] = "xxxxxxxxxxxxx";
    	char arr2[] = "hello";
    	strncpy(arr1, arr2, 3);
    	printf("%s", arr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    那如果num>源字符串的长度怎么办呢?拷贝完源字符串之后,在目标的后边追加0,直到num个

    int main()
    {
    	char arr1[20] = "xxxxxxxxxxxxx";
    	char arr2[] = "hello";
    	strncpy(arr1, arr2, 8);
    	printf("%s", arr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    6.2 模拟实现

    char* my_strncpy(char* str1, const char* str2, size_t num)
    {
    	char* ret = str1;
    	assert(str1 && str2);
    	int i = 0;
    	for (i = 0; i < num; i++)
    	{
    		*str1++ = *str2++;
    	}
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.strncat

    7.1 函数介绍

    char * strncat ( char * destination, const char * source, size_t num );
    它与strcat相比,也只是多了一个参数 size_t num,表示只从源字符串中追加前面num个字符和’\0’到目标空间中

    当num

    int main()
    {
    	char arr1[20] = "abc\0xxxxxxxx";
    	char arr2[] = "hello";
    	strncat(arr1, arr2, 3);
    	printf("%s", arr1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    当num>arr2的大小呢?多余的不再起作用

    在这里插入图片描述

    7.2 模拟实现

    char* my_strncat(char* str1, const char* str2, size_t num)
    {
    	char* ret = str1;
    	assert(str1 && str2);
    	//1.找到目标空间的末尾即'\0'位置
    	while (*str1)
    		str1++;
    	//2.追加
    	int i = 0;
    	for (i = 0; i < num; i++)
    	{
    		*str1++ = *str2++;
    	}
    	*str1 = '\0';
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    8.strncmp

    8.1 函数介绍

    int strncmp ( const char * str1, const char * str2, size_t num );
    它与strcmp相比,也只是多了一个参数 size_t num,表示只比较两字符串前num个字符的大小

    int main()
    {
    	char arr1[] = "abcdefg";
    	char arr2[] = "abcdqqq";
    	char arr3[] = "abbb";
    
    	int ret1 = strncmp(arr1, arr2, 5);
    	int ret2 = strncmp(arr1, arr2, 3);
    	int ret3 = strncmp(arr1, arr3, 3);
    
    	printf("%d %d %d", ret1, ret2, ret3);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    8.2 模拟实现

    int my_strncmp(char* str1, char* str2, size_t num)
    {
    	assert(str1 && str2);
    	int i = 0;
    	int flag = 0;
    	for (i = 0; i < num; i++)
    	{
    		if (*str1++ == *str2++)
    		{
    			flag++;
    			continue;
    		}
    		else
    			break;
    	}
    	if (flag == num)
    		return 0;
    	else
    		return *str1 - *str2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    9.strstr

    9.1 函数介绍

    const char * strstr ( const char *str1, const char * str2);
    若str2是str1的子串,返回str1中str2第一次出现的地址,如果str2不是str1的子串,就返回NULL

    int main()
    {
    	char arr1[] = "abbbcd";
    	char arr2[] = "bbc";
    	char arr3[] = "babc";
    
    	const char* p1 = strstr(arr1, arr2);
    	const char* p2 = strstr(arr1, arr3);
    
    	if (p1 == NULL)
    		printf("找不到\n");
    	else
    		printf("%s\n", p1);
    
    	if (p2 == NULL)
    		printf("找不到\n");
    	else
    		printf("%s\n", p2);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    9.2 模拟实现

    模拟实现的函数的形参为char* str1,t char* str2,因为指向的内容不变,所以用const修饰。返回值是指针,类型为char * 。如果我们想让str1,str2指向的位置不变,那我们定义指针变量cp用来记录开始匹配的位置,指针变量s1,s2遍历str1,str2指向的字符串。让cp=str1。先考虑特殊情况,当str指向的内容为0时,返回str1指向的字符串地址。

    使用while循环,当 * str1== 0时退出循环,让s1指向cp指向的位置,s2指向str2指向的位置。此时5个指针变量指向对象的图如下:
    在这里插入图片描述

    *s1!= * s2,cp++,s1== cp,s2==str2。

    在这里插入图片描述
    此时 * s1== * s2,s1++,s2++, 又* s1== * s2,s1++,s2++, * s1!= * s2,cp++,s1== cp,s2==str2。
    在这里插入图片描述

    此时 * s1== * s2,s1++,s2++, 又* s1== * s2,s1++,s2++,又 * s1== * s2,s1++,s2++,此时 * s2==0,表示arr2是arr1的子串,返回cp指针
    在这里插入图片描述

    变成代码:

    const char* my_strstr(const char* str1, const char* str2)
    {
    	assert(str1 && str2);
    	//str1,str2让其指向的位置不变
    	const char* cp = str1;//记录开始匹配的位置
    	const char* s1;//遍历str1指向的字符串
    	const char* s2;//遍历str2指向的字符串
    
    	if (*str2 == '\0')
    		return str1;
    
    	while (*cp)
    	{
    		s1 = cp;
    		s2 = str2;
    		while (*s1 && *s2 && *s1 == *s2)
    		{
    			s1++;
    			s2++;
    		}
    		if (*s2 == '\0')
    			return cp;
    		cp++;
    	}
    	return NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    这是一种暴力求解的方式,不够高效,可以了解一下KMP算法


    10.strtok

    char * strtok ( char * str, const char * sep );
    strtok是个字符串查找函数,它的功能是查询一个字符串中的被我们自己选定的分隔符(如@ . )。

    要点:
    1.sep参数是个字符串,定义了用作分隔符的字符集合
    2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
    3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记开头的指针。比如:要查找的字符串为“abc@aaa”,分隔符为“@”,调用strtok函数后,找到字符”@“并将其用’\0’覆盖,再返回a的地址。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
    4.strtok函数的第一个参数不为 NULL时 ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
    5.strtok函数的第一个参数为 NULL时 ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
    6.如果字符串中不存在更多的标记,则返回 NULL 指针

    示例1:

    int main()
    {
    	char arr[] = "666666@qq.com";
    	
    	char str[20] = { 0 };
    	strcpy(str, arr);
    
    	char* p = "@.";
    	char* s = strtok(str, p);//1
    	printf("%s\n", s);
    
    	s = strtok(NULL, p);//2
    	printf("%s\n", s); 
    	
    	s = strtok(NULL, p);//3
    	printf("%s\n", s);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    讲解:
    首先我们创建一个新的可修改的字符数组str,并将arr数组的内容拷贝到数组str中。因为strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。题目中将’@.‘作为分隔符,第一次调用strtok函数时,是将数组str的首元素地址作为第一个实参,意思是从该地址开始往后找,知道找到第一个’@‘或者’.‘,然后找到了字符6后面的字符’@‘,并将其用’\0’覆盖,返回开头的即第一个字符6的地址。打印时遇到‘\0’停止,所以只打印前面的666666;同时因为strtok函数的第一个参数不为 NULL ,strtok函数将保存第一个标记在字符串中的位置。
    再一次调用strtok函数,NULL作为第一个实参,函数将在从一个字符串中被保存的位置即原先是字符’@‘的位置开始,查找下一个标记,找到了字符q后面的字符’.‘,并将其用’\0’覆盖,返回开头的即第一个字符q的地址。打印时遇到 ‘\0’ 停止,所以只打印前面的qq;函数将保存这一个标记在字符串中的位置。
    又一次调用strtok函数,NULL作为第一个实参,函数将在从一个字符串中被保存的位置即原先是字符’.‘的位置开始,查找下一个标记,结果没有下一个标记,返回开始的地址即字符c的地址,打印时遇到 ‘\0’ 停止,所以只打印前面的com;

    在这里插入图片描述

    示例2:
    上面的示例中规定死了只能调用3次strtok函数,那么如果我想打印字符串”abdc@ssss.sss@999“中标记为”@.“时所有的在标记之前的字符该怎么办呢?其实很简单,用for循环即可

    int main()
    {
    	char arr[] = "666666@qq.com";
    	char str[20] = { 0 };
    	strcpy(str, arr);
    
    	char* p = "@.";
    	for (char* s = strtok(str, p); s != NULL; s = strtok(NULL, p))
    	{
    		printf("%s\n", s);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    11.strerror

    11.1 函数介绍

    char * strerror ( int errnum );
    strerror函数是将错误码翻译成错误信息,返回错误信息的字符串的初始地址。其实,不管是在设计库函数还是在正规的软件设计过程中,都会设计错误码。比如我们在上网时有时会看到404,这就是一个错误码,表示你访问的页面不存在。当我们在C语言中使用库函数,如果发生错误,就会将错误码放在全局变量errono中。错误码可能是0,1,2……

    示例1:
    让我们来了解一下0-10的错误码分别代表什么意思

    int main()
    {
    	int i = 0;
    	for (i = 0; i <= 10; i++)
    	{
    		//因为strerror函数返回的是错误信息的字符串的起始地址,所有用%s打印
    		printf("%d:%s\n", i, strerror(i));
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    示例2:
    当我们想用fopen函数打开一个文件夹中的一个文件,但该文件夹中没有该文件,那么指针变量pf为空指针。我们上面有讲到,在C语言中使用库函数时如果发生错误,就会将错误码放在全局变量errono中,将errno作为strerror函数的实参,返回值以%s打印可得到错误信息

    int main()
    {
    	FILE* pf = fopen("add.txt", "r");
    	if (pf == NULL)
    	{
    		printf("打开文件失败,原因:%s\n", strerror(errno));
    	}
    	else
    		printf("打开文件成功\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    11.2 perror

    是否只有借助strerror才能知道错误信息呢?其实不然,还有一个函数也可以,那就是perror函数,它的功能是直接打印错误码所对应的错误信息,你可以理解为perror==printf+strerror

    perror在打印时的规则:
    perror函数后面可以任意写文字、字符……,(如下面代码的”打开文件失败“)这些被称为自定义信息,perror会在打印完自定义信息后加冒号和一个空格,再打印错误信息(如:自定义信息: xxxxxxxxx)

    int main()
    {
    
    	FILE* pf = fopen("add.txt", "r");
    	if (pf == NULL)
    	{
    		perror("打开文件失败");
    	}
    	else
    		printf("打开文件成功\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述


    好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

  • 相关阅读:
    ch04图片
    MySQL笔记-07 常用函数
    文献解读——基于深度学习的病毒宿主预测
    如何注册Liberty大学并获取Perplexity Pro
    双向链表的实现
    【Web开发】C++实现Web服务器(libevent,libcurl)
    Docker基础:Docker 常用命令梳理
    02 Truffle TutorialToken 示例
    Java类的定义及定义类时可用的关键字
    基于单片机的自动循迹小车(论文+源码)
  • 原文地址:https://blog.csdn.net/qq_75000174/article/details/133579222