字符串函数(二)

一.长度受限制的字符串函数

上一小节介绍了一些长度不受限制的字符串函数,但是,那些函数是不太安全的。例如,在strcpy函数在复制的时候是不会考虑目标字符数组能否放的下源字符串,可能会存在越界访问。因此,推出了一些长度受限制的字符串函数,使用起来也相对安全一些。

1.strncpy函数及模拟实现

strncpy函数与strcpy功能相似,唯一的区别就是多了一个参数num。num表示从源字符串中拷贝num个字符到目标地址,如果num超过了源字符串的长度,多出来的部分就补'\0'。

这里给大家举了个例子:

字符串函数(二)_第1张图片

可以看到在复制完hello之后,还拷贝了2个'\0'。

下面我们对这个函数模拟实现(原理其实和strcpy类似):

还是上面那个例子

字符串函数(二)_第2张图片

2.strncat函数及模拟实现

同样的,strncat依然只是比strcat函数多了一个参数num。num是从源字符串中拷贝num个字符追加到目标字符串的后面(包括'\0')。

下面举个简单的例子帮助大家理解一下:

字符串函数(二)_第3张图片

可以看到hello找到了第一个'\0'的位置,并将其覆盖,从这里向后追加字符串。且当num大于源字符串的长度时,只会追加一个'\0',这一点是和strncpy不同的。特别的,如果num小于源字符串的长度,则会在追加完成之后,单独再加一个'\0'.

下面我们模拟实现一个这样的函数:

字符串函数(二)_第4张图片

3. strncmp函数及模拟实现

同理,这里就不多阐述,依旧是多了一个参数num。

下面我们简单举个应用的例子:

字符串函数(二)_第5张图片

字符串函数(二)_第6张图片

在这里看以看到两次的字符串是相同的,但比较的字符的个数发生变化导致最后返回的结果也因此而改变。

下面我们模拟实现这样的功能:

#include
int my_strncmp(char* p1, char* p2, size_t num)
{
	while (num--&&*p1++&&*p2++)
	{
		if (*p1 > *p2)
		{
			return 1;
		}
		if (*p1 < *p2)
		{
			return -1;
		}
	}
	if(*p1&&*p2||(*p1 == *p2 && *p1 == '\0'))
	return 0;
	if(*p1 == '\0'&&*p2)
		return -1;
	if(*p2 == '\0'&&*p1)
		return 1;
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "abcdefghi";
	int sz=my_strncmp(arr1, arr2,5);
	printf("%d", sz);
	return 0;
}

4.strstr函数及模拟实现

字符串函数(二)_第7张图片

strstr函数的功能是从str1字符串中找str2字符串,并返回str2字符串在str1中第一次出现的位置,如果找不到,就返回NULL。 

下面我们简单运用一下这个函数:

字符串函数(二)_第8张图片

可以看到打印时是从def开始向后打印的。同时,要注意检查是否返回的是NULL。

下面我们介绍两种模拟实现这个函数的方法:

4.1暴力求解(BF算法)

#include
#include
char* my_strstr(const char* p1,const char* p2)
{
	char* cur = p1;
	char* ptr1 = NULL;
	char* ptr2 = NULL;
    assert(p1&&p2);
	while (*p1)
	{
		ptr1 = cur;
		ptr2 = p2;
		while (*ptr1&&*ptr2&&*ptr1++ == *ptr2++)
		{
			;
		}
		if (*p2)
		{
			return cur;
		}
		cur++;
	}
	return NULL;
}

4.2kmp算法

KMP算法的核心就是:利用匹配失败之后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的效果,具体是通过一个next数组来实现,这个数组包含了模式串的局部匹配信息,时间复制度为O(m+n)。

#include
#include
#include
#include
void Getnext(int* n,char*p)
{
	n[0] = -1;
	n[1] = 0;
	int i = 2;
	int k = 0;
	for (; i < strlen(p);)
	{
		if (k==-1||p[i - 1] == p[k])
		{
			n[i] = k + 1;
			i++;
			k++;
		}
		else
		{
			k = n[k];
		}
	}
}
int	kmp(char*p1,char* p2,int pos)
{
	assert(p1 && p2);
 	int str1 = strlen(p1);
	int str2 = strlen(p2);
	if (*p1=='\0' || *p2=='\0')
		return -1;
	if (pos<0 || pos>str1)
		return -1;
	int* next = (int*)malloc(str2 * sizeof(int));
	assert(next);
	Getnext(next,p2);
	int i = pos;
	int j = 0;
	while (p1[i] && p2[j])
	{
		if (j == -1 || p1[i] == p2[j])
		{
			i++;
			j++;
		}
		else 
		{
			j = next[j];
		}
	}
	if (j >= str2)
		return i - j;
	else
		return -1;
}
int main()
{
	char arr1[20] = "abcdefabcdef";
	char arr2[] = "def";
	printf("%d\n",kmp(arr1,arr2,0));
	return 0;
}

通过上面的代码我们可以找到arr2在arr1中第一次出现的下标3。 这种算法在时间复杂度上会理想很多。

本节的内容就此结束,感谢您的观看!

公主王子们请点赞关注加收藏!

 

你可能感兴趣的:(java,算法,数据结构)