常见字符函数和字符串函数(上)
1. 字符分类函数
字符分类函数是一类用于判断字符是否属于特定的字符类别(如字母、数字、标点符号等)的函数。在C语言中,这些函数通常可以在<ctype.h>头文件中找到,它们对于文本处理和输入验证非常有用。
这些函数通常返回一个非零值(通常是int类型的1)如果字符c属于被测试的类别,否则返回0。例如,isalpha('A')会返回1,因为’A’是一个大写字母。
字符分类函数在处理用户输入、验证数据、以及进行文本分析时非常有用。例如,您可能需要检查用户输入的密码是否包含至少一个数字和一个特殊字符,这时就可以使用isdigit和ispunct函数来进行验证。
这些函数使用起来非常类似,就以 islower 函数为例。
1. int islower(int c);
islower 函数能够判断参数部分的 c 是否是小写字母。
通过返回值来判断是否是小写字母,如果是小写字母就返回非零的整数,如果不是小写字母,则返回零。
练习:
| 试着编写一个函数将给定字符串里的大写字母全部转化为小写,其他字符不变。
提示:
- 据Ascll表可知,大写字母的Ascll比自身小写字母小32;
- 并且我们需要判断给定字符串中大写字母都有哪些,这时候就需要isupper函数来帮忙了;
- 不要忘记包含对应的头文件<ctype.h>。
示例代码如下:
1. #include<stdio.h>
2. #include<ctype.h>
3. #include<assert.h>
4. void ce_lower(char* s)
5. {
6. assert(*(s+i)!='\0');
7. int i = 0;
8. char c;
9. while (s)
10. {
11. c = *(s+i);
12. if (isupper(c))
13. {
14. c += 32;
15. }
16. putchar(c);
17. i++;
18. }
19. }
20.
21. int main()
22. {
23. char str[] = { "Test String.\n" };
24. ce_lower(str);
25. return 0;
26. }
2. 字符转换函数
顾名思义,字符转换函数自然就是进行字符转换的,其作用类似于我们上述编写的这个代码。
C语言提供了两个字符转换函数:
1. int tolower(int a);//将参数传进去的大写字母转换为小写
2. int toupper(int b);//将参数传进去的小写字母转换为大写
上面的代码我们依靠Ascll之间的数值关系转换的,而有了之两个函数我们就可以直接使用函数来进行转换了,思路更简单了是不是。
1. #include<stdio.h>
2. #include<ctype.h>
3. #include<assert.h>
4. void ce_lower(char* s)
5. {
6. assert(s);
7. int i = 0;
8. char c;
9. while (*(s+i)!='\0')
10. {
11. c = *(s+i);
12. if (isupper(c))
13. {
14. toupper(c);
15. }
16. putchar(c);
17. i++;
18. }
19. }
20.
21. int main()
22. {
23. char str[] = { "Test String.\n" };
24. ce_lower(str);
25. return 0;
26. }
3. strlen 的使用和模拟实现
1. size_t strlen(const char* str);
以下是strlen函数的几个特点:
- 字符串以'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0',如果一个字符串在中间位置出现'\0',那么就只计算'\0'前的字符串长度,如果在开头出现,就为零)
- 参数指向的字符串必须以'\0'结尾,不然函数无法识别要计算到哪里;
- 注意函数的返回值为size_t,是无符号的(易错);
- strlen的使用需要包含头文件<string.h>;
strlen函数模拟实现:
第一种:计数器方式
1. #include<stdio.h>
2. #include<string.h>
3. #include<assert.h>
4. int my_strlen(const char* s)
5. {
6. assert(s);
7. int count = 0;
8. while (*s)
9. {
10. s++;
11. count++;
12. }
13. return count;
14. }
15. int main()
16. {
17. int ret = my_strlen("abcdef\n");
18. printf("%d\n", ret);
19. return 0;
20. }
第二种:不能创立临时变量计数器
1. #include<stdio.h>
2. #include<assert.h>
3. int my_strlen(const char* s)
4. {
5. assert(s);
6. if (*s == '\0')
7. {
8. return 0;
9. }
10. else
11. {
12. return 1 + my_strlen(++s);
13. }
14. }
15. int main()
16. {
17. int ret = my_strlen("abcdef\n");
17. printf("%d\n", ret);
19. return 0;
20. }
第三种:指针-指针的方式
1. #include<stdio.h>
2. #include<assert.h>
3. int my_strlen(const char* s)
4. {
5. assert(s);
6. char* cut = s;
7. while (*s)
8. {
9. s++;
10. }
11. return s - cut;
12. }
13. int main()
14. {
15. int ret = my_strlen("abcdef\n");
16. printf("%d\n", ret);
17. return 0;
18. }
以上三种都是有可能是strlen函数的内部实现方法,但也仅仅是有可能,具体其内部方法实现到底是怎样,这我们就不得而知了。并且与其原来函数不同的是,我们定义的函数其返回类型都为int类型,而原函数返回类型为size_t,当然这个我们自己就可以进行修改,再次提出这个点,无非就是因为它很容易被人忘记。
4. strcpy函数的使用和模拟实现
1. char* strcpy(char* destination, const char* source);
首先,我们先要知道这个函数是干嘛的?
答:拷贝一个字符串到另一个字符串里。
我们仔细观察这个函数形参可知,第一个形参命名为destination,意为目标,目的地,可见是要拷贝进的那个字符串,而第二个source,意为来源,可见是要被拷贝的那个字符串。从而我们可知这个函数的功能是要把第二个形参代表的字符串拷贝到第一个形参代表的字符串。好了,虽然功能已明确,但还有以下几点我们需要注意一下。
- 源字符串必须以 '\0' 结束;
- 会将源字符串中的 '\0' 拷贝到目标空间;
- 目标空间必须足够大,以确保能存放源字符串;
- 目标空间必须可修改;
注:源字符串指的是来源字符串,也就是上述所讲的第二个字符串。
1. #include<stdio.h>
2. #include<string.h>
3. int main()
4. {
5. char str1[20] = "Hello world!";
6. char str2[20] = { 0 };
7. strcpy(str2, str1);
8. printf("%s\n", str2);
9. return 0;
10. }
strcpy函数的模拟实现:
1. #include<stdio.h>
2. #include<assert.h>
3. char* my_strcpy(char* dest, const char* src)
4. {
5. char* ret = dest;
6. assert(dest && src);
7. while (*src)
8. {
9. *dest++ = *src++;
10. }
11. *dest=*src;
12. return ret;
13. }
这个是较为麻烦一点的实现方法,其实这个代码还可以简化一点,如下:
1. #include<stdio.h>
2. #include<assert.h>
3. char* my_strcpy(char* dest, const char* src)
4. {
5. char* ret = dest;
6. assert(dest && src);
7. while (*dest++ = *src++)
8. {
9. ;
10. }
11. return ret;
12. }
如果说这两个代码有什么会让人有点看不懂的地方,只有可能在while循环那一块,既然如此,我们就来分析一下这一块。
首先,我们需要清楚一点:* 的优先级并没有 ++ 高,并且是后置加加,这样就使得第一次赋值时还是原始值,成功将第一个字符拷贝过去;
其次,应该就是第二个代码中直接将*dest++ = *src++作为条件,这样实现的效果其实和第一个没啥区别,表达式中的值即为while循环条件值,当最后src指向的为'\0'时,恰好为空,实现拷贝;
5. strcat 的使用和模拟实现
此函数主要用于追加字符串,也就是将一个字符串追加到另一个字符串末尾。
那么它要如何使用呢?想要使用它,我们需要先来了解一下它的一些特点:
- 源字符串必须以 '\0' 结束;
- 目标字符串中也要有 '\0' ,否则没法知道从哪里开始追加;
- 目标空间需要足够大,能容下源字符串的内容;
- 目标空间必须可修改;
1. #include<stdio.h>
2. #include<string.h>
3. int main()
4. {
5. char str1[20] = "Hello ";
6. char str2[] = "world";
7. strcat(str1, str2);
8. printf("%s\n", str1);
9. return 0;
10. }
模拟实现strcat函数:
1. #include<stdio.h>
2. #include<assert.h>
3. char* my_strcat(char* dest, const char* src)
4. {
5. char* ret = dest;
6. assert(dest && src);
7. while (*dest)
8. {
9. dest++;
10. }
11. while ((*dest++ = *src++))
12. {
13. ;
14. }
15. return ret;
16. }
17. int main()
18. {
19. char str1[20] = "Hello ";
20. char str2[] = "world";
21. char*s=my_strcat(str1, str2);
22. printf("%s\n", str1);
23. return 0;
24. }
思考:如果我们将字符串自己追加会发生什么呢?
官方函数:
自己写的函数:
可见使用官方函数可以成功,但这是根据编译器不同效果也不一样,这是在Vs上可以,但在其他编译器就不一定可以了。 自己写的函数并没有成功,调试可知是陷入了死循环,src指向的内容一直在给dest指向的空间,就以图中字符串为例,起始src指向H,当\0被H替代后,然后其后空间又分别被ello代替,然后此时src又指向H,反反复复,直到空间溢出,退出程序。再次表明了我们模拟实现的仅仅只是他的实现猜想。
6. strcmp的使用和模拟实现
之前我们已经知道了如何用程序来比较两个整型的大小,但面对字符串之间的比较,我们则是束手无策,但现如今,有了strxmp函数来帮忙,它主要通过比较字符的Ascll值来进行判断.
还和上述函数一样,我们学习使用它之前,先来看一看它的一些规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字;
- 第一个字符串等于第二个字符串,则返回0;
- 第一个字符串小于第二个字符串,则返回小于0的数字;
1. #include<stdio.h>
2. #include<string.h>
3. int main()
4. {
5. char str1[] = "abcdefg";
6. char str2[] = "abcdrfg";
7. int ret = strcmp(str1, str2);
8. printf("%d\n", ret);
9. return 0;
10. }
模拟实现strcmp函数:
1. #include<stdio.h>
2. #include<assert.h>
3. int my_strcmp(const char* str1, const char* str2)
4. {
5. assert(str1 && str2);
6. while (*str1 == *str2)
7. {
8. if (*str1 == '\0')
9. {
10. return 0;
11. }
12. str1++;
13. str2++;
14. }
15. return *str1 - *str2;
16. }
17. int main()
18. {
19. char str1[] = "abcdefg";
20. char str2[] = "abcdrfg";
21. int ret = my_strcmp(str1, str2);
22. printf("%d\n", ret);
23. return 0;
24. }
模拟函数实现的结果是判断两个字符串第一个不相等的字符的Ascll值之差,更为详细一点。