C语言字符串\0的截断陷阱
Contents
前言
字符串在 C 语言中是一种常见的数据类型,以字符数组的形式存储。而 C 语言中的字符串以 \0 (空字符)作为结束符。然而, \0 的存在可能导致一些问题,特别是在处理包含 \0 的字符串时,常见的字符串处理函数可能会出现截断的情况。
最近就在字符串上踩了坑。
坑一
字符串截断问题
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
const char* str = "abcd\0efg";
printf("str len: %lu, str: %s", strlen(str), str);
return 0;
}
运行后结果如下
str len: 4, str: abcd
可以看到 8 个字符的长度变成了 4,并且字符串被截断了。这并不符合我们的预期。
踩坑二
来看下不以 \0 结尾的问题
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char str[4] = "abcd";
printf("str len: %lu", strlen(str));
return 0;
}
结果如下
error: initializer-string for char array is too long
char str[4] = "abcd";
^~~~~~
1 error generated.
再运行一次
str len: 10, sizeof str: 4
会发现每次运行的结果都不尽相同,因为 strlen 需要碰到 \0 才会结束,所以 strlen 在定义的数组长度之外找到 \0 才算结束,这就导致越界访问了。如果写代码的时候漏写了 \0 ,使用这种方式隐患就很大。
如何处理字符串长度
根据上面的两个例子知道,在 C 语言中字符串就是字符数组,字符串以 \0 结尾,这会导致 \0 后面的字符被截断,如果不以 \0 结尾又会导致越界访问,这种行为很可能会带来隐患。
为了正确处理字符串长度,我们可以采取以下方法:
显式传递字符串的长度:在使用字符串时,我们可以显式地传递字符串的长度,避免依赖 \0 结尾的方式。下面是一个打印字符串的示例代码:
#include <stdio.h>
#include <string.h>
void printString(const char* str, size_t length) {
fwrite(str, sizeof(char), length, stdout);
}
int main(int argc, char *argv[])
{
const char* str = "abcd\0efg";
printString(str, 8);
return 0;
}
结果如下
abcdefg
这里可以打印出包含 \0 的字符串。
C++中的字符串
C++中的字符串一样会有截断的问题,如下所示
std::string str("abcd\0efg");
std::cout << str.length() << ":" << str << std::endl;
结果如下
4:abcd
这时候我们可以通过在构造函数中指定字符串的长度来解决
std::string str("abcd\0efg", 8);
std::cout << str.length() << ":" << str << std::endl;
结果如下
8:abcdefg
总结
正确处理字符串长度是编程中一个重要的注意事项,可以避免由于截断导致的错误结果和越界访问。通过采取适当的处理方法,我们可以确保字符串的完整性和正确性。
了解和掌握这些字符串处理技巧将有助于开发人员避免潜在的问题,并编写出更稳健和可靠的代码。
参考
char[]转std::string时可能导致截断_char stdstring_guandafa 的博客-CSDN博客