接着上一篇内容继续分享字符串函数的使用
目录
1.strcmp
其用于字符串的比较,那比的是什么呢?怎么比呢?直接代码说话
先用条件语句引入,再这里只能比较两个字符串的首字符的地址,并不是字符的内容;
那么真正的字符串比较该怎么比呢?比的是什么呢?
我们先可以看一下关于strcmp的官方讲解
我们看到绿色的那一行规定了它的返回值和参数,参数就是两个字符类型的指针,而返回类型是整形类型,当然我们可以看到下面的表格,两个字符串进行比较,如果说第一个字符串的内容是大于第二个字符串内容的,那么就会返回一个大于零的值,如果说第一个字符串的内容是小于第二个字符串内容,那么就返回一个小于零的值, 如果比较的两个字符串完全相等,那么就会返回零
ok下面一段简单的代码应用一下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bbq";
int ret=strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
其实strcmp函数比较的是字符串的ASCII码值,因为a的ASCII码值小于b,所以就直接可以比出大小,那我们将字符串改成下面这样呢?
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret=strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
可见arr1还是小于arr2,因为'c'的ASCII码值是小于'q'的,
那我们再将'c'改成'q'呢?
int main()
{
char arr1[] = "abqdef";
char arr2[] = "abq";
int ret=strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
此时运行的结果大于零,因为arr1中"abq"比较完之后,后面的字符会和arr2中的'\0'进行比较所以返回值大于零,所以更准确的说比较的是对应位置上字符的ASCII码值,如果相等就比较下一位,直到不相等。
strcmp的自定义函数模拟实现
自定义函数模拟时要注意函数的返回值和参数
int my_strcmp(const char* arr1, const char* arr2)
{
while (*arr1 == *arr2)
{
if (*arr1 == '\0')
return 0;
arr1++;
arr2++;
}
if (*arr1 > *arr2)
return 1;
else
return -1;
}
思路也非常简单
进入函数直接将两个字符串的首元素进行判断,如果相等,就一致往后给他的地址+1;并且继续进行判断,直到不相等为止;但是也要注意的是如果字符串全都相等,就比如arr1中是"abq",而arr2中也是"abq",再往后就会成为\0和\0的比较,所以我们不妨在while语句中在进行判断,如果arr1和arr2中其中一个字符串成为'\0'的话,那么就意味着两个字符串相等,返回值为0;
代码不难看懂 。
到此为止前面讲过的都是长度不受限制的函数;那么这是什么意思呢?
举个例子:
我们使用strcpy拷贝字符内容的时候,时要注意目标空间的大小
但是当我们哪一天敲代码时一不小心忽略了这个问题就会写出bug
int main()
{
char arr1[] = "abcdef";
char arr2[5] = "abc";
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
我们都能看得出来 上面这段代码是有问题的
代码虽然报错了,但是还是将拷贝的内容成功的打印在了频幕上
所以这也是我们使用这些函数时Visual Studio编译器会警告我们这些函数不安全的原因,所以要在Visual Studio中使用这些函数,必须要在开始的部分宏定义
#define _CRT_SECURE_NO_WARNINGS 1
加上这段代码便可以使用上述函数。
所以我们更安全的函数是长度受限制的函数,比如strncpy、strncmp、strncat,注意就是在str后添加了一个n,这样函数就受限制了;
当我们了解这样的函数时
我们就会发现长度受限制的函数就多了一组参数
那么的size_t num意思就是要操作多少个字节的数据,注意单位是字节;
用代码测试一下这样类型的函数
注意代码中使用的函数已经是strncpy,并且在最后的参数中输入了想要拷贝的字节数,最后的结果就是将abc拷贝到arr2中去
2.strncat
那么strncat与strcat使用时的区别就是加上了要追加的字符个数,
我们可以看到追加三个字节,就只打印了abc
我们调试来更深一步的研究他追加的情况
将arr1字符串中手动添加\0以便于观察,现在这是未追加前的arr1中数组的数据
下面是追加后的arr1数组中的数据
我们可以看到追加确实是从\0开始追加,但是追加完后,会自动补上\0,不管她有没有将字节全部追加完。
3.strncmp
也是同样的用法,只不过多了一个要比较多少字节的参数;
代码举例
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "abcq";
int ret=strncmp(arr1,arr2,4);
printf("%d\n",ret);
return 0;
}
只比较了前四个字节的数据,d小于q,所以输出-1
4.strstr
先观察一下函数的返回类型 和函数的参数,返回类型和参水都是char*类型的指针
下面上代码简单解释一下此函数的作用
#include<stdio.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bcd";
char *p=strstr(arr1, arr2);
if (p == NULL)
{
printf("没找到\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
这个函数的作用就是在arr1的字符串中寻找arr2字符串第一次出现在arr1中的位置
这个指针p存放的是第一次找到的首元素的地址,也就是上段代码中b的地址,所以就会打印出bcdef;
那我们将arr1的字符串内容改变
可以看到找到的是第一次出现的地址。
strstr自定义函数模拟实现
我们都知道这两个函数的参数是指针类型,分别指向arr1和arr2中的首元素的地址;但是地址中的内容是有所不同的,这就需要arr1中的内容向后查找与arr2中的指针内容相等,当查找到相同元素的时候,arr2的指针也开始向后移动,那么既然是要在arr1中查找arr2,arr2指针就要移动到'\0'处,同时arr1指针与arr2指着同时移动,这样便能查找到相同字符串。
但是
上述的情况是只需要查找一次便能查找到,如果我们将arr1和arr2数组总的内容改成以下代码要怎样查找呢?
char arr1[] = "abbbcdef";
char arr2[] = "bcd";
在这种情况时,如果按照以上说法在arr1查找arr2,因为arr1中的第二个元素和arr2中的第一个元素相同,那么指针在arr1中找到第二个元素便会向后查找,结果还差找不到,所以我们需要记住与查找字符串中首元素的地址,即使在arr1中只找到了与查找字符串中的第一个字符但后面的元素不同,我们只需回到记住的地址就可以继续向后查找。
接下来就是函数体内容
char* my_strstr(const char* arr1, const char* arr2)
{
char* s1 = NULL;
char* s2 = NULL;
}
首先创建两个空指针用来代替指针arr1和指针arr2,防止直接操作arr1和arr2使地址离起始位置太远;
接下来用以下两个字符串简单思考一下
"abcdef"
"bcd"
当我们进入到这两个字符串的首元素时,就已经有可能匹配上了,我们不妨再定义一个char *类型的指针char *cp,用来指向'a',作用和arr1相同;
接下来我们s1和s2拿出来引用,意思就相当于从'a'开始就i有可能查找成功,所以让s1向后进行查找;s2作用同样,从'b'的位置向后开始查找;
char* my_strstr(const char* arr1, const char* arr2)
{
char* s1 = NULL;
char* s2 = NULL;
char* cp = arr1;
s1 = cp;
s2 = arr2;
}
接下来就开始while循环
如果*s1和*s2相等,s1向后挪动,同样的s2也向后挪动
那如果*s1和*s2不相等,那就使cp指针向后挪动一位,使s1和cp在同一位置上继续向后进行查找;
那这样要一直查找到arr1字符串结束,我们则不妨将其放入循环中
代码如下
char* my_strstr(const char* arr1, const char* arr2)
{
char* s1 = NULL;
char* s2 = NULL;
char* cp = arr1;
while (*cp)
{
s1 = cp;
s2 = arr2;
while (*s1 == *s2)
{
s1++;
s2++;
}
cp++;
}
}
还需要注意的是我们在遍历arr2字符串时,已经遇到'\0'了,那么这个循环就没要必要再继续循环下去了;那我们不妨再while循环中再加入判断
char* my_strstr(const char* arr1, const char* arr2)
{
char* s1 = NULL;
char* s2 = NULL;
char* cp = arr1;
while (*cp)
{
s1 = cp;
s2 = arr2;
while (*s1&&*s2&&*s1 == *s2)
{
s1++;
s2++;
}
cp++;
}
}
那么加再while循环中的判断意思就是说当*s1已经走到'\0'了还没有找*s2,那这个循环就没有走下去的必要,所以*s1=0循环可以停下来;*s2=0时,循环可以停下来;
*s1不等于*s2时,也可以停下来;
但是有一个很敏感的条件是当*s2='\0'时,说明已经把想要查找的字符串已经便利完了;所以还要加入if语句进行判断;但是如果上述条件都不满足,那自能返回空指针了;
char* my_strstr(const char* arr1, const char* arr2)
{
char* s1 = NULL;
char* s2 = NULL;
char* cp = arr1;
while (*cp)
{
s1 = cp;
s2 = arr2;
while (*s1&&*s2&&*s1 == *s2)
{
s1++;
s2++;
}
if(*s2=='\0')
{
return cp;
}
cp++;
}
return NULL;
}
这就是完整的函数体代码,我们完整的跑一次
模拟成功
希望以上内容对你有所帮助