C语言常见字符串库函数的使用与实现

Posted 蓝乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言常见字符串库函数的使用与实现相关的知识,希望对你有一定的参考价值。

字符串有关库函数介绍及使用

简述

在这里插入图片描述

1.strlen的使用及实现

strlen函数是用于计算字符串长度的函数,字符串是以’\\0’作为结束标志的,故strlen计算第一次遇到’\\0’前的字符个数。
strlen函数的实现方式有三种:
1.计数器法
通过count变量来统计字符串中’\\0’前的字符个数

int my_strlen(const char* str)
{
	assert(str);//避免对NULL解引用
	int count = 0;
	while (*str++)
	{
		count++;
	}
	return count;
}

2.递归法
不借助临时变量通过递归找到’\\0’并返回其前字符个数

int my_strlen(const char* str)
{
	assert(str);
	if (*str == '\\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

3.指针-指针法
由于指针与指针的差是两指针间的元素个数,故通过指针作差可以计算字符串的长度

int my_strlen(const char* str)
{
	assert(str);
	char* start = (char*)str;
	char* end = (char*)str;
	while (*end)
	{
		end++;
	}
	return end - start;
}

【注意】
1.由于字符串是以’\\0’为结束标志的,故以下两个语句之间有区别:

int main()
{
	char str1[] = "never give up";
	char str2[] = { 'a','b','c' };
	printf("%d\\n", my_strlen(str1));
	printf("%d\\n", my_strlen(str2));
	return 0;
}

在这里插入图片描述
对于str1其在字符串末尾隐藏了’\\0’,而对于str2,由于不确定’\\0’的位置,因此所求出的字符串长度是随机值。
2.库中strlen函数的形式为:size_t strlen ( const char * str );其返回类型是size_t,即无符号整形,因为其认为字符串函数是非负的,但这可能在实际使用中出现问题,比如strlen(“abc”) - strlen(“abcdef”)是大于0的(因二者皆为无符号整形,始终非负)。

2.strcmp的使用及实现

int strcmp ( const char * str1, const char * str2 );

strcmp函数是依次比较字符串中的字符的函数,若字符相同则返回0,遇到第一个不相同的字符,则比较其ASCII码值,str1大于str2则返回大于0的数,str1小于str2则返回小于0的数。
函数的实现非常简单:

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)//判断两字符串是否相等
	{
		if (*str2 == '\\0')//相等则返回0
		{
			return 0;
		}
		else
		{
			str1++;
			str2++;
		}
	}
	if (*str1 > *str2)
	{
		return 1;
	}
	else
		return -1;
}

3.strcpy的使用及实现

char * strcpy ( char * destination, const char * source );

将source所指向的字符串拷贝到destination中。

int main()
{
	char str1[] = "################";
	char str2[] = "never give up";
	my_strcpy(str1, str2);
	printf("%s\\n", str1);
	return 0;
}

在这里插入图片描述
函数实现也相对简单:

char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;//记录下目的字符串首字符的地址并返回
	while (*dest++ = *src++)//将*src赋值给*dest
	{
		;
	}
	return ret;
}

4.strcat的使用及实现

char * strcat ( char * destination, const char * source );

将source所指向的字符串追加到destination所指向的字符串后。

int main()
{
	char str1[30] = "never ";
	char str2[] = "give up";
	my_strcat(str1, str2);
	printf("%s\\n", str1);
	return 0;
}

在这里插入图片描述
代码实现:

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* cp = dest;
	while (*cp)//cp指向dest所指字符串中'\\0'的位置
	{
		cp++;
	}
	while (*cp++ = *src++)//将src所指向字符串拷贝到cp所指向的字符串中
	{
		;
	}
	return dest;
}

5.strstr的使用及实现

char * strstr ( const char *str1, const char *str2 );

判断str2是否在str1中出现,即str2是否为str1的子串,若是,则返回str2在str1中首次出现的字符地址,否则返回NULL。

int main()
{
	char str1[] = "abbbcdef";
	char str2[] = "bbc";
	printf("%s", my_strstr(str1, str2));
 	return 0;
}

在这里插入图片描述
函数的实现需要引入三个临时变量,s1与s2比较判断s2是否与s1相同,cp记录当前比较的第一个字符的位置,遍历cp即可比较str2是否在str1中出现在这里插入图片描述

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	char* s1 = NULL;//不改变str1和str2的指向
	char* s2 = NULL;//保留模式串str2
	char* cp = (char*)str1;
	while (*cp)//cp遍历str1
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 == *s2 && *s1 && *s2)
		{
			s1++;
			s2++;
			if (*s2 == '\\0')//s2遍历
				return cp;
		}
		cp++;
	}
	return NULL;
}

在使用strcat时并不能让字符串自己追加到自己之后,因为这样做会让’\\0’被覆盖以至于无法找到结束标志而进入死循环,因此需要strncat函数来实现这个功能,同时strncat函数作为长度受限制的函数,在一定程度上防止了越界的出现,使代码相对安全。

6.strncat的使用及实现

char * strncat ( char * destination, const char * source, size_t num );
在destination所指向的字符串末尾加上num个source所指向的字符串的字符。

int main()
{
	char str1[30] = "never ";
	char str2[] = "give up";
	my_strncat(str1, str2, 4);
	printf("%s\\n", str1);
	return 0;
}

在这里插入图片描述
函数的实现与strcat类似,只是需要分num大于str2所指向的字符串的长度和num小于两种情况:

char* my_strncat(char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);
	char* cp = str1;
	while (*cp)//cp遍历str1至'\\0'
	{
		cp++;
	}
	while (num--)//将str2中num个字符拷贝到str1中,若num大于str2字符串长度,则将str1之后的一个字符置为'\\0'
	{
		*cp++ = *str2++;
		if (*str2 == '\\0')
			return str1;
	}
	*cp = '\\0';
	return str1;
}

在strcpy函数中,如果str2的长度大于str1,则会出现越界,因此为了保证代码的安全行,需要strncpy函数来限制字符串的长度。

7.strncpy的使用及实现

char * strncpy ( char * destination, const char * source, size_t num );

strncpy函数的功能是将source所指向的字符串中num个字符拷贝到destination所指向的字符串中

int main()
{
	char str1[] = "#################";
	char str2[] = "never give up";
	my_strncpy(str1, str2, 14);
	printf("%s\\n", str1);
	return 0;
}

在这里插入图片描述
strncpy函数的实现也与strcpy类似:

char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* cp = dest;
	while (num && (*cp++ = *src++))//将src字符串中的num个字符拷贝到cp中
	{
		num--;
	}
	while (num)//若num人大于0,则将cp中接下来的num个字符置为'\\0'
	{
		*cp++ = '\\0';
		num--;
	}
	return dest;
}

8.strncmp的使用及实现

int strncmp ( const char * str1, const char * str2, size_t num );

strncmp顾名思义,就是比较str1和str2中前num个字符,比较规则与strcmp相同。

int main()
{
	char str1[] = "never give up";
	char str2[] = "never get mad";
	int ret = my_strncmp(str1, str2, 7);
	printf("%d\\n", ret);
	return 0;
}

在这里插入图片描述
strncmp函数的实现与上面两个长度受限制的字符串函数类似:

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);
	while (*str1 == *str2 && num)//str1与str2相等或num不为0是进入循环
	{
		str1++;
		str2++;
		num--;
		if (*str2 == '\\0' || num == 0)//num等于0或str2与str1已比较完成说明二者相同,返回0
			return 0;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}

9.strtok的使用

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

strtok函数是一个不怎么常见的库函数,它的作用是:
a)第一个参数指定一个字符串,该字符串包含了0个或多个有srp字符串中一个或者多个分割符分割的标记。
b)strtok函数找到str中的下一个标记,并将其用 \\0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
c)strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
d)strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
e)如果字符串中不存在更多的标记,则返回 NULL 指针。
上面还是有些抽象,下面用一段代码来介绍一下这个函数:

#include <string.h>

int main()
{
	char str[] = "1506536196@qq.com";
	char* sep = "@.";
	char tmp[30];
	char* cp = NULL;
	strcpy(tmp, str);//将str拷贝一份到tmp中,避免strtok将str中的数据修改
	for (cp = strtok(tmp, sep); cp; cp = strtok(NULL, sep))
	{
		printf("%s\\n", cp);
	}
	return 0;
}

在这里插入图片描述
第一次调用strtok函数时第一个参数传的是要分割的字符串,之后strtok函数会保留已经分割过的字符串因此第一个参数只需要传NULL即可,故使用strtok函数可以用一个for循环语句,初始化条件为将strtok返回的地址赋给接收的cp指针,结束条件为cp不为NULL,调整部分即为将NULL作为参数传给strtok函数,再将返回值赋给cp指针,for循环体内打印出被分割的字符串。

10.strerror的使用

char * strerror ( int errnum );

strerror函数的作用是:返回错误码所对应的错误信息。

# include <string.h>
# include <errno.h>

int main()
{
	printf("%s\\n", strerror(0));
	printf("%s\\n", strerror(1));
	printf("%s\\n", strerror(2));
	printf("%s\\n", strerror(3));
	printf("%s\\n", strerror(4));
	printf("%s\\n", strerror(5));
	printf("%s\\n", strerror(6));
	printf("%s\\n", strerror(7));
	printf("%s\\n", strerror(8));
	printf("%s\\n", strerror(9));
	printf("%s\\n", strerror(10));
	return 0;
}

在这里插入图片描述
strerror函数的应用在判断一些操作的错误类型时能起到很好的效果,比如在程序未达到预期的效果时,可以通过strerror来判断错误的原因,比如:
想打开text.txt文件时,没用达到预期效果,可以调用该函数来查找原因
在这里插入图片描述

以上是关于C语言常见字符串库函数的使用与实现的主要内容,如果未能解决你的问题,请参考以下文章

c语言深入浅出,玩爆常见字符串,内存操作库函数(爆肝最长时间之作)

用 C 语言开发一门编程语言 — 函数库的设计与实现

能列举些C语言中比较常见重要库函数的用法吗?

c语言重要库函数解读 和模拟实现————常用字符函数

C语言数据输入与输出

C语言数据输入与输出