我喜欢“重新发明轮子”用于学习目的,所以我正在为字符串工作一个容器类。将NULL
字符用作数组终止符(即数组中的最后一个值是NULL
)是否会导致对以null结尾的字符串的干扰?
我认为如果添加一个空字符串只会是一个问题,但我可能会遗漏一些东西。
编辑:这是用C ++编写的。
答案 0 :(得分:2)
""
是C和C ++中的空字符串,而不是NULL
。请注意,""
只有一个元素(而不是零),这意味着它等同于{'\0'}
作为char
的数组。
char const *notastring = NULL;
char const *emptystring = "";
emptystring[0] == '\0'; // true
notastring[0] == '\0'; // crashes
答案 1 :(得分:2)
不,它不会,因为你不会存储在char数组中,你将存储在char *数组中。
char const* strings[] = {
"WTF"
, "Am"
, "I"
, "Using"
, "Char"
, "Arrays?!"
, 0
};
答案 2 :(得分:2)
这取决于您要存储的字符串类型。
如果你要存储C风格的字符串,它们基本上只是指向字符数组(char*
)的指针,那么NULL
指针值和空字符串之间就有区别。前者表示指针为“空”,后者表示指针指向包含字符值为0('\0'
)的单个项的数组。所以指针仍然有一个值,测试它(if (foo[3])
)将按预期工作。
如果您要存储的是string
类型的C ++标准库字符串,则没有NULL
值。那是因为没有指针,string
类型被视为单个值。 (虽然指针在技术上不是,但可以看作是参考。)
答案 3 :(得分:2)
我觉得你很困惑。虽然C字符串是“空终止”,但没有“NULL”字符。 NULL
是null 指针的名称。 C字符串的终止符是空字符,即值为零的字节。在ASCII中,这个字节(有点令人困惑)命名为NUL
。
假设您的类包含用于存储字符串数据的char
数组。你不需要“标记数组的结尾”;数组具有在编译时设置的特定大小。你需要知道实际使用了多少空间;字符串数据上的null-terminator为您完成 - 但您可以通过实际记住长度来获得更好的性能。另外,带有静态大小的char缓冲区的“string”类根本不是很有用,因为缓冲区大小是你可以拥有的字符串长度的上限。
因此,更好的字符串类将包含类型为char*
的指针,该指针指向new[]
s的动态分配(via char
)数组。同样,“标记数组的结尾”是没有意义的,但是你要记住字符串的长度(即使用的空间量)和分配的大小(即空间的数量)可以在必须重新分配之前使用。
答案 4 :(得分:1)
当您从std::string
进行复制时,请使用迭代器begin()
,end()
并且您不必担心NULL - 实际上,只有当您使用NULL时才会出现NULL call c_str()
(在这种情况下,指向的内存块将有一个NULL来终止字符串。)如果你想memcpy
使用data()
方法。
答案 5 :(得分:0)
为什么不遵循vector
使用的模式 - 存储容器类中的元素数量,然后总是知道其中有多少个值:
vector<string> myVector;
size_t elements(myVector.size());
使用x
实例化字符串,其中const char* x = 0;
可能会有问题。在执行此操作时,在Visual C ++ STL中查看此代码:
_Myt& assign(const _Elem *_Ptr)
{ // assign [_Ptr, <null>)
_DEBUG_POINTER(_Ptr);
return (assign(_Ptr, _Traits::length(_Ptr)));
}
static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
{ // find length of null-terminated string
return (_CSTD strlen(_First));
}
答案 6 :(得分:0)
#include "Maxmp_crafts_fine_wheels.h"
MaxpmContaner maxpm;
maxpm.add("Hello");
maxpm.add(""); // uh oh, adding an empty string; should I worry?
maxpm.add(0);
此时,作为MaxpmContainer的用户,他没有阅读您的文档,我希望如下:
strcmp(maxpm[0],"Hello") == 0;
*maxpm[1] == 0;
maxpm[2] == 0;
通过“将其解释为存储器地址”运算符*,避免了位置2处的零终结器与位置1处的空字符串之间的干扰。位置一不会为零;它将是一个整数,如果将其解释为内存地址,则结果为零。位置2将为零,如果您将其解释为内存地址,则结果将是从程序中突然无序退出。