【C语言】常见的字符串使用以及易错使用2(strcmp、strncat、strncmp、strstr的使用)

接着上一篇内容继续分享字符串函数的使用

目录

1.strcmp

strcmp的自定义函数模拟实现

2.strncat

3.strncmp

4.strstr

strstr自定义函数模拟实现


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;
}

这就是完整的函数体代码,我们完整的跑一次

模拟成功

希望以上内容对你有所帮助

猜你喜欢

转载自blog.csdn.net/wangduduniubi/article/details/129475645