25 Nov 2016
c库函数strncat出现乱字符
最近项目接近尾声,基本都是在fix bug,今天说说一个bug,是由于strncat函数使用不当导致命令行输出有乱字符。虽说只是一个很简单的小问题,但是不弄明白就是大问题。
1 strncat声明
char *strncat(char *dest, const char *src, size_t n)
- dest: 目标字符串,需保证其容量能容纳连接后字符串
- src: 源字符串
- n: 追加的字符数,如果超过src大小,只拷贝src所有字符
这个函数的主要功能是将src指向的字符串追加到dest指向的字符串,最多追加n个字符,包括最后一个字符串结尾符NUL,最后返回指向dest字符串的指针。
2 strncat误用
引起bug的代码大致如下,主要功能是将一个字符串拷贝到一个空的字符数组中。
#include <stdio.h>
#include <string.h>
int main ()
{
char dest[10];
strncat(dest, "Hello World!", 100);
printf("Final destination string: %s\n", dest);
return (0);
}
3 代码输出
root@leo:demo# crun strncat.c
Final destination string: Hello World!
root@leo:demo# crun strncat.c
Final destination string: τ:Hello World!
root@leo:demo# crun strncat.c
Final destination string: ᰷Hello World!
如果从第一次运行结果来看,看似没有什么问题。但是再运行2次,发现结果有乱字符。
广告时间: 这里使用的crun是我封装的一个命令,只是为了在终端运行c代码时方便,如果你觉得实用的话拷贝到你的bash配置文件,命令定义如下:
crun(){
gcc $1 -g;
if [ $? -ne 0 ]; then
echo "failed build $1"
else
./a.out
rm -rf ./a.out
fi
}
4 出现乱字符的原因
输出有乱字符,是因为dest声明后,没有初始化,其内存空间是一些随机数据。不是一个合法的字符串,所以没有字符串结束符NUL,但是strncat函数在追加字符串时需要知道目的字符串dest的结尾,因为找不到字符串结束符NUL,所以出现未定义行为。
5 strncat正确使用
所以正确使用方式是给dest第一个字符赋值为NUL,即字符\0。
#include <stdio.h>
#include <string.h>
int main ()
{
char dest[10];
dest[0] = '\0';
strncat(dest, "Hello World!", 100);
printf("Final destination string: %s\n", dest);
return (0);
}
6 总结
在c语言中,如果忽略了字符串结束符,会导致很多依赖字符串结束符的函数发生未定义行为。比如以下函数:
- strlen
- strcat
- strcpy
- strncpy
再强调下c字符串定义:
字符串是以ASCII字符NUL结尾的字符序列,ASCII字符NUL表示为\0。
所以不要把字符数组和字符串混淆,字符串是一个字符数组,但是该字符数组最后一个字符必须是\0,但是字符数组不一定是字符串。上面说到的bug就是因为混淆了字符数组和字符串定义导致。
本次荐书:代码的未来
LEo
at 22:09