如何制作一个非空终止的c字符串?

bas*_*bie 5 c c++

我想知道:char*cs = .....;如果cs指向内存块但是没有'\ 0',那么strlen()和printf("%s",cs)会发生什么?我写这些线:

 char s2[3] = {'a','a','a'};
printf("str is %s,length is %d",s2,strlen(s2));
Run Code Online (Sandbox Code Playgroud)

我得到结果:"aaa","3",但我认为这个结果是因为'\ 0'(或0字节)恰好位于s2 + 3位置.如何制作一个非空终止的c字符串?strlen和其他c字符串函数严重依赖于'\ 0'字节,如果没有'\ 0',我只想更深入,更好地了解这条规则.

ps:通过研究SO上的帖子来激发我的好奇心. 如何将const char*转换为std :: string 以及该帖子中的这些单词:"这实际上比它看起来更棘手,因为除非字符串实际上是nul终止,否则你不能调用strlen."

Mik*_*our 22

如果它不是以空值终止的,那么它不是C字符串,并且你不能使用类似的函数strlen- 它们将从数组的末尾开始,导致未定义的行为.你需要以其他方式跟踪长度.

printf只要给出长度,您仍然可以打印一个非终止字符数组:

printf("str is %.3s",s2);
printf("str is %.*s",s2_length,s2);
Run Code Online (Sandbox Code Playgroud)

或者,如果您有权访问数组本身,而不是指针:

printf("str is %.*s", (int)(sizeof s2), s2);
Run Code Online (Sandbox Code Playgroud)

您还标记了C++的问题:在该语言中,您通常希望避免使用所有这些容易出错的malarkey并使用它std::string.

  • 使用带有字符串长度参数的`printf`的+1 - 我已经完全忘记了这一点.咖啡因为"容易出错的malarkey"而嗤之以鼻. (3认同)

Seb*_*edl 8

根据定义,"C字符串"以空值终止.该名称来自具有以null结尾的字符串的C约定.如果你想要别的东西,它不是C字符串.

因此,如果您有一个非空终止的字符串,则不能在其上使用C字符串操作例程.你不能使用strlen,strcpystrcat.基本上,任何采用char*但没有单独长度的函数都是不可用的.

那你能做什么?如果您有一个非空终止的字符串,则您将分别拥有该长度.(如果你没有,你就搞砸了.你需要一些方法来找到长度,无论是通过终结器还是单独存储它.)你可以做的是分配一个适当大小的缓冲区,复制字符串,并附加一个null.或者,您可以编写自己的一组字符串操作函数,这些函数可以使用指针和长度.在C++中,你可以使用std::string带有一个char*和一个长度的构造函数; 那个人不需要终结者.


JVM*_*ATL 6

您的假设是正确的:您的 strlen 出于纯粹的运气返回了正确的值,因为在您不正确终止的字符串之后,堆栈中恰好有一个零。字符串为 3 个字节可能会有所帮助,并且编译器可能会将堆栈上的内容对齐到 4 个字节的边界。

你不能依赖这个。C 字符串在末尾需要 NUL 字符(零)才能正常工作。C 字符串处理很混乱,而且容易出错;有一些库和 API 可以帮助减少这种情况……但它仍然很容易搞砸。:)

在这种特殊情况下,您的字符串可以初始化为以下之一:

  • char s2[4] = { 'a','a','a', 0 }; // good if string MUST be 3 chars long
  • char *s2 = "aaa"; // if you don't need to modify the string after creation
  • çchar s2[]="aaa"; // if you DO need to modify the string afterwards

另请注意,声明BC是“更安全”的,因为如果有人稍后出现并以改变长度的方式更改字符串声明,则BC仍然自动正确,而A取决于程序员记得更改数组大小并在末尾保留显式空终止符。


小智 -1

你所做的是未定义的行为。

您正在尝试写入不属于您的内存位置。

将其更改为

char s2[] = {'a','a','a','\0'};
Run Code Online (Sandbox Code Playgroud)

  • 而且你也错误地理解了OP想要的内容。他故意没有以空终止字符串,因为他正在询问非空终止字符串。 (3认同)