字符函数和字符串函数
字符函数:
1.字符分类函数
C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。
这些函数的使用都需要包含一个头文件:<ctype.h>
函数 如果他返回下列条件就返回
iscntrl 任何控制字符
isspace 任何字符:空格 ‘’,换页 ‘\f’ ,换行 '\n',回车 ‘\r’,制表符'\t'或者垂直制表符‘\v’
isdigit 十进制数字 ‘0’ ~ ‘9’ 字符
isxdigit 十进制数字,包括所有十进制数字字符,小写字母 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 任何可打印字符,包括图形字符和空白字符
islower 是能够判断参数部分的 c 是否是小写字母的。
通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。
//判断字母的大小写
int main()
{int ch = getchar();//getchar()接受一个字符,直接返回来,会让我们输入一个值if (ch >= 'a' && ch <= 'z'){printf("小写\n");}else if (ch >= 'A' && ch <= 'Z'){printf("大写\n");}//putchar(ch);//直接输出(打印)上面getchar输入的值//在ASCII码中0-31这32个字符是不可打印字符return 0;
}
#include<ctype.h>
int main()
{int ch = getchar();if (islower(ch)){printf("小写\n");}else if (isupper(ch)){printf("大写\n");}return 0;
}
2.字符转换函数
例子:将字符串中的小写字母转换成大写字母,其余的字符不变。
int tolower ( int c ); 将参数传进去的大写字母转为小写
int toupper ( int c ); 将参数传进去的小写字母转为大写
//将一个字符串转换全小写
int main()
{char arr[] = "I Am A Student";int i = 0;while (arr[i]){if (isupper(arr[i])){arr[i] = arr[i] + 32;// a 对应的ASCII码值:97// A 对应的ASCII码值:65}putchar(arr[i]);i++;}return 0;
}
字符串函数:
3.strlen 的使用和模拟实现
size_t strlen ( const char * str );
- 字符串以 ' \0 ' 作为结束标志,strlen函数返回的是在字符串中 ' \0 ' 之前的字符的个数(不包含' \0 ')
- 参数指向的字符串必须以 ' \0 ' 结束
- 注意函数返回的类型是 size_t , 是无符号的(易错)
- strlen的头文件是<string.h>
#include<string.h>
//strlen() 函数 求字符串长度的函数
int main()
{//char arr[] = "zxcvbn";// 数组内容:z x c v b n \0//char arr[] = { 'z','x','c' };//随机值 没有找到 \0char arr[] = { 'z','x','c','\0'};// 3size_t len = strlen(arr);printf("%zd\n", len);return 0;
}
看个有趣的代码:
int main()
{ // 3-7=-4 ??if (strlen("asd") - strlen("asdfghj") > 0){printf("大于\n");}else{printf("小于等于");}return 0;
}
运行出的结果:
为什么上面显示的是 “大于”??
strlen 返回的值是 无符号类型的整数,无符号类型的整数的加减的结果也是无符号类型的整数,所以不会出现负数
strlen 函数的多种模拟实现方法:
#include<assert.h>//方法1:size_t my_strlen1(char * str)
{assert(str);size_t count = 0;while (*str){count++;str++;}return count;
}//方法2:size_t my_strlen2(char* str)
{assert(str);char *start = str;while (*str){str++;}return str-start;//指针减指针的应用
}//方法3://不创建变量实现 strlen()函数的实现 ---- 递归的方法来实现
size_t my_strlen3(char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen3(str + 1);}// ch arr[]="zxcvbn" --> [z x c v b n \0]
//1+my_srtrlen("xcvbn")
//1+1+my_srtrlen("cvbn")
//1+1+1+my_srtrlen("vbn")
//1+1+1+1+my_srtrlen("bn")
//1+1+1+1+1+my_srtrlen("n")
//1+1+1+1+1+1+my_srtrlen("")int main()
{char arr[] = "abc";//size_t len = my_strlen1(arr);//size_t len = my_strlen2(arr);size_t len = my_strlen3(arr);printf("%zd\n", len);return 0;
}
4.strcpy 的使用和模拟实现
char* strcpy(char* destination, const char* source);
- 源字符串必须以 ' \0 ' 结束
- 会将源字符串中的 ' \0 ' 拷贝到目标空间
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可以修改
int main()
{char arr1[] = "xxxxxxxxxxxxxxxxxx";char arr2[] = "hehehe";strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}
调试看看是否将arr2的内容拷贝到了arr1中,同样也将arr2中的 '\0' 也拷贝到了arr1中??
确实是:将arr2的内容拷贝到了arr1中,同样也将arr2中的 '\0' 也拷贝到了arr1中
int main()
{char arr1[3] = { 0 };//目标空间必须足够大,否则会出现错误char arr2[] = "hello hello world";strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}
int main()
{char* pch = "abcdefghiasdfg";//常量字符串是不可修改的char arr[] = "hello world";strcpy(pch, arr);printf("%s\n", pch);//目标空间必须是可以修改的return 0;
}
strcpy 的模拟实现:
char * my_strcpy(char* str1,const char* str2)
{char* ret = str1;while (*str2 !='\0'){*str1 = *str2;str1++;str2++;}*str1 = *str2;return ret;
}//优化如下:#include <assert.h>
char* my_strcpy(char* str1, const char* str2)
{assert(str1 && str2);char* ret = str1;while (*str1++ = *str2++){;}return ret;
}int main()
{char arr1[20] = {0};char arr2[] = "hello world";printf("%s\n",my_strcpy(arr1, arr2));return 0;
}
5.strcat 的使用和模拟实现
char * strcat ( char * destination, const char * source );
- 源字符串必须以 ' \0 ' 结束
- 目标空字符串中也得有 ' \0 ',否则没办法知道从哪里开始追加
- 目标空间必须足够大,能容下源字符串的内容
- 目标空间必须可修改
- 字符串自己给自己追加,是什么情况??
int main()
{char arr1[25] = "Hello ";char arr2[] = "World";char *ret=strcat(arr1, arr2);printf("%s\n", ret);return 0;
}
模拟实现strcat函数:
char* my_strcat(char* dest, const char* sour)
{char* ret = dest;assert(dest && sour);//1.找到目标空间中的\0while (*dest){dest++;}//2.拷贝sour中的内容到dest中while (*dest++ = *sour++){;}return ret;
}int main()
{char arr1[25] = "Hello ";char arr2[] = "World";char* ret = my_strcat(arr1, arr2);printf("%s\n", ret);return 0;
}
字符串自己给自己追加的情况:
#include <assert.h>
char* my_strcat(char* dest, const char* sour)
{char* ret = dest;assert(dest && sour);//1.找到目标空间中的\0while (*dest){dest++;}//2.拷贝sour中的内容到dest中while (*dest++ = *sour++){;}return ret;
}int main()
{char arr1[25] = "Hello ";char* ret = my_strcat(arr1, arr1);printf("%s\n", ret);return 0;
}
6.strcmp 函数的使用
int strcmp ( const char * str1, const char * str2 );
标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
- 是根据两个字符串上对应的字符ASCII码值的大小的比较
int main()
{int ret = strcmp("bbq", "abcdef");printf("%d\n", ret);return 0;
}
int main()
{int ret = strcmp("bbq", "abcdef");if (ret > 0){printf("大于\n");}else if (ret < 0){printf("小于\n");}elseprintf("等于\n");return 0;
}
strcmp函数的模拟实现:
int my_strcmp(const char* dest, const char* sour)
{while (*dest == *sour){if (*dest == '\0')return 0;dest++;sour++;}if (*dest - *sour > 0)return 1;elsereturn -1;}//方法二:
int my_strcmp(const char* dest, const char* sour)
{while (*dest == *sour){if (*dest == '\0')return 0;dest++;sour++;}return *dest - *sour;}
int main()
{int ret = my_strcmp("bbq", "abcdef");if (ret > 0){printf("大于\n");}else if (ret < 0){printf("小于\n");}elseprintf("等于\n");return 0;
}
7.strncpy 函数的使用
char * strncpy ( char * destination, const char * source, size_t num );
- Copies the first num characters of source to destination. If the end of the source C string(which is signaled by a null-character) is found before num characters have been copied,destination is padded with zeros until a total of num characters have been written to it.
- 拷⻉num个字符从源字符串到⽬标空间。
- 如果源字符串的⻓度⼩于num,则拷⻉完源字符串之后,在⽬标的后边追加0,直到num个。
8.strncat 函数的使用
char * strncat ( char * destination, const char * source, size_t num );
- Appends the first num characters of source to destination, plus a terminating null-character(将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 \0 字符)。
- If the length of the C string in source is less than num, only the content up to the terminatingnull-character is copied.(如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到\0 的内容追加到destination指向的字符串末尾)。
//strncat 比strcat多了一个参数:可以限制追加的字符的个数
int main()
{char arr1[20] = "xxxxxxxxxx";char arr2[] = "world";strncat(arr1, arr2, 7);//调试就会发现:看不出是否追加arr2的\0return 0;
}
int main()
{char arr1[20] = "hello\0xxxxxxxx";char arr2[] = "world";strncat(arr1, arr2, 7);//将w o r l d \0拷贝到了arr1中,是从arr1中的第一个\0开始拷贝//可以看出是要将arr2中的\0追加到arr1中的return 0;
}
9.strncmp函数的使用
int strncmp ( const char * str1, const char * str2, size_t num );
比较str1和str2的前num个字符,如果相等就继续往后⽐较,最多比较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0。
int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = strncmp(arr1, arr2, 3);//将arr1和arr2中的前3个字母进行比较,有字母长度的限制printf("%d\n", ret);return 0;
}
10.strstr 函数的使用
- Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(函数返回字符串str2在字符串str1中第⼀次出现的位置)。
- The matching process does not include the terminating null-characters, but it stops there.(字符串的⽐较匹配不包含 \0 字符,以 \0 作为结束标志)。
int main()
{char arr1[] = "abbbbcdebbehig";char arr2[] = "bbe";char* ret = strstr(arr1, arr2);if (ret != NULL)printf("%s\n", ret);elseprintf("找不到\0");return 0;
}
strstr函数的模拟实现:
//暴力求解 char* my_strstr(const char* str1, const char* str2)
{const char* cur = str1;char* s1 = NULL;char* s2 = NULL;assert(str1 && str2);//特殊规定的处理:if (*str2 == '\0')return (char *)str1;while (*cur){s1 = cur;s2 = str2;while (*s1&&*s2&&*s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return (char*)cur;}cur++;}return NULL;
}//测试用例1
//abbbbcdebbehig
//bbe//测试用例2
//abbbbcdebbehig
//abb//测试用例3
//abbbbcdebbehig
//bbf//测试用例4
//abbbbcdebbehig
//abbbbcdebbehig//测试用例越多,功能越齐全,不容易漏掉其他的情况
//bug也不容易出现int main()
{char arr1[] = "abbbbcdebbehig";char arr2[] = "bbe";char* ret = my_strstr(arr1, arr2);if (ret != NULL)printf("%s\n", ret);elseprintf("找不到\0");return 0;
}
11.strtok 函数的使用
char * strtok ( char * str, const char * sep);
#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<string.h>
//strtok 函数
int main()
{char arr1[] = "zhangsan@163.com#hehhe";char arr2[30] = {0};strcpy(arr2, arr1);const char* p = "@.#";char* s = NULL;//for循环优点:初始化部分只执行一次for (s = strtok(arr2, p); s != NULL; s = strtok(NULL, p)){printf("%s\n", s);}//char* s = strtok(arr2, p);//printf("%s\n", s);//s = strtok(NULL, p);//printf("%s\n", s);//s = strtok(NULL, p);//printf("%s\n", s);//s = strtok(NULL, p);//printf("%s\n", s);//繁琐、冗余return 0;
}
12.strerror 函数的使用
- strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
- 在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全局的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会将对应 的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址回。
int main()
{int i = 0;for (i = 0; i < 10; i++){printf("%d:%s\n", i, strerror(i));}return 0;
}
在vs下输出结果为:
#include<errno.h>//C语言是可以进行文件操作的
//打开文件:
//FILE* pf=fopen(...)
//如果文件打开成功,则返回一个地址
//如果文件打开失败,则返回一个NULL
int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)//printf("Error opening file unexist.ent: %s\n", strerror(errno));//strerror 头文件:<string.h>//errno 头文件:<errno.h>perror("Error opening file unexist.ent");//perror 函数自动加上:和空一格return 0;
}
输出结果: