C语言----字符函数和字符串函数

在编程的过程中,我们要经常处理字符和字符串,为了方便操作字符和字符串,c语言标准库中提供的一系列库函数,接下来我们就开始学习与认识他们

1.字符分类函数

c语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的

这些函数的使用需要包含一个头文件:ctype.h

用islower举例

格式:int islower (int c)

为什么后面的是int c--用整型接受的,因为传过来的是字符或者对应的ASCII值

那么我们就用整型接受

返回值也是int

如果这个字符是小写字母的话,那么返回值就是一个非0数字

如果这个字符是一个大写字符的话,那么返回值就是0

总之:如果括号内的不是小写字母,那么这个函数就会返回一个0

是小写字母就返回一个非0数字

int main()
{int ret1 = islower('b');//2printf("%d\n", ret1);int ret2 = islower('A');//0printf("%d\n", ret2);int ret3 = islower('0');//字符0不是字母printf("%d\n", ret3);return 0;
}
int main()
{int ret1 = isdigit('A');//不是数字字符就返回0printf("%d\n", ret1);int ret2 = isxdigit('A');//A是16进制的字符--返回的就是非0值printf("%d\n", ret2);return 0;
}
//写一个代码,将字符串中的小写字母转换成大写字母,其他字符不变
int main()
{char arr[] = "I am a student";//末尾隐藏\0//需要遍历字符串--通过下标进行访问int i = 0;while (arr[i] != '\0')//不等于'\0'就一直遍历数组,直到遇到\0就停止遍历数组{//判断这个数组内的字符是不是小写字母if (islower(arr[i]))//如果不是小写字母,返回值就是0,是小写字母返回值就是非0数字,//这个函数是用来判断输入的字符是不是小写字母{//小写字母转大写字母的方法://小写字母的ASCII-32=对应放入大写字母ASCIIarr[i] = arr[i] - 32;}i++;//没有遇到'\0'就i++}printf("%s", arr);return 0;
}//小写字母转大写字母出了这个toupper函数,还可以直接通过小写字母的ASCII-32就可以进行转换了//那么我们对上面的问题进行改造一下
int main()
{char arr[] = "I am a student";//末尾隐藏\0//需要遍历字符串--通过下标进行访问int i = 0;while (arr[i] != '\0')//不等于'\0'就一直遍历数组,直到遇到\0就停止遍历数组{//判断这个数组内的字符是不是小写字母if (islower(arr[i]))//如果不是小写字母,返回值就是0,是小写字母返回值就是非0数字,//这个函数是用来判断输入的字符是不是小写字母{//小写字母转大写字母的方法:arr[i] = toupper(arr[i]);//小写字母通过toupper这个函数转换为大写字母了}i++;//没有遇到'\0'就i++}printf("%s", arr);return 0;
}
//对于这个循环还有一种判断是不是小写字母的方法
//if(arr[i]>='a'&&arr[i]<='z')
//在这个区间内的就都是小写字母了

这些字符分类函数主要是进行判断

2.字符转换函数

c语言提供两个字符转换函数

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

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

//int main()
//{
//    char ch = toupper('a');
//    printf("%c\n", ch);//打印出来的就是A,大写的A
//
//    //如果传进来的大写字母,那么输出的还是大写字母,不做判断
//    ch = tolower('A');
//    printf("%c\n", ch);//将大写字母转换为小写字母
//
//
//    return 0;
//}
//小写字母转大写字母出了这个toupper函数,还可以直接通过小写字母的ASCII-32就可以进行转换了//那么我们对上面的问题进行改造一下
int main()
{char arr[] = "I am a student";//末尾隐藏\0//需要遍历字符串--通过下标进行访问int i = 0;while (arr[i] != '\0')//不等于'\0'就一直遍历数组,直到遇到\0就停止遍历数组{//判断这个数组内的字符是不是小写字母if (islower(arr[i]))//如果不是小写字母,返回值就是0,是小写字母返回值就是非0数字,//这个函数是用来判断输入的字符是不是小写字母{//小写字母转大写字母的方法:arr[i] = toupper(arr[i]);//小写字母通过toupper这个函数转换为大写字母了}i++;//没有遇到'\0'就i++}printf("%s", arr);return 0;
}
//对于这个循环还有一种判断是不是小写字母的方法
//if(arr[i]>='a'&&arr[i]<='z')
//在这个区间内的就都是小写字母了

3.strlen的使用和模拟实现

strlen格式:size_t strlen(const char * str);

统计的是\0之前的个数

strlen的返回值是size_t类型的

//
//int main()
//{
//    char arr1[] = "abcdef";
//    size_t len=strlen(arr1);//输出的数据是6
//    printf("%zd\n", len);
//
//
//    char arr2[] = { 'a','b','c','d','e','f' };//这里面是没有\0的
//    size_t len1 = strlen(arr2);
//    printf("%zd\n", len1);//输出数据是17
//    return 0;
//}
//注意函数的返回值是sizeof_t,是无符号的int main()
{if (strlen("abc") - strlen("abcdef") > 0)
//另一种写法:if(strlen("abc")>strlen("abcdef")){// size_t类型      size_t类型printf(">\n");}else{printf("<=\n");}return 0;
}
//输出的结果是>,为什么呢?
//当两个无符号整型进行计算的时候,算出来的结果还是无符号整型的结果
//如果想得到-3的话,那么我们需要将strlen("abc")和strlen("abcdef")强制类型转换为int 类型的数据

strlen的,模拟实现的三种方法

1.计数器的方法

2.指针~指针

size_t my_strlen(const char*str)//返回类型是sizeof_t,因为传过来的是字符串首元素的地址,那么我们用一个字符指针进行接收
{//前面加上const防止被修改//利用传过来的首元素的地址,我们遍历数组,统计\0之前的元素个数//只要不是\0就统计一个数字int count = 0;//因为str是指针变量,为了防止str是空指针,我们要进行断言一下assert(str != NULL);//如果str为空指针就报错while (*str != '\0'){count++;str++;//使指针++,向后走一步}return count;}
int main()
{char arr[] = "abcdef";size_t len = my_strlen(arr);//自己创建一个函数来实现strlen函数//传过去一个数组名,字符串首元素的地址printf("%zd\n", len);return 0;
}
//第二种方法:指针-指针
//两个指针相减就能得到两个指针之间的元素个数了
size_t my_strlen(const char* str)
{char* start = str;assert(str != NULL);while (*str != '\0'){str++;//走到'\0'前面就停止了,那么到最后str的值是最后一个元素的地址}return str - start;//因为一开始将第一个元素的地址赋值给start了,那么现在指针相减,得到的就是两个指针之间的元素的个数了}int main()
{char arr[] = "abcdef";size_t len = my_strlen(arr);//自己创建一个函数来实现strlen函数//传过去一个数组名,字符串首元素的地址printf("%zd\n", len);return 0;
}
//这种写法可以不创建临时变量//使用递归来实现
size_t my_strlen(const char* str)
{if (*str != '\0'){ return 1 + my_strlen(str + 1);}else{return 0;}
}int main()
{char arr[] = "abcdef";size_t len = my_strlen(arr);//自己创建一个函数来实现strlen函数//传过去一个数组名,字符串首元素的地址printf("%zd\n", len);return 0;
}

4.strcpy的使用和模拟实现

功能:拷贝字符串

strcpy---cpoy string

strcpy在拷贝的过程中会将arr1里面的内容包括\0拷贝到arr2里面去

int main()
{char arr1[] = "hello world";char arr2[20] = { 0 };//现在想把arr1里面的hello world放到arr2里面去//我们可以用strcpy来实现strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}

注意注意:

被拷贝的字符串一定要包含'\0',保证strcpy遇到\0就能停止拷贝

1.源头的字符串中必须包含\0,没有\0,strcpy是不能结束的

2.目标空间必须足够大,以确保能存放原字符串

3.目标空间必须是可以修改的

int main()
{char arr1[] = "hello world";char* p = "xxxxxxxxxxxxxx";//常量字符串--不能修改strcpy(p, arr1);//会报错的return 0;
}
//模拟实现拷贝
char*my_strcpy(char*dest,const char*src)//传过来的是首元素的地址,返回值是目标空间的起始地址,所以就是char*
{//*dest指向的是arr2第// 一个元素,*src指向的是arr1第一个元素//保证这两个指针不为空指针/*assert(src != NULL);assert(dest != NULL);*///另一种写法:assert(dest && src);//如果dest为空指针,那么括号内就为0,就是假的,就会报错char* ret = dest;//将dest存起来while (*src != '\0'){*dest=*src;//进行加加操作,换下一个字符和下一个位置进行交换src++;dest++;}//当这个循环结束的时候,\0还没有被拷贝进去//最后的时候,src已经++成为\0了,那么现在再次赋值就能将\0拷贝进去了*dest =* src;//这里处理的就是\0return ret;//直接返回目标空间的起始地址}
int main()
{char arr1[] = "abcdef";//末尾隐藏\0char arr2[20] = { 0 };//1.直接打印arr2my_strcpy(arr2, arr1);printf("%s\n", arr2);//2.接收返回值char* p = my_strcpy(arr2, arr1);printf("%s\n", p);//直接将返回值放到打印里面也可以printf("%s\n", my_strcpy(arr2, arr1));return 0;
}//这个函数返回的是char*,为的是实现链式访问//strcpy函数返回的是字符串拷贝成功过后,目标空间的起始地址,
//返回值就是arr2的首元素的地址//总结:
//将arr1拷贝到arr2后,我们可以通过三种方法直接打印arr2
//一种就是直接打印arr2
//还有一种就是根据这个拷贝函数的返回值进行打印
//返回值是一个地址,在函数的一开始我们就将目标函数赋值给另一个临时指针,那么这个临时指针就指向了arr2
//在拷贝过后,我们直接将这个临时指针返回,所以在函数的开头我们用char*
//在返回了临时指针后,我们在主函数就用再创建一个临时指针变量进行返回值的接受,
//因为这个临时指针变量指向的是arr2的其实元素,那么我们就可以用这个临时指针变量直接打印arr2
//有了字符串起始元素的地址,我们就能打印这个字符串了
//对函数部分进行改进,
//思考:能不能将拷贝\0和前面的字符串放在一起呢?char*my_strcpy(char*dest,const char*src)
{assert(dest && src);char* ret = dest;while (*dest++ = *src++)//因为这里是后置++,所以先带进去数据进行解引用,再进行++{//arr1里面的字符通过*dest++ = *src++这个代码一个个拷贝到arr2里面去了//在最后,*src是\0拷贝过去了,然后因为while循环里面是\0,所以循环停止了// 但是\0拷贝到dest里面了 ;}//这个循环拷贝过去之后判断表达式的值//因为是后置++,所以延后产生return ret;}int main()
{char arr1[] = "abcdef";char arr2[20] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);char* p = my_strcpy(arr2, arr1);printf("%s\n", p);printf("%s\n", my_strcpy(arr2, arr1));return 0;
}

5.strcat的使用和模拟实现

原字符串必须有\0结尾

目标字符串也得有\0,否则没办法知道从哪里开始

目标空间必须足够大,能容纳下字符串的内容

目标空间是可以进行修改的,而不是常量不能进行修改

int main()
{char arr1[20] = "hello ";char arr2[] = "world";//如何将arr2里面的字符串追加在arr1后面呢?strcat(arr1, arr2);//字符串追加printf("%s\n", arr1);return 0;
}//这个函数是如何实现追加呢?
//先找到目标函数的末尾\0的位置
//再将原字符串拷贝过来//要求目标字符串末尾有\0,因为后面要将原字符串拷贝过去,所以原字符串也要有\0
//要返回目标空间的起始地址
//目标空间是可修改的,但是源头需要进行限制,不能被修改
char* my_strcat(char* dest,const char* src)//返回类型为char*类型的
//dest指向的是arr1的首元素的地址
//src指向的是arr2首元素的地址
{char* ret = dest;//将起始位置存起来assert(dest && src);//进行断言,防止空指针//1.找目标空间的\0while (*dest != '\0'){dest++;}//while循环找到\0就停下来//2.拷贝----我们在字符串追加的时候,我们要将目标字符串末尾的\0覆盖掉while (*dest++ = *src++)//这个代码是进行字符串间的拷贝的,因为上面已经找到\0了,已经停止循环了,并且dest指向了arr1末尾的\0{;//写个分号就行了,循环得有一个循环语句}return ret;//直接返回arr1的起始地址
}
int main()
{char arr1[20] = "hello ";char arr2[] = "world";//如何将arr2里面的字符串追加在arr1后面呢?my_strcat(arr1, arr2);//字符串追加printf("%s\n", arr1);return 0;
}//这个函数是如何实现追加呢?
//先找到目标函数的末尾\0的位置
//再将原字符串拷贝过来//要求目标字符串末尾有\0,因为后面要将原字符串拷贝过去,所以原字符串也要有\0//总结: 我们应该先找到目标字符串末尾\0的位置,这样我们才好追加,
//切记:追加的时候我们要将目标字符串末尾的\0覆盖掉//在这个追加函数我们用了两个循环,第一个循环是找到\0,第二个循环是将原字符串拷贝到目标字符串的后面去

我们是不能对一个数组自己进行追加的

6.strcmp的使用和模拟实现

strcmp是用来比较两个字符串的

返回值是int

用返回值来比较这两个字符串大小

比较的是对应位置上的字符,如果对应位置字符相等就比较下一对字符

比较的不是字符串的长度,而是对应位置上字符的大小

如果两个字符串相等,返回值就是0

如果前面的字符串大于后面的字符串,那么就会返回一个大于0的数字

如果是后面的字符串大于前面的字符,前面的字符小,就返回一个小于 0的数字

int main()
{char arr1[] = "abcdef";char arr2[] = "abq";int ret=strcmp(arr1, arr2);//printf("%d\n", ret);//输出的结果是-1,就说明arr1<arr2if (ret == 1)//仅仅在vs平台可以写返回值为1,其他的平台就不知道返回值是多少了{printf(">" );}else{printf("<=");}return 0;
}
//
//int main()
//{
//    char arr1[] = "abcdef";
//    char arr2[] = "abq";
//    int ret=strcmp(arr1, arr2);
//    //printf("%d\n", ret);//输出的结果是-1,就说明arr1<arr2
//    if (ret == 1)//仅仅在vs平台可以写返回值为1,其他的平台就不知道返回值是多少了
//    {
//        printf(">" );
//    }
//    else
//    {
//        printf("<=");
//    }
//    return 0;
//}//int my_strcmp(const char*str1,const char*str2)//返回值是Int,并且加上const进行限制
//{
//    //我们一对一对字符进行比较
//    assert(str1 && str2);
//    while (*str1 == *str2)
//    {
//        if (*str1 == '\0')//如果str1在上一轮循环++到\0之后,就说明这两个字符串已经完全相等了
//        {
//            return 0;//两个字符串完全相等
//        }
//        str1++;
//        str2++;
//    }//两个字符相等我们就找下一对字符进行比较
//    if (*str1 > *str2)
//    {
//        return 1;
//    }
//    else//*str1 < *str2
//    {
//        return -1;
//    }
//}//另一种写法
int my_strcmp(const char* str1, const char* str2)//返回值是Int,并且加上const进行限制
{//我们一对一对字符进行比较assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')//如果str1在上一轮循环++到\0之后,就说明这两个字符串已经完全相等了{return 0;//两个字符串完全相等}str1++;str2++;}//两个字符相等我们就找下一对字符进行比较return (*str1 - *str2);//直接返回他们相减的值}
int main()
{char arr1[] = "abcdef";char arr2[] = "abcdef";int ret=my_strcmp(arr1, arr2);printf("%d\n", ret);return 0;
}

7.strncpy函数的使用

int main()
{char arr1[20] = "abcdef";char arr2[20] = { 0 };strncpy(arr2, arr1, 3);printf("%s", arr2);//打印的结果就是abc,只选择arr1里面的前三位字符进行拷贝return 0;
}int main()
{char arr1[20] = "abcdef";char arr2[20] = "xxxxxxxx";strncpy(arr1, arr2, 3);printf("%s", arr1);//输出xxxdefreturn 0;
}

拷贝n个字符从原字符串到目标空间

如果原字符串的长度小于n的话,则拷贝完原字符串之后,在目标的后边追加0,直到凑齐n个

8.strncat函数的使用

可以用来给自己追加

在原有的基础上,可以选择性的追加n个字符

9.strncmp函数的使用

int main()
{char arr1[20] = "abcdef";char arr2[20] = "abc";int ret=strncmp(arr1, arr2, 3);//比较三个字符printf("%d", ret);//现在返回值就是0return 0;
}

指定几个字符进行比较久进行几个字符比较

总之来说还是比较方便的

10.strstr的使用和模拟实现

在一个字符串里面找子字符串,在一个字符串里面找另外一个字符串是否出现

如果要找的字符串出现一次以上,那么我们就返回第一次出现的位置

在str1中找str2

如果在str1中没有找到str2的话,就会返回一个空指针NULL

int main()
{char arr[] = "abcdefabcdef";char* p = "efab";//定义了一个指向字符串常量"efab"的指针pchar* ret=strstr(arr, p);//返回的是e的地址//printf("%s", ret);//打印结果是efabcdefif (ret == NULL){printf("不存在\n");}else{printf("%s\n", ret);}return 0;
}
char* my_strstr(const char* str1, const char* str2)//我们只是希望在str1中查找str2,并不希望将这两个字符串修改了,所以要加上const
{assert(str1 && str2);//保证两个指针不是空指针const char* s1 = NULL;//加上const限制住const char* s2 = NULL;const char* cur = str1;//一开始指向的是str1的起始位置的//*cur != '\0'简化如下:当*cur是\0我们就进不去循环了if (*str2 == '\0')//特殊情况,假如str2是空指针,那么我们直接返回str1{return str1;}while (*cur)//如果等于'\0'的话就说明这个字符串已经找完了{//只要*cur不是\0就能一直寻找要找的字符串//分别将起始位置赋值给s1和s2s1 = cur;s2 = str2; //*s1!='\0'&& *s2!= '\0'简化如下,效果还是一样的//就是反正你*s1和*s2是\0这个循环就进不去,直接跳出来了while(*s1&& *s2&& * s1 == *s2)//判断两个指针指向位置的字符是否相等{//如果这一对字符相等的情况下我们就往后走判断下一对字符s1++;s2++;}if (*s2 == '\0')//说明我们已经在str1里面已经找完了字符串{return cur;//那么我们就直接返回str1中我们记录的cur的位置}cur++;//如果*s1!=*s2的话,就cur++换下一个字符,就跳出这个while循环了//再次循环就s1又被重新赋值了,但是s2仍然是被srt2赋值,//就是相等与我们在仅仅只是将str1的出发点进行了更换,但是str2的还没变//直到能在str1里面找到str2了,就是str2语言\0了,就说明已经在str1里面找到str2了//如果*s1不为\0,但是*s2已经是\0了,那么这个while循环我们就跳出来了}return NULL;//如果cur为\0就是我们已经不可能在str1中找到str2了,那我们直接返回空指针}
int main()
{char arr[] = "abcdefabcdef";char* p = "bbs";const char* ret=my_strstr(arr, p);if (ret == NULL)//根据返回值进行判断str1中是否存在str2{printf("不存在\n");}else{printf("%s\n", ret);}return 0;
}
//如果在str1里面提前遇到了\0就说明这个字符串已经找完了还没遇到要找的字符串
//但是str2提前遇到\0的话,就说明我们已经找到了要找的字符串了//总结:
/*
我们在这个模拟函数中,我们最重要的就是创建了一个cur来不断重新定义来找的位置假如在第一次寻找的过程中,我们没找到,那么cur就进行++操作,然后s1=str2重新赋值,
就是我们将要找的字符串的指针重新定义在首元素,但是cur一直在往后走,
直到s2走到\0,就是说明我们已经在str1内找到str2了那么如果找到了的话,我们就将cur现在的地址return 回去,就是说明我们在str1中cur处可以找到str2了*/

我们当前写的strstr函数的实现不是最优的算法

KMP算法---字符串中找字符串---效率更高,但是实现更难

11.strtok函数的使用

charstrtok(charstr,const char *sep)

1.sep参数指向一个字符串,定义了用作分隔符的字符集合

2.第一个参数指定了一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记

3.strtok函数找到str中的下一个标记,并将用\0结尾,返回一个指向这个标记的指针。(注意:strtok会改变被操作符的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改)

4.strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,就是第一个分隔符,strtok函数将保存他在字符串中的位置

5.strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置,查找下一个标记。

6.如果字符串中不存在更多的标记,则返回NULL指针,就是说明这个字符串已经被找完了,再没有任何的分隔符了,已经尽数转化为\0了

//int main()
//{
//    char arr[] = "abdjskgb@vsfkv.net";
//    char buf[256] = { 0 };
//    strcpy(buf, arr);//把arr数据拷贝到buf内//abdjskgb\0vsfkv\0net
//    char sep[] = "@.";//char*sep= "@."
//    char* ret=strtok(buf, sep);
//    printf("%s\n", ret);//输出结果就是abdjskgb
//
//    char* ret1 = strtok(NULL, sep);
//    printf("%s\n", ret1);//输出结果就是vsfkv
//
//
//    char* ret2 = strtok(NULL, sep);
//    printf("%s\n", ret2);//输出结果是net
//
//
//    return 0;
//}
//strtok的返回值是buf的第一个标记的指针
//当这个函数返回的是一个空指针的时候,就说明这个函数已经找完了//上面这种写法必然是错误的,我们必须先知道提供的字符串需要切割几段int main()
{char arr[] = "abdjskgb@vsfkv.net";char buf[256] = { 0 };strcpy(buf, arr);//把arr数据拷贝到buf内//abdjskgb\0vsfkv\0netchar *sep = "@.";//分割符char* ret = NULL;//上个代码的buf只在strtok里面进行一次,后面都是空指针//我们利用了for循环的特点,初始化只执行一次//就是说只有第一次传的是buf,后面传的都是NULLfor (ret = strtok(buf, sep); ret != NULL;ret=strtok(NULL,sep)){printf("%s\n", ret);}//只要ret不等于NULL这个循环就一直执行//strtok(buf, sep)的返回值是第一个切割符前面的字符串的地址,并将其赋值给ret,//每次循环都会运行ret=strtok(NULL,sep),将新获得的返回值赋值给ret,然后每次循环就从新位置开始return 0;
}//总结:我们定义一个数组arr,里面带有分隔符
// 再定义一个空数组,将带有分隔符的数组拷贝过来,在后面的过程,我们都是用这个拷贝的数组
// 
// char* ret = NULL;:定义了一个指向分割后子字符串的指针。
//char *sep = "@."; 定义了分隔符字符串,包含 @ 和 .。/*针对这个循环进行更加详细的解释ret = strtok(buf, sep)是初始化部分,
在循环开始之前,strtok被调用,使用buf和sep来分割字符串,并返回第一个子字符串的指针
这个指针被赋值给ret,作为循环的起始点循环条件:ret != NULL   这表示只要strtok返回的指针不是NULL,就能继续执行循环体,
因为strtok在没有更多子字符串可供分割时会返回NULL,所以在没有更多子字符串可供分割时会结束迭代部分:ret = strtok(NULL, sep)   
在每次循环迭代时,strtok(NULL, sep)被调用,告知strtok继续从上一次的位置继续分割字符串
并返回下一个子字符串的指针,这个指针被赋值给ret,作为下一次循环的起始点这个循环的条件保证了每次循环迭代都能够正确地从输入字符串中分割出一个子字符串,
并且在没有更多子字符串可供分割时结束循环。*///strtok可以把一个字符串切成一段一段的,每切一次就将起始地址返回去//每次就直接将分隔符前面的字符串切割下来,并将切割符变为\0,就是\0后面的字符将不进行访问//函数会找到第一个分隔符,并记住位置,下次找就从这个位置开始找

12.strerror函数的使用

strerror可以将错误对应的错误信息字符的地址返回

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会将对应的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

//int main()
//{
//    for (int i = 0; i < 10; i++)
//    {
//        printf("%d:%s\n", i,strerror(i));
//    }
//    return 0;
//}//0:No error
//1:Operation not permitted
//2 : No such file or directory
//3 : No such process
//4 : Interrupted function call
//5 : Input / output error
//6 : No such device or address
//7 : Arg list too long
//8 : Exec format error
//9 : Bad file descriptorint main()
{//打开文件FILE*pf=fopen("date.txt", "r");//r---读,以读文件的形式打开文件,如果文件不存在就是打开失败//打开失败就返回一个空指针if (pf == NULL)//打开失败{printf("打开文件失败,原因是%s",strerror(errno));//为了使用errno我们要包含头文件#include <errno.h>return 1;//打开失败我们就直接结束进程}else{printf("打开成功\n");fclose(pf);//关闭文件pf = NULL;}return 0;
}
//打开文件失败,原因是No such file or directory

strerror---将错误码对应的错误信息的字符串的起始地址返回

int main()
{//打开文件FILE*pf=fopen("date.txt", "r");//r---读,以读文件的形式打开文件,如果文件不存在就是打开失败//打开失败就返回一个空指针if (pf == NULL)//打开失败{printf("打开文件失败,原因是:%s\n",strerror(errno));//为了使用errno我们要包含头文件#include <errno.h>perror("打开文件失败,原因是");return 1;//打开失败我们就直接结束进程}else{printf("打开成功

perror--将errno中错误信息直接打印出来

perror函数线打印str指向的字符串,再打印冒号,再打印空格,再打印错误码对应的信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/26511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「漏洞复现」I Doc View 在线文档预览 qJvqhFt.json 任意文件读取漏洞(XVE-2024-2115)

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

解决electron设置透明背景后,引入element-plus样式问题

首先给当前窗口设置自定义窗口以及背景色。 const mainWindow new BrowserWindow({width: 900,height: 670,show: false,autoHideMenuBar: true,...(process.platform linux ? { icon } : {}),webPreferences: {preload: join(__dirname, ../preload/index.js),sandbox: fal…

【 EI会议 | 西南大学主办 | 往届均已实现检索】第三届神经形态计算国际会议(ICNC 2024)

第三届神经形态计算国际会议&#xff08;ICNC 2024) 2024 3rd International Conference on Neuromorphic Computing (ICNC 2024) 一、重要信息 大会官网&#xff1a;www.ic-nc.org&#xff08;点击投稿/参会/了解会议详情&#xff09; 会议时间&#xff1a;2024年12月13-15…

Elasticsearch:智能 RAG,获取周围分块

作者&#xff1a;来自 Elastic Sunile Manjee 在检索增强生成 (RAG) 领域&#xff0c;一个持续存在的挑战是找到输入大型语言模型 (LLM) 的最佳数据量。数据太少会导致响应不足或不准确&#xff0c;而数据太多会导致答案模糊。这种微妙的平衡启发我开发了一个专注于智能分块和利…

社区论坛圈子软件APP ,提供互动交流、知识共享和专业交流的社交平台。

社区论坛圈子软件APP的开发能够为用户提供一个互动交流的社交平台&#xff0c;促进用户之间的知识分享、交流和互助。本文将突出社区论坛圈子软件APP的前景、作用和特点&#xff0c;以帮助您了解该系统的潜力和优势。 一、前景&#xff1a; 知识共享&#xff1a;社区论坛圈子软…

力扣每日一题-419

题目 给你一个大小为 m x n 的矩阵 board 表示甲板&#xff0c;其中&#xff0c;每个单元格可以是一艘战舰 X 或者是一个空位 . &#xff0c;返回在甲板 board 上放置的 战舰 的数量。 战舰 只能水平或者垂直放置在 board 上。换句话说&#xff0c;战舰只能按 1 x k&#xff…

一带一路情 相逢《中国缘》-诗琳探访湘西墨戎苗寨交流有感

一带一路情 相逢《中国缘》 诗琳探访湘西墨戎苗寨交流有感 5月21日至25日&#xff0c;《中国缘》栏目组组织的走进湘西苗疆边陲的文化交流活动&#xff0c;在群山环抱、绿树成荫、人文厚重的湘西古丈墨戎苗寨美丽绽放。这场以民间角度推演的中国和中亚人民的文化交流活动&am…

有一个主域名跟多个二级子域名时该怎么申请SSL证书?

当您拥有主域名以及多个子域名时&#xff0c;选择合适的SSL证书类型对于确保网站的安全性至关重要。以下是三种SSL证书类型的简要介绍&#xff1a; 单域名SSL证书&#xff1a; 功能&#xff1a;只能绑定单个域名&#xff0c;无论是主域名还是子域名。 适用场景&#xff1a;仅…

常用 磁力搜索 磁力链接 工具使用教程

一、什么是磁力链接&#xff1f; 磁力链接&#xff08;Magnet link&#xff09;是一种链接&#xff0c;它利用磁力编码来识别和获取文件的信息。它通常由一串以“magnet:?xturn:btih:”开头的字符串组成&#xff0c;后面跟着文件的哈希值。 二、如何使用磁力链接&#xff1f…

一篇文章看懂Redission原理

文章目录 ☃️可重入锁原理☃️锁重试和WatchDog机制☃️MutiLock原理 上一篇文章讲解了 Rediision的使用 ,这篇文章讲解其原理 ☃️可重入锁原理 在Lock锁中&#xff0c;他是借助于底层的一个voaltile的一个state变量来记录重入的状态的&#xff0c;比如当前没有人持有这把锁…

探索 cartesian_product:更深入理解范围库

理解范围库中的cartesian_product适配器 一、简介二、cartesian_product 适配器的动机三、将行为封装到算法中四、算法的局限性五、总结 一、简介 view::cartesian_product 适配器是range-v3 库一个新的组件。本文主要理解这个组件的功能以及它背后的设计理念&#xff0c;可以…

罗森伯格1800M 2000M 2400M 900M无源互调分析仪

在无线通信领域&#xff0c;频段是宝贵的资源&#xff0c;不同的通信系统通常会采用不同的频段以满足其传输需求。随着技术的发展&#xff0c;越来越多的通信系统被部署在各种频段上。为了准确、高效地测试和调试这些 信系统&#xff0c;各种测试设备也应运而生。源互调分析仪便…

Llama-3安装方法及应用

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Stable Diffusion直接生成IP三视图,一天设计100个?

AI都能直接生成IP形象三视图了&#xff01; SD生成一个动物Q版IP三视图模型。标准的三视图&#xff0c;并且极富设计感&#xff0c;IP设计师的好帮手&#xff0c;用来辅助创意&#xff0c;建模参考。这个模型主要是动物类&#xff0c;一般不需堆叠复杂的质量词&#xff0c;直接…

资源付费系统小程序APP公众号h5源码

&#x1f510; 揭秘“资源付费系统”&#xff1a;知识、技能与价值的交汇点 &#x1f48e; &#x1f31f; 引言&#xff1a;为何资源需要付费&#xff1f; 在数字化时代&#xff0c;我们周围充斥着大量的信息。但并非所有信息都具有同等的价值。其中&#xff0c;那些经过精心…

入门 Axure RP 9 | 原型设计基础教程

选择正确的原型设计工具并非易事&#xff0c;Axure RP 9能够快速完成原型设计。原型设计是一种经过时间考验的方法&#xff0c;可以将你的设计快速放置在用户的设备并交到他们手中。替代Axure RP 9的原型设计工具即时设计是一个完全集成的协同设计工具&#xff0c;无需使用不同…

Vue3中使用深度选择器不起作用

问题&#xff1a; 想要给这个菜单设置高度100%&#xff0c;使用深度样式选择器无效 这样写无效 但是如下在控制台写是有效果的 解决&#xff1a; 参考 解决方法是给这个组件增加一个根元素&#xff0c;然后再使用深度选择器

【C语言】指针的指针使用场景

前言 C 语言中&#xff0c;比较难理解的就是指针&#xff0c;完全搞懂了指针&#xff0c;那么C语言算是入了门。 指针中比较难理解的概念&#xff1a; 指针的指针。 指针的指针&#xff0c;刚开始看到这个概念&#xff0c;感觉头疼。但是我们在程序里面应用一次就能搞懂。 本文…

如何合并pdf文件到一个pdf

在现代办公和学习中&#xff0c;PDF格式的文件因其跨平台兼容性和安全性得到了广泛应用。然而&#xff0c;有时我们需要将多个PDF文件合并成一个&#xff0c;以便于管理和分享。本文将详细介绍几种合并PDF的方法&#xff0c;帮助读者轻松完成PDF文件的合并工作。 首先通过浏览器…

运营商二要素核验-手机号机主姓名核验接口-运营商二要素核验接口

通过电信运营商验证手机号码与姓名是否一致。广泛用于实名注册、风控审核等场景&#xff0c;如电商、游戏、直播、金融等需要用户实名认证的场景。支持携号转网核验。 更新周期&#xff1a;联通T1 电信T3 移动T3~5 均为工作日 接口地址&#xff1a; https://www.wapi.cn/api_de…