大家好,今天我们一起学习相关的字符串函数,相信有很多函数大家都知道如何去运用,但是更重要的是我们要了解并掌握其中的代码逻辑。
1. strlen函数的使用和模拟实现
strlen函数,顾名思义,string length--> 求字符串的长度
size_t strlen(const char* str);
使用strlen函数时,有几个点需要我们注意:
- 字符串以'\0' 作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0')
- 参数指向的字符串必须以'\0'结束
- 注意函数的返回值为size_t,是无符号的(容易出错)
- strlen函数的使用需要包含头文件 #include<string.h>
这里我们针对函数的返回值为size_t,举一个简单的小例子
#include<stdio.h>
#include<string.h>
int main() {
if (strlen("abc") - strlen("abcdef") > 0) {
printf("大于\n");
}
else {
printf("小于等于\n");
}
return 0;
}
str1字符串长度为6,str2字符串长度为3,进入if条件,6-3 = -3 ,哈哈,我知道啦,肯定走else,控制台上打印 str1 > str2
结果是不是这样呢?
诶,好奇怪,为啥打印大于呢?
这是因为,strlen函数返回的是size_t类型 ,无符号整型 , 3-6 = -3 相当于(无符号整型 - 无符号整型 ---------> 无符号整型), -3 转换为无符号的整型,将会是一个非常大的数,因此,会在控制台上打印"大于"。
那我们有没有办法打印 str1 > str2 呢? 办法肯定有, 就是将strlen函数返回的结果强制类型转换为int整型,控制台上就可以打印"小于等于"了。
strlen函数的使用:
#include<stdio.h>
#include<string.h>
int main() {
char arr[] = "abcdefg";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
执行结果: 7
接下来我们模拟实现strlen函数
方法1: 采用计数器,定义一个变量pcur,用来遍历字符串,pcur初始时指向数组str,记录的是数组首元素的地址,count计数器初始时为0,每当pcur遍历完一个元素,count自增一次,直到pcur走到'\0',此时返回count
代码如下:
int my_strlen(char arr[]) {
int count = 0; //计数器初始时为0
char* pcur = arr; //pcur指向首元素
while (*pcur != '\0') { //pcur进入循环,一直走到'\0'为止
count++; //每当遍历一个元素,计数器自增一次
pcur++; //pcur继续遍历下一个元素
}
return count; //返回计数器
}
int main(){
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
方法2: 我们可以采用递归,通过不断调用自身处理字符串的下一个字符,直到遇到结束符'\0',每次递归返回当前字符长度加上剩余字符串长度,从而得到整个字符串的长度。
比如:字符串为abcdef, 现在我们调用my_strlen方法来获取字符串的长度,那么过程大致是这样的:
my_strlen("abcdef");
1+my_strlen("bcdef");
1+1+my_strlen("cdef");
1+1+1+my_strlen("def");
1+1+1+1+my_strlen("ef");
1+1+1+1+1+my_strlen("f");
1+1+1+1+1+1+my_strlen("");
1+1+1+1+1+1+0;
将结果6返回给控制台
代码如下:
int my_strlen(char arr[]) {
char* pcur = arr;
if (*pcur == '\0') {
//如果传递过来的arr(首元素的地址为'\0'),则返回0
return 0;
}
else {
//否则,返回当前字符长度加上剩余字符串长度
return 1 + my_strlen(arr + 1);
}
int main(){
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
方法3: 我们可以采取指针-指针得到数组长度,用start指针指向首元素,用end指针指向最后一个元素,两个指针相减即可得到字符串的长度。
代码如下:
int my_strlen(char arr[]) {
char* start = arr; //start指针指向首元素
char* end = arr;
while (*end != '\0') { //end指针一直走到'\0',才退出循环
end++;
}
return end - start; //两个指针相减得到它们之间的元素个数
}
int main(){
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
另外,还有一种不需要指针的代码如下:
int str_len(char st[256]){
int i = 0;
while(st[i] != '\0'){ //下标i从0开始,从第一个元素开始,一直遍历到最后一个元素
i++;
}
return i; //返回下标i即字符串的长度
}
2.strcpy函数的使用和模拟实现
strcpy--->string copy,一眼就看出是字符串拷贝,将源字符串的元素拷贝到目标字符串中去,我们来瞅瞅这个函数
char* strcpy(char* destnation , const char* source);
使用strcpy函数时,有几个点需要我们注意:
- 源字符串必须以 '\0' 结束
- 会将源字符串中的 '\0' 拷贝到目标空间
- 目标空间必须足够大,以确保能存放源字符串
- 目标空间必须可以修改
使用strcpy函数
#include<stdio.h>
#include<string.h>
int main() {
char arr1[100] = "";
char arr2[] = "abcdef";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
执行结果为: abcdef
strcpy函数的模拟实现
方法一: 定义2个数组,一个为源数组,一个为目标数组,将源数组中的数据拷贝到目标数组中,定义2个指针,分别遍历源数组和目标数组,每次遍历完一个元素,2个指针都指向下一个元素,一直遍历到源数组的最后一个元素。
代码如下:
char* my_strcpy(char* dest, const char* src) { //加上const修饰是为了防止src的内容被改变
assert(dest && src); //防止dest和src是空指针
char* ret = dest; //用ret来保存dest
char* s1 = dest;
char* s2 = src;
while (*s2 != '\0') { //拷贝除'\0'的所有内容
*s1 = *s2;
s1++;
s2++;
}
*s1 = *s2; //拷贝'\0'
return ret;
}
int main(){
char str1[100] = "#################";
char str2[] = "abcdef";
my_strcpy(str1,str2);
printf("%s\n",str1);
}
emmm,代码有点复杂冗余,可否简短一些呢?
当然可以! 优化代码如下:
char* my_strcpy(char* dest,const char* src) { //加上const修饰是为了防止src的内容被改变
assert(dest && src); //防止dest和src是空指针
char* ret = dest; //用ret来保存dest
char* s1 = dest;
char* s2 = src;
while (*s2) { //拷贝除'\0'的所有内容
*s1++ = *s2++;
}
*s1 = *s2; //拷贝'\0'
return ret;
}
哈哈哈,我们还可以再优化:
char* my_strcpy(char* dest, const char* src) { //加上const修饰是为了防止src的内容被改变
assert(dest && src); //防止dest和src是空指针
char* ret = dest; //用ret来保存dest
char* s1 = dest;
char* s2 = src;
while (*s1++ = *s2++) { //循环拷贝,当拷贝完'\0',判断为假,跳出循环
; //空语句
}
return ret;
}
还有一种不用指针的解法如下:
char* str_cpy(char str1[256],char str2[50]){
int i = 0; //下标的初始值为0
while(str2[i] != '\0'){ //str2[i]的元素为'\0'时,跳出循环
str1[i] = str2[i]; //将str2中的元素赋给str1
i++; //每赋值一次,下标自增一次
}
str1[i] = '\0'; //str1数组最后的元素为'\0'
return str1; //将str1返回
}
3. strcat函数的使用和模拟实现
strcat函数(字符串拼接函数),是将一个字符串拼接到另外一个字符串,构成一个新的字符串,函数原型如下:
char* strcat(char* dest,const char* src);
使用strcat函数时,有几个点需要我们注意:
- 源字符串必须以'\0'结束
- 目标字符串也得有'\0',否则没办法知道追加从哪里开始
- 目标空间必须足够大,能容纳下源字符串的内容
- 目标空间必须可修改
使用strcat函数 :
#include<stdio.h>
#include<string.h>
int main() {
char arr1[100] = "abcd";
char arr2[] = "efgh";
strcat(arr1, arr2); //将arr2里面的元素拼接到arr1的后面
printf("%s\n", arr1);
return 0;
}
执行结果为: abcdefgh
模拟实现strcat函数
思路: 1. 找到目标字符串的'\0'
2.拷贝源头字符串的数据到目标空间的'\0'位置及后面空间
代码如下:
void my_strcat(char arr1[], char arr2[]) {
assert(arr1 && arr2); //保证arr1 和 arr2 有效
char* s1 = arr1;
char* s2 = arr2;
while (*s1 != '\0') { //找到目标空间的'\0'
s1++;
}
//循环将 s2 指向的字符逐个拷贝到 arr1 数组的末尾
//当拷贝到 arr2 数组的结束符'\0'时,循环结束
//每拷贝完一个字符, s1 和 s2 都会自增一次,直到循环完成
while (*s2 != '\0') { //拷贝除'\0'的部分
*s1 = *s2;
s1++;
s2++;
}
*s1 = *s2; //拷贝'\0'
}
int main(){
char arr1[100] = "hello";
char arr2[] = "world";
my_strcat(arr1,arr2);
printf("%s\n",arr1);
}
另外: strcat函数不能自己给自己追加,因为会把源字符串的'\0' 覆盖掉,造成死循环。
另外一种不用指针的解法如下:
char* str_cat(char str1[256],char str2[50]){
int i = 0;
int j = 0;
i = strlen(str1); //下标i从str1的最后一个元素的下一个位置开始
while(str2[j] != '\0'){ //遍历str2
str1[i] = str2[j]; //将str2中的元素拷贝到str1中
i++;
j++;
}
str1[i] = '\0'; //str1数组最后一个元素为'\0'
return str1; //将str1返回
}
4. strcmp函数的使用和模拟实现
strcmp函数,我们可以将其拆成2个英文单词,string compare,意思是字符串之间的比较,比较的是对应位置上ASCII码值的大小,注意: 比较的不是字符串的长度!
函数原型为:
int strcmp(const char* s1, const char* s2);
只有strcmp函数时,有以下几点需要注意:
- 第一个字符串大于第二个字符串,则返回大于0的数字(一般返回1)
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字(一般返回-1)
- 怎样去判断两个字符串呢? 比较两个字符串中对应位置上字符ASCII码值的大小
strcmp函数的使用:
#include<stdio.h>
#include<string.h>
int main() {
char arr1[] = "abcdefg";
char arr2[] = "abc";
int ret = strcmp(arr1, arr2); //字符'd'的ASCII码值比'\0'大,因此返回1
printf("%d\n", ret);
return 0;
}
字符串的比较是从左往右依次比较字符的ASCII码值,'d' 的ASCII码值比'\0'大,此时不再进行比较,直接输出结果。
执行结果: 1
怎样实现strcmp函数呢?
思路1 : 定义2个指针,分别指向2个字符串数组,当它们指向的字符的ASCII码值相同时,继续比较下一个字符,如果其中一个字符串数组的元素的ASCII码值比另外一个字符串数组的元素ASCII码值大,则跳出循环,返回1,反之,返回-1; 如果一直比较到最后的'\0'都相同,则返回0。
int my_strcmp(char arr1[], char arr2[]) {
assert(arr1 && arr2);
char* s1 = arr1;
char* s2 = arr2;
//如果s1指针指向的元素和s2相同,继续比较下一个元素
while (*s1 == *s2) {
//如果当前字符是字符串结束符'\0',说明到目前为止,两个字符串都相同
//此时可以返回0,表示这两个字符串相同
if (*s1 == '\0') {
return 0;
}
//移动到字符串的下一个字符进行比较
s1++;
s2++;
}
if (*s1 > *s2) {
return 1;
}
else {
return -1;
}
}
int main(){
char arr1[] = "abcdefgh";
char arr2[] = "abc";
int ret = my_strcmp(arr1,arr2); //'d'的ASCII码值比'\0'大,返回1
printf("%d\n",ret);
return 0;
}
另外一种不用指针的解法如下:
int str_cmp(char str1[256],char str2[50]){
int len1 = strlen(str1); //字符串str1的长度
int len2 = strlen(str2); //字符串str2的长度
int k = len1 > len2 ? len2 : len1; //比较两个字符串的长度,找出长度较小的那个字符串
int t = 0; //t表示两个字符串之间的元素相减得到的结果
for(int i = 0; i <= k; ){
t = str1[i] - str2[i];
if(t != 0){ //如果该结果不为0,说明两个字符串之间的元素不相同,跳出循环
break;
}else{
i++; //如果两个字符串对应的字符恰好相等,那么继续往后遍历
}
}
if(t == 0){
return 0; //如果结果为0,说明两个字符串相同,返回0
}else if( t > 0){
return 1; //如果结果大于0,说明str1里面的字符大于str2对应的字符,返回1
}else{
return -1; //如果结果小于0,说明str1里面的字符小于str2对应的字符,返回-1
}
}
5. strstr函数的使用和模拟实现
strstr函数,是用来在一个源字符串中查找目标字符串第一次出现的位置,并且返回指向该字符串的指针,如果没有找到字符串,返回NULL。注意: 字符串的比较匹配不包含'\0'字符,以'\0'作为结束标志
函数原型如下:
char* strstr(const char* str1,const char* str2);
strstr函数的使用:
#include<stdio.h>
#include<string.h>
int main() {
char arr1[] = "Today is a nice day!";
char* S = strstr(arr1, "nice"); //在arr1字符串数组中查找"nice"第一次出现的位置
printf("%s\n", S); //找到了,返回指向该字符串的指针
return 0;
}
执行结果: nice day!
strstr函数的模拟实现:
思路: 我们定义3个指针变量,分别为s1,s2和pcur, pcur用来标记第一次出现str2的位置;s1初始时指向源数组str1,查找在str1中是否有str2; s2初始时指向目标数组str2,将str1数组和str2数组从头到尾进行比较匹配。
代码如下:
char* my_strstr(char arr1[], char arr2[]) {
char* pcur = arr1; //pcur初始时指向arr1
char* s1 = NULL;
char* s2 = NULL;
if (arr2 == '\0') { //如果传递过来的arr2为空,那么直接返回arr1
return arr1;
}
while (pcur != NULL) { //pcur没有遍历完arr1,进入循环
s1 = arr1;
s2 = arr2;
while (*s1 == *s2) { //如果s1指向的元素和s2指向的元素相同,那么继续往后遍历
s1++;
s2++;
}
if (*s2 == '\0') { //如果将字符串arr2都遍历完毕,则返回第一次出现该字符串的位置
return pcur;
}
pcur++; //如果木有找到,继续往后找
}
return NULL; //如果遍历完整个字符串都没有找到字符串arr2,返回NULL
}
int main(){
char arr1[] = "abbbcdefg";
char arr2[] = "bbc";
char* S = my_strstr(arr1,arr2);
printf("%s\n",S);
return 0;
}
写到最后
在这篇文章中,我们学习了一些字符串函数,还有更多的字符串函数等着我们去探索,我将留在下一篇文章。
希望看到这篇文章的友友们,能点赞收藏加关注!!!
非常感谢!!!