如果我不给它一点额外的空间,绳子就会发疯。谁能解释一下这里发生了什么?
首先,我想说,我是 C / C++ 新手,我最初是一名 PHP 开发人员,所以我生来就以我喜欢的方式滥用变量。
C是一个严格的国家,编译器不太喜欢我这里,我习惯于打破规则来完成事情。
无论如何,这是我的简单代码:
char IP[15] = "192.168.2.1";
char separator[2] = "||";
puts( separator );
输出:
||192.168.2.1
但是如果我将 separator
的定义更改为:
char separator[3] = "||";
我得到了所需的输出:
||
那么为什么我需要给这个人额外的空间,所以他不会不和面前的男人睡吗?
First, I'd like to say that I'm new to C / C++, I'm originally a PHP developer so I am bred to abuse variables any way I like 'em.
C is a strict country, compilers don't like me here very much, I am used to breaking the rules to get things done.
Anyway, this is my simple piece of code:
char IP[15] = "192.168.2.1";
char separator[2] = "||";
puts( separator );
Output:
||192.168.2.1
But if I change the definition of separator
to:
char separator[3] = "||";
I get the desired output:
||
So why did I need to give the man extra space, so he doesn't sleep with the man before him?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
这是因为当
separator
长度强制为 2 时,您会得到一个非空终止字符串。始终记住为空终止符分配一个额外的字符。对于长度为
N
的字符串,您需要N+1
个字符。一旦违反此要求,任何需要空终止字符串的代码(包括
puts()
函数)都将遇到未定义的行为。最好的选择是不要强制任何特定长度:
将分配一个大小完全正确的数组。
That's because you get a not null-terminated string when
separator
length is forced to 2.Always remember to allocate an extra character for the null terminator. For a string of length
N
you needN+1
characters.Once you violate this requirement any code that expects null-terminated strings (
puts()
function included) will run into undefined behavior.Your best bet is to not force any specific length:
will allocate an array of exactly the right size.
C 中的字符串以 NUL 结尾。这意味着两个字符的字符串需要三个字节(两个用于字符,第三个用于表示字符串结尾的零字节)。
在您的示例中,可以省略数组的大小,编译器将分配正确的存储量:
最后,如果您使用 C++ 而不是 C 进行编码,则最好使用
std::string< /代码>。
Strings in C are NUL-terminated. This means that a string of two characters requires three bytes (two for the characters and the third for the zero byte that denotes the end of the string).
In your example it is possible to omit the size of the array and the compiler will allocate the correct amount of storage:
Lastly, if you are coding in C++ rather than C, you're better off using
std::string
.如果您无论如何都使用 C++,我建议使用 std::string 类而不是 C 字符串 - 恕我直言,更容易且更不容易出错,特别是对于具有脚本语言背景的人。
If you're using C++ anyway, I'd recommend using the std::string class instead of C strings - much easier and less error-prone IMHO, especially for people with a scripting language background.
每个字符串末尾都有一个隐藏的 nul 字符“\0”。你必须为此留出空间。
如果这样做,
您将得到一个大小为 3 的字符串,而不是大小为 2 的字符串。
There is a hidden nul character '\0' at the end of each string. You have to leave space for that.
If you do
you will get a string of size 3, not size 2.
因为在 C 中,字符串以 nul 结尾(它们的结尾标记为 0 字节)。如果将分隔符声明为两个字符的数组,并给它们两个非零值,那么就没有终止符!因此,当您
put
数组时,几乎所有内容都可以添加到末尾(无论发生在内存中超出数组末尾的内容 - 在这种情况下,它似乎是IP< /代码> 数组)。
编辑:以下内容不正确。请参阅下面的评论。
当数组长度为 3 时,额外的字节恰好有 0,这会终止字符串。但是,您可能不能依赖该行为 - 如果该值未初始化,它实际上可能包含任何内容。
Because in C strings are nul terminated (their end is marked with a 0 byte). If you declare separator to be an array of two characters, and give them both non-zero values, then there is no terminator! Therefore when you
puts
the array pretty much anything could be tacked on the end (whatever happens to sit in memory past the end of the array - in this case, it appears that it's theIP
array).Edit: this following is incorrect. See comments below.
When you make the array length 3, the extra byte happens to have 0 in it, which terminates the string. However, you probably can't rely on that behavior - if the value is uninitialized it could really contain anything.
在 C 中,字符串以特殊的
'\0'
字符结尾,因此分隔符文字"||"
实际上多了一个字符。puts
函数只打印每个字符,直到遇到'\0'
- 在您的情况下是 IP 字符串之后的一个。In C strings are ended with a special
'\0'
character, so your separator literal"||"
is actually one character longer.puts
function just prints every character until it encounters'\0'
- in your case one after the IP string.在 C 中,字符串末尾包含一个(不可见的)空字节。您需要考虑该空字节。
在上面的代码中,
ip
有足够的空间容纳 15 个字符。 14 个“常规字符”和空字节。太短了:应该是char ip[16] = "1.2.3.4";
In C, strings include a (invisible) null byte at the end. You need to account for that null byte.
in the code above,
ip
has enough space for 15 characters. 14 "regular characters" and the null byte. It's too short: should bechar ip[16] = "1.2.3.4";
由于到目前为止没有人指出这一点:如果您像这样声明变量,则字符串将自动以空终止,并且您不必弄乱数组大小:
但是请注意,我假设您不这样做打算更改这些字符串。
但正如已经提到的,C++ 中的安全方法是使用 std::string 类。
Since no one pointed it out so far: If you declare your variable like this, the strings will be automagically null-terminated, and you don't have to mess around with the array sizes:
Note however, that I assume you don't intend to change these strings.
But as already mentioned, the safe way in C++ would be using the std::string class.
AC“String”总是以 NULL 结尾,但如果你写的话,你只是不把它给字符串
字符分隔符[2] =“||”。 put 在第一个写入的情况下在 ned 处期待这个 \0,直到找到 \0,在这里您可以看到它在 IP 地址末尾的位置。有趣的是,您甚至可以看到局部变量在堆栈上的布局方式。
A C "String" always ends in NULL, but you just do not give it to the string if you write
char separator[2] = "||". And puts expects this \0 at the ned in the first case it writes till it finds a \0 and here you can see where it is found at the end of the IP address. Interesting enoiugh you can even see how the local variables are layed out on the stack.
该行:
char seperator[2] = "||"
;应该会导致未定义的行为,因为该字符数组的长度(包括末尾的 null)将为 3。另外,您用什么编译器编译了上述代码?我用 g++ 编译并将上面的行标记为错误。
The line:
char seperator[2] = "||"
; should get you undefined behaviour since the length of that character array (which includes the null at the end) will be 3.Also, what compiler have you compiled the above code with? I compiled with g++ and it flagged the above line as an error.
C\C++ 中的 String 以 null 结尾,即末尾有一个隐藏的零。
所以你的分隔符字符串将是:
String in C\C++ are null terminated, i.e. have a hidden zero at the end.
So your separator string would be: