目录
字符串函数注意点
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
注意:不能与source在内存中重叠指的是,自己拷贝自己实际上没有意义。
为保证目的地接收拷贝后仍为一个字符串,我们在涉及函数时需要拷贝完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这个条件
错误改正:
过两天再看一下自己的代码,发现strncpy有一个错误,当时调试时只用了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'
如有其它错误,请读者尽快联系我加以改正。感谢大家的支持。