在末尾定义一个没有空终止char(\ 0)的字符串

C / C ++中有哪些方法可以定义一个字符串,结尾没有空终止字符(\ 0)?

编辑:我只对字符数组感兴趣,而不是STL字符串。

通常,另一张海报写道:

char s[6] = {'s', 't', 'r', 'i', 'n', 'g'}; 

或者如果你当前的C字符集是ASCII,这通常是正确的(今天的EBCDIC不多)

 char s[6] = {115, 116, 114, 105, 110, 107}; 

还有一种很大程度上被忽略的方式只适用于C(不是C ++)

 char s[6] = "string"; 

如果数组大小太小而不能保持最后的0(但足够大以容纳常量字符串的所有其他字符),则不会复制最终的零,但它仍然是有效的C(但是无效的C ++)。

显然你也可以在运行时这样做:

 char s[6]; s[0] = 's'; s[1] = 't'; s[2] = 'r'; s[3] = 'i'; s[4] = 'n'; s[5] = 'g'; 

或(与上面的ASCII字符集相同)

 char s[6]; s[0] = 115; s[1] = 116; s[2] = 114; s[3] = 105; s[4] = 110; s[5] = 103; 

或者使用memcopy(或memmove或bcopy,但在这种情况下,这样做没有任何好处)。

 memcpy(c, "string", 6); 

或strncpy

 strncpy(c, "string", 6); 

应该理解的是,C中没有字符串这样的东西(在C ++中有字符串对象,但这完全是另一个故事)。 所谓的字符串只是char数组。 甚至名字char也具有误导性,它不是一个字符,而只是一种数字类型。 我们可能已经把它称为字节,但在过去,使用9位寄存器或类似的字节意味着8位。

由于char通常用于存储字符代码,因此C设计者认为比在char中存储数字更简单。 您可以在简单的引号之间放一个字母,编译器会理解它必须将此字符代码存储在char中。

我的意思是(例如)您不必这样做

 char c = '\0'; 

要在char中存储代码0,只需执行以下操作:

 char c = 0; 

由于我们经常不得不使用一堆可变长度的字符,因此C设计师也选择了“字符串”的约定。 只需将代码0放在文本应该结束的位置。 顺便说一句,这种字符串表示有一个名称“零终止字符串”,如果你在变量名的开头看到两个字母sz,通常意味着它的内容是一个零终止的字符串。

“C sz strings”根本不是一个类型,只是一个正常的字符数组,比如一个int数组,但字符串操作函数(strcmp,strcpy,strcat,printf和许多其他函数)理解并使用0结束约定。 这也意味着如果你有一个非零终止的char数组,你不应该调用任何这些函数,因为它可能会出错(或者你必须格外小心并使用名字中带有n个字母的函数,如strncpy )。

这个惯例的最大问题是很多情况下效率低下。 一个典型的例子:你想把一些东西放在一个0终止的字符串的末尾。 如果你保持大小你可以跳到字符串的末尾,使用sz约定,你必须通过char检查它的char。 处理编码的unicode等时会出现其他类型的问题。 但是在创建C的时候,这个约定非常简单并完美地完成了工作。

如今,像“string”这样的双引号之间的字母不像过去那样是普通的char数组,而是const char * 。 这意味着指针指向的是一个不应该被修改的常量(如果你想修改它,你必须先复制它),这是一件好事,因为它有助于在编译时检测许多编程错误。

C ++ std::string s不是NUL终止的。

PS: NULL是一个宏1NUL\0 。 不要混淆它们。

1:C.2.2.3宏NULL

在任何定义的宏NULL是本国际标准中实现定义的C ++空指针常量(18.1)。

终止null用于终止字符串。 没有它,你需要一些其他的方法来确定它的长度。

您可以使用预定义的长度:

 char s[6] = {'s','t','r','i','n','g'}; 

您可以模拟pascal样式的字符串:

 unsigned char s[7] = {6, 's','t','r','i','n','g'}; 

您可以使用std::string (在C ++中)。 (因为你对std :: string不感兴趣)。

最好使用一些处理unicode的预先存在的技术,或者至少理解字符串编码(即wchar.h )。

评论:如果你把它放在一个打算在实际计算机上运行的程序中,你可以考虑输入你自己的“字符串”。 如果您不小心尝试将其传递给期望C样式字符串的函数,这将鼓励您的编译器进行barf。

 typedef struct { char[10] characters; } ThisIsNotACString; 

在C ++中,您可以使用字符串类,而不是处理null char。

只是为了完整,并完全解决这个问题。

vector

使用std :: string。

有许多其他方法来存储字符串,但使用库通常比制作自己的库更好。 我相信我们都可以想出很多古怪的方法来做没有空终结符的字符串:)。

在C中,通常不会有更容易的解决方案。 您可以执行pascal所做的操作并将字符串的长度放在第一个字符中,但这有点痛苦,并且会将字符串长度限制为可以适合第一个字符空间的整数的大小。 在C ++中,我肯定会使用可以访问的std :: string类

 #include  

作为一个常用的库,这几乎肯定比滚动自己的字符串类更可靠。

NULL终止的原因是字符串的处理程序可以确定它的长度。 如果不使用NULL终止,则需要通过单独的参数/变量或作为字符串的一部分传递字符串长度。 否则,您可以使用另一个分隔符,只要它不在字符串本身中使用。

说实话,我不太明白你的问题,或者它实际上是一个问题。

即使是string类也会将其存储为null。 如果由于某种原因你绝对不希望在内存中你的字符串末尾有一个空字符,你必须手动创建一个字符块,并自己填写。

我个人无法想到为什么你想要这样做的任何现实场景,因为空字符是信号字符串结尾的信号。 如果你也存储了字符串的长度,那么我猜你已经节省了一个字节,代价是变量的大小(可能是4个字节),并且可以更快地访问所述字符串的长度。