重要的字符(串)函数的使用及其实现

目录

字符串函数注意点

1、\0

2、适当使用const修饰

3、多使用assert断言

4、库函数不可能完全安全

1、求字符串长度strlen

 1、计数实现

2、递归实现

3、指针相减求元素个数

2、长度不受限制的字符串函数

1、strcpy

2、strcat

3、strcmp

3、长度受限制的字符串函数(字符函数)

1、strncpy

2、strncat

 3、strncmp

字符串函数注意点

1、\0

对于字符串来说,重要的是结束标志\0,在实现字符串函数时,要时刻考虑\0的影响。

是否要用\0标记某个位置,或者是否需要在最后补充一个\0。

2、适当使用const修饰

当我们给函数传入数组名时,若我们并不想修改这个数组的内容,可以在接收的指针前加上const来修饰,即保护我们的数组内容不被错误修改。

3、多使用assert断言

当代码量较大时,作为程序员我们是有可能传入一个空指针给函数的,如果我们在函数中对这个空指针解引用,非法访问一些空间,会使程序产生错误,但编译器往往无法精准定位到这个错误。    因此,出于我们自身考虑,多使用assert可减轻我们回头检查bug的负担,是一个编程好习惯。

4、库函数不可能完全安全

当我们完成一个库函数时,总能想到一些特殊的例子,导致库函数产生不安全的影响。也就是说,当一个喝醉酒的程序员写bug时,我们是拦不住的。

1、求字符串长度strlen

 1、计数实现

2、递归实现

3、指针相减求元素个数

刚学指针时我们知道,当两个指针指向相同的一块空间,且指针类型相同时,指针相减的绝对值是两个指针之间元素的个数。

总结:

1、求字符串长度时不用修改数组内容,或者当这个字符串为常量字符串时,它本身不能被修改,所以可用const来修饰。

2、求字符串长度len本身是一个非负的数,所以库函数中使用的是size_t返回类型,但是我们如果返回int也可以实现。同时,由于size_t的结果不能为负数,在进行进一步运算时,可能会产生错误

int main()
{
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;

3、字符串函数的实现是到\0停止计数,且\0不算在内。注意与sizeof区别,sizeof是操作符,可通过类型返回一个确定的值。而strlen若找不到\0,就会一直找,导致产生随机值或error。

2、长度不受限制的字符串函数

1、strcpy

注意:dest不能与src在内存上有所重叠,否则拷贝的过程中src可能会被修改,导致结果错误。

 为保证目的地接收拷贝后仍为一个字符串,我们在涉及函数时需要拷贝完src的内容后补加\0

同时arr1所占空间大小必须大于arr2

 *dest++=*src++表达式的值为*src,当*src为\0时停止,即把\0补到拷贝字符串后面了。

注意:这里是后置++,赋值完\0后,src指向的是\0下一个字符,但我们不去访问,并不影响函数实现。 

2、strcat

注意:dest找到\0后覆盖,将src的\0也追加过去。

dest和src不能重叠,这是因为找到dest的\0覆盖后,src就失去了结束标志\0,导致追加过程死循环

这里必须保证arr1空间内容足够大,能够接收arr2的追加。

这里我们注意到,\0也会被追加过去。 

3、strcmp

 

注:比较的是第一个不同的字符的ASCLL码值的大小,不是字符串的长度。

只要相等,就继续比,有一个是\0即俩都是,return0,。不相等跳出来返回相应值。 

总结:长度不受限制的字符串是整体操作两个字符串,是有可能因为数组内存空间不够用,而造成非法访问的,从某种意义上来说是不够安全的。因此产生了下面长度受限制的字符串函数。即多引入一个参数n,控制src中操作字符串的长度,使其安全性提高。

3、长度受限制的字符串函数(字符函数)

1、strncpy

将src的前n个拷贝到dest,若n比src长,拷贝后继续补\0,若src比dest会导致溢出,也不是绝对安全。

  拷贝数超过dest溢出报错。

用int类型接收也可以完成功能。

2、strncat

 追加完要再补一个\0。若src长度不够,就全追加过去即可。

 

 3、strncmp

相比strcmp,多了一个与n个字符匹配就相同条件。

int my_strncmp(const char* p1, const char* p2, int k)
{
	assert(p1 && p2);
	while (*p1 == *p2 && k)
	{
		--k;
		if (*p1 == '\0'|| k==0)
		{
			return 0;
		}
			p1++;
			p2++;
	}
	return *p1 - *p2;
}
int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "abcdeeeeee";
	int ret =my_strncmp(arr1, arr2, 20);
	if (ret > 0)
	{
		printf("arr1>arr2\n");
	}
	else if (ret < 0)
	{
		printf("arr1<arr2\n");
	}
	else
	{
		printf("arr1=arr2\n");
	}
}

 实现时注意加上n这个条件

错误改正:

过两天再看一下自己的代码,发现strncat有一个错误,当时调试时只用了k>len的例子。

当k<=len时,拷贝完字符,最后还要加一个\0

下面是修改过后的代码。

char* my_strncat(char* dest, const char* src, size_t k)
{
	assert(dest && src);
	char* start = dest;
	size_t len = strlen(src);
	while (*dest)
	{
		dest++;
	}
	if (k > len)
	{
		while (*dest++ = *src++)
		{
			;
		}
	}
	else
	{
		while (k)
		{
			--k;
			*dest++ = *src++;
		}
		*dest = '\0';
	}
	return start;
}
int main()
{
	char arr1[20] = "hello \0xxxxxxxx";
	char arr2[] = "world";
	my_strncat(arr1, arr2, 3);
}

多加上了一个*dest='\0'

如有其它错误,请读者尽快联系我加以改正。感谢大家的支持。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值