0. 前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在
常量字符串 中或者 字符数组 中。
字符串常量 适用于那些对它不做修改的字符串函数。
1.无限制长度的库函数类型
1.1 strlen
库函数 strlen的作用就是计算某个字符串的大小。之前在操作符sizeof那一结就看到过strlen,之前就有稍稍做过一些简介。
从这个函数结构看,它返回的是一个size_t 类型的值,这里解释一下size_t。
size_t
size_t 是一些C/C++标准在stddef.h中定义的,size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数。
那么我们可以来尝试模拟实现一下strlen。上代码
#include <stdio.h> #include <assert.h> size_t my_strlen(const char* str) { assert(str);//对传进的数组进行断言,确保str不为'\0 ' const char* start = str; const char* end = str; while (*end != '\0') { end++; } return end - start; } int main() { char arr[] = "hello bit"; printf("%d", my_strlen(arr)); return 0; }
介绍一下assert:断言
如果具有函数形式的此宏的参数表达式比较等于零(即表达式为 false),则会将消息写入标准错误设备并调用,从而终止程序执行。
介绍一下const:
我们之前最开始就见过这个玩意,在常量与变量那一章节的时候。被const修饰过的变量,就无法修改了。
常量指针有两种定义:
const int * p = 20; int * const p =20;
第一种定义:const在 * 的左边,表示指针指向的内容,不可以通过指针来改变,但指针本身是可以发生改变的,可以通过一个其他的来改变。
第二种定义:const在 * 的右边,表示,这里修饰的指针变量p,表示指针变量不能被改变,但是之指针所指向的内容是可以发生改变的。
我们这里不希望改变指针str的值,所以对它用const修饰。
1.2 strcpy
将源指向的 C 字符串复制到目标所指向的数组中,包括终止 null 字符(并在该点停止)。
我们也对strcpy进行模拟实现
#include <stdio.h> #include <assert.h> char* my_strcpy(char* dest, const char* src) { assert(dest);//对dest断言防止出现sdest为'\0'的情况 assert(src);//对src断言防止出现src为'\0'的情况 char* ret = dest; while (*dest++ = *src++)//每次循环将src赋给dest并且同时向后移动指针 { ;//当src为\0时循环结束 } return ret; } int main() { char arr1[20] = "abc"; char arr2[] = "hello bit"; printf("%s\n", my_strcpy(arr1, arr2)); return 0; }
我们在对strcpy进行模拟实现或者是使用都必须注意几点
1.源字符串必须以 '\0' 结束。
2.会将源字符串中的 '\0' 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变
否则就会发生各种各样的错误。
1.3 strcat
将源字符串的副本追加到目标字符串。目标中的终止空字符被源的第一个字符覆盖,并且空字符包含在由目标中两者的串联组成的新字符串的末尾。
注意事项:
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
模拟实现:
#include <stdio.h> char* my_strcat(char* str1,const char* str2) { char* ret = str1;//保存ch1的首元素地址 while (*str1 != '\0') { str1++; }//表示找到了str1也就是ch1的结尾处 while (*str1++ = *str2++)//追加 { ; } return ret; } int main() { char ch1[20] = "hello "; char ch2[] = "world"; printf("%s", my_strcat(ch1, ch2)); return 0; }
看看结果:
那我们是否可以自己给自己追加呢?
假设ch1 为 " hello " 根据上面代码的思路,我们先找到自己的 ' \0 ' 处,然后将 ‘ h ’ 给到 ' \0 ' ,当这一步进行以后,我们原来的ch1就不再是 " hello " 而是 " helloh "。那我们一直往后追加,就永远追不到结尾' \0 '。直到程序奔溃。
所以我们不可以用strcat给自己追加自己。
1.4 strcmp
对两个字符串的比较。
标准规定:
第一个字符串大于第二个字符串,则返回大于 0 的数字
第一个字符串等于第二个字符串,则返回 0
第一个字符串小于第二个字符串,则返回小于 0 的数字
#include <stdio.h> #include <assert.h> int my_strcmp(const char* str1, const char* str2) { assert(str1 && str2);//断言 while (*str1 == *str2)//判断str1 和 str2 每个对于的字符是否相等 { if (*str1 == '\0')//这是在str1 和str2 相等的条件下进行的,当str1 ='\0'时,str2 ='\0' { return 0; } str1++; str2++; } return *str1 - *str2;//返回两个差值 } int main() { char ch1[] = "abc"; char ch2[] = "abc"; int key = my_strcmp(ch1, ch2); if (key > 0) { printf("ch1 > ch2\n"); } else if (key < 0) { printf("ch1 < ch2\n"); } else { printf("ch1 == ch2\n"); } return 0; }
2.限制长度的库函数类型
2.1 strncpy
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
上代码:
#include <stdio.h> int main() { char str1[20] = "abcd"; char str2[]="***"; strncpy(str1, str2, 2); printf("%s\n",str1); return 0; }
但是需要注意:拷贝的大小尽量不要大于源字符串的大小,我们把上面的2改为8试试。
我们默认添加 ' \0 '虽然对我们的目标影响不大,但是还是得尽量避免。
2.2 strcat
将源的前 num 个字符追加到目标,外加一个终止空字符。
如果源中 C 字符串的长度小于 num,则仅复制到终止空字符之前的内容。
上代码:
#include <stdio.h> int main() { char str1[20] = "abcd\0hijkln";//为了区别追加字符串末尾的 '\0'是从str2中获取的还是本身自带的 char str2[] = "***"; strncat(str1, str2, 2); printf("%s\n", str1); return 0; }
根据结果可以看见,原来的 ' h ' 被 ' \0 ' 替换了 。
我们之前用strcat自己给自己追加行不通,但是我们可以用strncat来完成,确定要追加多少个字符。
2.3 strncmp
将 C 字符串 str1 的最多数字字符与 C 字符串 str2 的字符进行比较。
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对操作,直到字符不同,直到达到终止空字符,或者直到两个字符串中的数字字符匹配,以先发生者为准。
它的返回值与strcmp一样。
看代码
#include <stdio.h> int main() { int ret = strncmp("abcdef","abc",2); printf("%d", ret); return 0; }
我们把它改为比较前四个试试:
我们这一章先介绍这几个字符串函数,下一章主要讲讲内存函数等等。