如果我不给它一点额外的空间,就会发疯。 任何人都可以解释这里发生了什么?
首先,我想说我是C / C ++的新手,我最初是一名PHP开发人员,所以我习惯于以任何我喜欢的方式滥用variables。
C是一个严格的国家,编译器不是很喜欢我这里,我习惯于违反规则去完成任务。
无论如何,这是我的一段简单的代码:
char IP[15] = "192.168.2.1"; char separator[2] = "||"; puts( separator );
输出:
||192.168.2.1
但是,如果我将separator
的定义更改为:
char separator[3] = "||";
我得到所需的输出:
||
那么为什么我需要给这个男人额外的空间,所以他不和他之前的男人睡觉?
这是因为当separator
长度被强制为2时,会得到一个不以null结尾的string。
一定要记住为空终止符分配一个额外的字符。 对于长度为N
的string,您需要N+1
字符。
一旦违反了这个要求,任何期望以空值终止的string(包括puts()
函数)的代码将会运行到未定义的行为。
你最好的select是不强制任何特定的长度:
char separator[] = "||";
将分配一个正确大小的数组。
C中的string是NUL终止的。 这意味着一个由两个字符组成的string需要三个字节(两个字符,第三个字符表示string的结尾)。
在你的例子中,可以省略数组的大小,编译器将分配正确的存储量:
char IP[] = "192.168.2.1"; char separator[] = "||";
最后,如果你用C ++而不是C编码,最好使用std::string
。
如果你正在使用C ++,我build议使用std :: string类而不是Cstring – 更容易和更容易出错的恕我直言,尤其是对于有脚本语言背景的人。
每个string的末尾都有一个隐藏的nul字符“\ 0”。 你必须留下空间。
如果你这样做
char seperator[] = "||";
你会得到一个3号string,而不是2号string。
因为在Cstring中nul终止(它们的末尾标有0字节)。 如果你声明分隔符是一个两个字符的数组,并给它们两个非零值,那么就没有终结符! 因此,当你puts
数组的时候,几乎所有东西都可以加到最后(不pipe在arrays末尾的内存中发生了什么 – 在这种情况下,看起来就是IP
数组)。
编辑:这下面是不正确的。 见下面的评论。
当数组长度为3时,额外的字节恰好有0,这就终止了string。 然而,你可能不能依赖这种行为 – 如果这个值是未初始化的,它可以包含任何东西。
在Cstring结尾有一个特殊的'\0'
字符,所以你的分隔符"||"
实际上是一个字符更长。 puts
函数只是打印每个字符,直到它遇到'\0'
– 在你的情况下一个IPstring后面。
在C中,string在末尾包含一个(不可见的)空字节。 你需要考虑那个空字节。
char ip[15] = "1.2.3.4";
在上面的代码中, ip
有15个字符的空间。 14个“常规字符”和空字节。 这太短了:应该是char ip[16] = "1.2.3.4";
ip[0] == '1'; ip[1] == '.'; /* ... */ ip[6] == '4'; ip[7] == '\0';
由于目前还没有人指出:如果你这样声明你的variables,那么这些string将被自动地以null结尾,而且你不必乱用数组的大小:
const char* IP = "192.168.2.1"; const char* seperator = "||";
但请注意,我假设你不打算改变这些string。
但是如前所述,C ++中的安全方式是使用std :: string类。
AC“string”总是以NULL结尾,但是如果写入char separator [2] =“||”,则不会将其赋给string。 在第一种情况下,它会写这个\ 0,直到它find一个\ 0,这里你可以看到它在IP地址的末尾find的地方。 有趣的是,你甚至可以看到局部variables是如何放在堆栈上的。
行: char seperator[2] = "||"
; 应该得到你未定义的行为,因为该字符数组的长度(包括最后的null)将是3。
另外,你用什么编译器编译了上面的代码? 我用g ++编译,并把上面的行标记为错误。
C \ C ++中的string是空终止的,即末尾有一个隐藏的零。
所以你的分隔符string将是:
{'|', '|', '\0'} = "||"