串函数的模拟实现

一,strstr函数的详解

        strstr函数在串的结构中与实现串的基本的模式匹配功能相似,其中strstr函数的结构框架如下:

char* strstr(char* a1,char* a2)

        其中,strstr函数返回a主串对应的第一个b子串的地址,若匹配失败则返回NULL。下面,我们将运用此函数来求模式串在目标串中的位置并输出主串对应字串往后的字符串

#include
#include
int main()
{
	char a[] = "abcdefdefr";
	char b[] = "def";
	char* t = strstr(a, b);
	//输出b这个子串在a主串中的位置
	fprintf(stdout, "%d\n", t - a);//指针-指针等于两者指向之间元素的个数,即3
	//输出主串对应字串往后的字符串
	fprintf(stdout, "%s", t);//即defdefr
	return 0;
}

         通过运用此函数我们可很方便的求串中有关子串和主串两者的对应关系。在以后的问题如若设计子串和主串的物理关系时,我们都可运用此函数进行快速求解。          

        下面我们来具体深究此函数的功能实现:

        通过以上例子不难发现,此函数的功能与匹配算法如出一辙,只不过在参数返回时需进行调整,若匹配成功则返回子串在主串中位置那个字符的地址,若匹配失败,则返回NULL,即匹配失败。

​
char* my_strstr(char* a1, char* a2)
{
	int i = 0, j = 0;
	while (a1[i] != 0 && a2[j] != 0)
	{
		if (a1[i]==a2[j])
		{
			i++;
			j++;
		}
		else
		{
			i = i - j + 1;
			j = 0;
		}
	}
	if (a2[j] == 0)
		return a1 + i - j;
	else
		return 0;
}

​

二,strtok函数的详解

        strtok函数的结构式如下:

char* strtok(char* str,const char* sep)

        strtok函数是串中的“切割函数”,其中,sep是切割符的集合,str是字符串,strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针,因此,strtok函数会改变str串中的字符,使用时要注意这一点。

strtok函数中串的参数:

1,strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

2,strtok函数的第一个参数为NULL,函数将在同一个串中被保存的位置开始,查找下一个标记。

注意:如若在str串中不存在标记,函数直接返回NULL。

下面为函数的代码功能:

#include
#include
int main()
{
	char str[] = "abc.efdr@qwe?poiu";
	char sep[] = ".@?";//切割符号的集合,以次进行切割
	//第一个切割符为'.',返回在此切割符之前字串的第一个字符的地址
	//第一次我们用str这个字符串, 后面继续往后进行切割只需将str改成NULL
	char* t = strtok(str, sep);//第一次调用,在str串中,将'.'转成了NULL
	fprintf(stdout, "%s\n", t);//输出abc
	//当第二次或第n次使用时,让参数为NULL可以进行上一个继续往后面分割

	t = strtok(NULL, sep);//第二次调用,在str串中,将'@'转成了NULL
	fprintf(stdout, "%s\n", t);//输出efdr
	
	t = strtok(NULL, sep);//第三次调用,在str串中,将'?'转成了NULL
	fprintf(stdout, "%s\n", t);//输出qwe
	
	//因为sep切割符中最后一位默认为\0,即切割符为\0
	t = strtok(NULL, sep);
	fprintf(stdout, "%s\n", t);//输出poiu

	//注意:当用strtok切割完之后,在str串中,切割符就转成了NULL
	fprintf(stdout, "%s", str);//输出abc,因为strtok将切割符变成了NULL
	return 0;
}

        其中,需注意,若第一个串的参数一直为str串中的首元素地址进行输出,因为strtok会将切割符置为NULL,因此,会一值出现第一次切割的子串,代码如下。

#include
#include
int main()
{
	char str[] = "abc.efdr@qwe?poiu";
	char sep[] = ".@?";
	//char* t = strtok(str, sep);//第一次调用,'.'变成NULL,即'\0'
	//fprintf(stdout, "%s\n", t);//输出abc

	第二次调用,因为从str开始,所以在str首个开始往后查找,到了'\0'自动结束
	//t = strtok(str, sep);
	//fprintf(stdout, "%s\n", t);//输出abc
	//
	//t = strtok(str, sep);//第三次调用,同理
	//fprintf(stdout, "%s\n", t);//输出abc

	//t = strtok(str, sep);//第四次调用,同理
	//fprintf(stdout, "%s\n", t);//输出abc

	char* t = NULL;
	//下面为依次输出被分割的子串
	for (t = strtok(str, sep); t != 0; t = strtok(NULL, sep))
	{
		fprintf(stdout, "%s\n", t);
	}
	return 0;
}//总:strtok函数会改变原有的串,在以后使用中要注意,要是不想改变可以再复制一个串

三,strerror函数的介绍

        strerror函数并不重要,也并不常用,我们不需要深入了解,只需会用即可。首先,此函数是报错函数,它返回的是计算机内错误码的首元素地址

      char* strerror(int errnum)

        我们首先对其传参,参数是int型,strerror函数将进行判断是否会出错(提醒一下,错误码是一个字符串,字符也是int型,在计算机内部用ASCII存储)

#include
#include
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		fprintf(stdout, "%d: %s\n", i, strerror(i));
	}
	return 0;
}//此函数常用strerror(errno)形式,其中errno是c中所包含错误码的全局变量

串函数的模拟实现_第1张图片

        用此函数可得出错误码的信息,方便我们在今后的学习中找到具体错误。


四,memcpy函数的详解

        memcpy函数与strcpy函数功能相同,只不过memcpy函数比strcpy函数更为强大,memcpy函数可复制具体的元素个数和复制不同的数据类型。为了方便理解,下面为此函数的优化结构式:

char* memcpy(char* a,char* b,size_t n)//size_t是无符号类型

        其中,memcpy函数将b复制到a中,一共复制n个字节(注意:不是元素个数),返回a所指向首元素的地址。

        注意:此函数功能虽强大,但是它也有一定的缺陷,memcpy函数不能处理重叠的内存拷贝的,通俗来说也就是当a与b的地址部分重合时会发生错误拷贝,例如:a=p,b=p+2,这是a与b的地址部分重叠,将会出现错误。此函数的运用代码如下:

#include
#include
int main()
{
	int a[] = { 1,2,3,4,5,6,7,8,9,0 };
	int b[5] = { 6,5,4,3,2 };
	int i = 0;
	//将b数组复制到a中,一共复制20个字节,函数返回a的首元素地址
	memcpy(a, b, 20);
	for (i = 0; i < 10; i++)
		fprintf(stdout, "%d ", a[i]);
	puts("");
	memcpy(a + 6, a, 12);//会出现差异,因为memcpy函数不能处理重叠的内存拷贝的
	for (i = 0; i < 10; i++)
		fprintf(stdout, "%d ", a[i]);
	return 0;
}

        对于memcpy函数的缺陷可能有部分人有疑问,对此我们要先明白此函数的功能代码是如果具体实现的,代码如下:

char* my_memcpy(char* a, char* b, size_t n)
{
	char* t = a;
	while (n--)
	{
		*a = *b;
		a++;
		b++;
	}
	return t;
}

        可知,当地址重叠时,会把重叠的数据进行复制,所以,会出现不一样的变化。


五,memmove函数的详解

        memmove函数也是用于进行复制的函数,但此函数的功能可以说是最为完美的,它不仅可以进行有限个不同的数据复制,也可以进行重叠的地址进行复制。代码优化结构式如下:

char* memmove(char* a,char* b,size_t n)

        此函数功能与运用跟memcpy相同,唯一需不同的是此函数的功能实现与memcpy不同,代码如下:

char* my_memmove(char* a, char* b, size_t n)
{
	char* t = a, * p = b;
	strcpy(p, b);//进行复制,避免重叠地址使用时发生会乱
	while (n--)
	{
		*a = *p;
		a++;
		p++;
	}
	return t;
}

        由于提前将b数据复制,所以在进行赋值的时候不会发生重叠错误。函数的运用如下:

#include
#include
int main()
{
	int a[20] = { 1,2,3,4,5,6,7,8 };
	int b[10] = { 11,12,14,15 };
	int i = 0;
	//memmove函数功能与形式与memcpy相同,但memmove功能更加强大,可以处理重叠的内存
	memmove(a, a+1, 4*7);//不会出现问题
	for (i = 0; i < 8; i++)
		fprintf(stdout, "%d ", a[i]);
	return 0;
}

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