字符串与字符串函数总结

学习目标:

掌握C语言中的字符串函数的用法及其模拟实现

C中对字符串和字符的处理很是繁琐,但是C语言中并没有字符串类型!字符串通常放在常量字符串吧和字符数组中,其中的字符串常量适用于那些对它不做修改的字符串函数。


学习内容:

长度不受限制的字符串函数strlen、strcpy、strcat、strcmp
长度受限制的字符串函数strncpy、strncat、strncmp
内存操作函数memcpy、memmove、memset、memcmp(下篇文章介绍)
字符串查找函数strstr、strtok
错误信息报告strerror


1:strlen

①:标准格式:size_t strlen ( const char * str );

②:含义:str指向的字符串须以‘\0’作为结束标志,那strlen返回的就是字符串结束标志前面的字符个数。

③:注意事项

     (a):str指向的字符串必须要以‘\0’收尾

     (b):strlen函数返回的是一个unsigned int!!!!

④:经典案例:

#include <stdio.h>
#include <string.h>
int main()
{
	printf("%d\n", strlen("abcdef"));
	return 0;
}

⑤:易错:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	if ((strlen(arr2) - strlen(arr1)) > 0)
		printf("hehe\n");
	else
		printf("gaga\n");
	return 0;
}

问:上述代码打印什么?

结果是hehe,因为无符号整型做表达式运算结果还是无符号整形,那无符号整型只要有二进制位非零就一定是大于0的。

⑥:strlen的模拟实现

法一:(计数法)

#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* s)
{
	assert(s);
	size_t count = 0;
	while (*s != '\0')
	{
		count++;
		s++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

法二:递归

#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* s)
{
	assert(s);
	if (*s != '\0')
		return 1 + my_strlen(s + 1);
	else
		return 0;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

法三:利用指针的减法

#include <assert.h
size_t my_strlen(const char* s)
{
	assert(s);
	char* start = s;
	while (*s != '\0')
		s++;
	return s - start;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d\n", ret);
	return 0;
}

2:strcpy

①:标准格式:char * strcpy ( char * destination, const char * source );

②:含义:从source起拷,拷至‘\0’(包含),从destination起放,最终返回destination.

③:注意事项:

     (a):源字符串必须以'\0’收尾(\0会被一起拷过去哈)

     (b):目标空间要足够的大

  ④:模拟实现:

#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	while (*src != '\0')
	{
		*dest = *src;
		dest++; 
		src++;
	}
	*dest = *src;//拷贝\0
	return ret;
}
int main()
{
	char arr1[] = "********************";
	char arr2[] = "abcdef";
	char* ret = my_strcpy(arr1,arr2);
	printf("%s\n", arr1);
	return 0;
}

    


3:strcat

①:标准格式:char * strcat ( char * destination, const char * source );

②:含义:将源字符串的副本附加到目标字符串后面,destination指向的字符串的末尾的‘\0’会被来追加的source字符串的首字符覆盖,并且追加完后,在“大字符串”的末尾多加一个‘\0’,或者说把源字符串连同它的字符串结束标志一同追加至目标字符串。返回destination。

③:注意事项:

    (a):源字符串末尾须以'\0'结尾

    (b):目标空间要足够的大,要能放得下追加后的“大字符串”

④:模拟实现:

#include <stdio.h>
#include <assert.h>
char* my_strcat(char* destination, const char* source)
{
	assert(destination && source);
	char* ret = destination;
	while (*destination!= '\0')
	{
		destination++;
	}
	while (*source != '\0')
	{
		*destination = *source;
		destination++;
		source++;
	}
	return ret;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "***";
	char* ret = my_strcat(arr2, arr1);
	printf("%s\n", ret);
	return 0;
}

4:strcmp

①:标准格式:int strcmp ( const char * str1, const char * str2 );

②:含义:从str1和str2各自指向的字符开始,逐一比对这两个字符是否相同,有以下情形将退出比对:

   (a):其中一串字符出现'\0'

   (b):两字符比对到出现不同了

③:返回情况:

<0

遇到了不匹配字符,且str1指向的字符的ASCII值小于此时str2

所指向的字符的ASCII值

=0两者逐一比对字符,直至同时到达'\0',功德圆满
>0

遇到了不匹配字符,且str1指向的字符的ASCII值大于此时str2

所指向的字符的ASCII值

④:模拟实现:

#include <stdio.h>
int my_strcmp(const char* str1, const char* str2)
{
	while ((*str1 != '\0') && (*str2 != '\0'))
	{
		if (*str1 == *str2)
		{
			str1++;
			str2++;
		}
		else
		{
			if ((*str1 - *str2) > 0)
			{
				return 1;
				break;
			}
			else
			{
				return -1;
				break;
			}
			
		}
	}
	if ((*str1 - *str2) > 0)
	{
		return 1;
	}
	else if((*str1-*str2)==0)
	{
		return 0;
	}
	else
	{
		return -1;
	}
	
}
int main()
{
	char arr1[] = "abcdeg";
	char arr2[] = "abcdef";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	if (ret == 0)
	{
		printf("两个字符串一样\n");
	}
	else
		printf("两个字符串不一样\n");
	return 0;
}

前述都是无脑式的操作至'\0',那如果现在想操作制定个数字符实现与上述类似的目的,该用哪些库函数?


1:strncpy

①:标准格式:char * strncpy ( char * destination, const char * source, size_t num );

②:将source起数的num个字节的字符拷贝到destination为起始地址的目标空间里头。这里的num的单位是字节!

③:注意事项:source指向的字符串是有长度的,所以num和它比较是有大小之别的,那就有一下两种情况:

   (a):num>source指向字符串的字符个数(包括\0),那此时拷到目标空间除了source指向的字符串(包括\0)之外,在后面补\0至总个数为num个。

   (b):num<source指向字符串的字符个数(包括\0),那此时仅拷num个字节的字符过去,因为char就占一个字节,可以理解为拷num个字节到目标空间,因为num<source指向的字符串个数啊,所以source中的\0并没有拷过去,那此时的destination要足够的长才能使其自身的\0不被覆盖,那就有。相等的话,那就退化为strcpy咯。

④:使用案例:

#include <string.h>
#include <stdio.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "*******";
	strncpy(arr2, arr1, 4);
	printf("%s\n", arr2);//应当打印:abcd***
	return 0;
}

⑤模拟实现:就只是比strcpy多了个字节个数限制而已,思想差不多。不再赘述。


2:strncat

①:标准格式:char * strncat ( char * destination, const char * source, size_t num );

②:在destination指向的字符串末尾追加num个字节的source指向的字符串中的字符。且是从desination指向字符串的字符串结束标志开始追加,所以destination指向字符串的字符串结束标志被覆盖。

③:与strncpy类似有num和source指向字符串的字符个数之间的关系问题:

  (a):num>source指向字符串的字符个数时,仅拷贝source指向字符串(包括\0),后面不拷

  (b):num<source指向字符串的字符个数时,先拷num个字符过去,再多添一个\0

④:使用案例:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[100] = "***********************";
	char* ret = strncat(arr2, arr1, 4);
	printf("%s\n", ret);
	return 0;
}

3:strncmp

①:标准格式:int strncmp ( const char * str1, const char * str2, size_t num );

②:含义:从str1,str2开始逐一比对num字节内容是否一致,返回结果同strcmp

③:使用案例:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcedf";
	int ret = strncmp(arr1, arr2, 4);
	printf("%d\n", ret);
	return 0;
}

字符串查找函数:strstr

①:标准格式:const char * strstr ( const char * str1, const char * str2 );

②:含义:在str1指向的字符串中找str2指向的字符串,且返回第一次找到的首字符地址。找不到返回NULL

③:使用案例:

 ④:模拟实现(代码见下一篇博客),目前先掌握使用。


strtok:(名字我不知道怎么取贴合实际,请看含义理解)

 ①格式:char * strtok ( char * str, const char * delimiters );

②:含义:str指向的字符串中存在0个或多个你想要的使用的分隔符,那如何截取出你使用的分隔符之间的字符串呢?那就使用strtok函数。具体说来就是,从str开始一直往后找到第一个非分隔符的字符作为开始,再往后找至第一个分隔符(也可以找至\0),此时将该分割符修改为\0(此时str指向的字符串被修改,所以说为了保持str指向的字符串最后还能被原样输出,我们最好是对str指向的字符串的临时拷贝来进行strtok的操作),然后干两件事:第一:返回找到的字符串的首字符地址,也就是该函数的返回值。第二:隐式存储该函数被修改为\0的字符的下一个字符的地址。做隐式存储的目的:因为strtok的使用特点是:在str找第一个字符串时,strtok的第一个参数才是str,再往后找下一个字符串时,都是从哪个隐式存储的地址往后找的,此时strtok的第一个参数是NULL!!!,分隔符delimiters一般存在一个字符数组中,要么就是一个字符串常量。

③:strtok何时返回NULL?

(a):上述过程是将\0的地址作隐式存储,那再进行一次strtok,将返回NULL

(b):将\0和面的第一个字符作为了隐式存储(可以这么去记忆),这里是从分隔符找至\0的情况,那再一次strtok将返回NULL

④:使用案例:

 上述属于:以\0的地址做预存地址,且分隔符是一个字符串常量的情况。

上述 属于:以\0后面一个字符地址作预存地址,且分隔符是一个字符串数组的情况。

上述;两个案例都没做临时拷贝,大家记得最好做一下临时拷贝。上述总结是个人理解,也确实能预测该函数的结果。有更好的理解方式,大家可以评论区见。


学习时间:

2021.10.10


学习产出:


1、 技术笔记 2 遍
2、CSDN 技术博客 1篇
3、gitee

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值