C标准库 string.h (三) 查找函数

string.h 查找函数

  • memchr 内存中查找
  • strchr 字符串中查找
  • strrchr 字符串中反向查找
  • strstr 字符中查找字符串
  • strtok 根据标识(token)查找字符串
  • strspn 范围之内查找,返回下标
  • strcspn 范围之外查找,返回下标
  • strpbrk 同strcspn,返回指针

其中,部分手痒自己实现过,而函数标准库的写法已然足够,就没有画蛇添足。
关于strspn的BUG详细部分回头会补充。

memchr

memory character

内存中查找,参数void *适合各种数据类型,不过只能查找一个字节(按照标准库我们可以看出来,虽然c是int类型,不过比较却是一个字节一个字节的)。


#include <stdio.h>
#include <string.h>

/*
	自实现
*/
void *_memchr(const void *s, int c, size_t n)
{
	const unsigned char *pstr = s;
	const unsigned char search = (unsigned char)c;

	while(n-- > 0)
	{
		if (*pstr == search)
		{
			return (void *)pstr;
		}
		pstr++;
	}

	return NULL;
}

/*
	标准库
*/
void *memchr(const void *s, int c, size_t n)
{
	const unsigned char uc = c;
	const unsigned char *su;

	for (su = s; 0 < n; ++su, --n)
		if (*su == uc)
			return ((void *)su);
	return (NULL);
}

int main(int argc, char const *argv[])
{
	char *p;
	p = _memchr("hello world", 'w', 8);
	printf("%sn", p);
	return 0;
}

使用for循环可以将循环的变量纳入语言结构,写起来更加简洁。

strchr

string character

字符串中查找字符,并返回这个字符第一次出现的地址


#include <stdio.h>
#include <string.h>

/*
	自实现
*/
char *_strchr(const char *s, int c)
{
	const unsigned char *pstr = s;
	const unsigned char search = (unsigned char)c;

	while(*pstr != '\0')
	{
		if (*pstr == search)
		{
			return (char *)pstr;
		}
		pstr++;
	}
	return NULL;
}

/*
	标准库
*/
char *strchr(const char *s, int c)
{
	const char ch = c;

	for (; *s != '\0'; ++s)
		if (*s == '\0')
			return NULL;
	return ((char *)s);
}

int main(int argc, char const *argv[])
{
	char *p;
	p = _strchr("hello world", 'o');
	printf("%sn", p);
	return 0;
}

自实现显得有些不上档次,不过可以给新手当个参考就保留了。

strrchr

string reverse character

字符串反向查找字符,返回这个字符最后一次出现的位置


#include <stdio.h>
#include <string.h>

/*
	自实现
*/
char *_strrchr(const char *s, int c)
{
	const unsigned char *pstr = NULL, search = (unsigned char)c;

	do
	{
		if (*s == search)
		{
			pstr = s;
		}
	} while (*s++);

	return (char *)pstr;
}

/*
	标准库
*/
char *strrchr(const char *s, int c)
{
	const char ch = c;
	const char *sc;

	for (sc = NULL; ; ++s)
	{
		if (*s == ch)
			sc = s;
		if (*s == '\0')
			return ((char *)sc);
	}
}

int main(int argc, char const *argv[])
{
	char *p;
	p = strrchr("hello world", 'o');
	printf("%sn", p);
	return 0;
}

标准库循环完了居然不返回NULL 值得吐槽

strstr

string string

字符串中查找字符串,如果能找到则返回其地址找不到则返回NULL


#include <stdio.h>
#include <string.h>

char *_strstr(const char *s1, const char *s2)
{
	while ( (s1 = strchr(s1, *s2)) != NULL )
		if(strcmp(s1, s2) == 0)
			return (char *)s1;
		else
			s1++;
	return NULL;
}

char *strstr(const char *s1, const char *s2)
{
	if(*s2 == '\0')
		return ((char *)s1);
	for( ; (s1 = strchr(s1, *s2)) != NULL; ++s1)
	{
		const char *sc1, *sc2;

		for(sc1 = s1, sc2 = s2; ; )
			if(*++sc2 == '\0')
				return ((char *)s1);
			else if(*++sc1 != *sc2)
				break;
	}
	return NULL;
}

int main(int argc, char const *argv[])
{
	printf("%sn", _strstr("that this think", "think"));
	return 0;
}

博主直接偷懒用了strcmp, 不过标准库的写法貌似对编译器有要求,如果是老版本的,变量是需要定义在函数开头的不能定义在函数中间,比如这里的for循环中。

strtok

string token

通过标识来查找字符串。需要注意的是这个会修改原来字符串的值。并且要获得标识前后的值需要两次调用。如果标识多次出现的话那么也需要多次调用该函数。


#include <stdio.h>
#include <string.h>

// Finding Tokens in a String

char * strtok(char *s1, const char *s2)
{
	char *sbegin, *send;
	static char *ssave = "";

	sbegin = s1 ? s1 : ssave;
	// printf("1.sbegin: %sn", sbegin);
	// printf("2.strspn(sbegin, s2): %dn", strspn(sbegin, s2));
	sbegin += strspn(sbegin, s2);
	if (*sbegin == '\0')
	{
		ssave = "";
		return NULL;
	}

	// printf("3.sbegin: %sn", sbegin);

	send = sbegin + strcspn(sbegin, s2);
	// printf("4.sbegin: %sn", sbegin);
	// printf("5.send: %sn", send);
	
	if (*send != '\0')
		*send++ = '\0';

	ssave = send;
	// printf("6.send: %sn", send);
	return (sbegin);
}

int main(int argc, char const *argv[])
{
	char input[] = "program,hello,world";
	char *p;

	/* 截取到第一个标识符之前 */
	p = strtok(input, "e");
	if(p)
	{
		printf("%sn", p);
	}
	/* 截取第一个标识符之后一段 */
	p = strtok(NULL, "e");
	if(p)
	{
		printf("%sn", p);
	}

	// 源字符串被截断
	printf("最后input : %s", input);
	return 0;
}

输出结果:

program,h
llo,world
最后input : program,h

strspn

string span

span 范围,比较范围内相同的字符串, 命名为早期VAX指令的风格。
字符串范围查找,按照下方函数定义,在s1中找s2,情况是从s1的开头依次与s2比较,返回第一个与s2不同的字符下标


#include <string.h>
#include <stdio.h>

// 函数说明 strspn 返回字符串中第一个不在指定字符串中出现的字符下标

size_t _strspn(const char *s1,const char *s2)
{
	const char *sc1 = s1, *sc2 = s2;

	for(sc1 = s1, sc2 = s2; *sc1 != '\0'; ++sc1, ++sc2)
		if (*sc2 == '\0')
			return (sc1 - s1);
		else if (*sc1 == *sc2)
			continue;
		else
			break;
	return sc1 - s1;
}

size_t strspn(const char *s1,const char *s2)
{
	const char *sc1, *sc2;

	printf("sc2: [%s] ", s2);

	for(sc1 = s1; *sc1 != '\0'; ++sc1)
		for (sc2 = s2; ; ++sc2)
			if (*sc2 == '\0')
				return (sc1 - s1);
			else if (*sc1 == *sc2)
				break;
	return (sc1 - s1);
}

int main(int argc, char const *argv[])
{
	char *str = "what do you think about this this program? 1";
	printf("%dn", _strspn(str,"w"));
	printf("%dn", _strspn(str,"what"));
	printf("%dn", _strspn(str,"what "));
	printf("%dn", _strspn(str,"what d"));
	printf("%dn", _strspn(str,"what do"));
	printf("%dn", _strspn(str,"what do "));
	printf("%dn", _strspn(str,"what do y"));
	printf("%dn", _strspn(str,"what do yo"));
	printf("%dn", _strspn(str,"what do you"));
	printf("%dn", _strspn(str,"you"));
	printf("%dn", _strspn(str,"1234567890"));
	return 0;
}

关于该函数的BUG,详细回头补上

strcspn

string complement span

complement 补集,可以理解成 strspn 的补函数。
在s1中依次比较每个字符是否s2在中出现过,如果该字符在s2中出现过,则返回该字符在s1中的下标。


#include <stdio.h>
#include <string.h>

// 功能:顺序在字符串s1中搜寻与s2中字符的第一个相同字符,包括结束符NULL,返回这个字符在S1中第一次出现的位置。

/*
	标准库
*/
size_t strcspn(const char *s1,const char *s2)
{
	const char *sc1, *sc2;

	for (sc1 = s1; *sc1 != '\0'; ++sc1)
		for(sc2 = s2; *sc2 != '\0'; ++sc2)
			if (*sc1 == *sc2)
				return (sc1 - s1);
	// 返回NULL,即字符串结束
	return (sc1 - s1);
}


int main(int argc, char const *argv[])
{
    char *str = "Linux was first developed for 386/486-based pcs. ";
    printf("字符串长度为 %dn", strlen(str));
    printf("%dn", strcspn(str, " "));
    printf("%dn", strcspn(str, "/-"));
    printf("%dn", strcspn(str, "1234567890"));
    printf("%dn", strcspn(str, ""));
	return 0;
}

执行结果:

字符串长度为 49
5	// 只计算到" "的出现, 所以返回"Linux"的长度
33	// 计算到出现"/"或"-", 所以返回到"6/486"之前的长度
30	// 计算到出现数字字符为止, 所以返回"386"出现前的长度

strpbrk

string pointer break

早期的命名风格,这里可以理解为找到目标(string)中的字符后中断(break)并返回其地址(pointer),其功能与strcspn相同,区别只是strpbrk返回的是地址。

可查阅资料:
MSDN: strPBrk
GNU:(推荐) strpbrk


#include <stdio.h>
#include <string.h>

/*
	依次检验字符串s1中的字符,当被检验字符在字符串s2中也包含时
	则停止检验,并返回该字符地址,空字符NULL不包括在内。
*/

/*
	标准库
*/
char * strpbrk(const char * s1,const char * s2)
{
	const char *sc1, *sc2;

	for(sc1 = s1; *sc1 !='\0'; ++sc1)
		for(sc2 = s2; *sc2 !='\0'; ++sc2)
			if(*sc1 == *sc2)
				return ((char *)sc1);
	return NULL;
}

int main(int argc, char const *argv[])
{
	char *s1="Welcome To Beijing";
	char *s2="BIT";
	char *p;

	p = strpbrk(s1,s2);
	if(p)
		printf("%sn",p);
	else
		printf("Not Found!n");

	p = strpbrk(s1, "Daj");

	if(p)
		printf("%s",p);
	else
		printf("Not Found!n");

	return 0;
}

Advertisements

One thought on “C标准库 string.h (三) 查找函数

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s