我的问题围绕下面显示的程序(环境是Mac Xcode)。
#include <iostream>
int main () {
char nameOne [5];
std::cin >> nameOne; // input: BillyBobThorton
std::cout << nameOne; // output: BillyBobThorton
char nameTwo [5] = "BillyBobThorton"; // compile error, initializer string too long
std::cout << nameTwo;
return 0;
}
我有一个长度为5的char数组,所以我希望我在这个数组中存储的最大字符数为4(加上空终止字符)。当我尝试将字符串存储到nameTwo
变量时,情况确实如此。但是,当我使用一个字符数组作为存储用户输入的变量时,数组长度会被完全忽略,并且数组似乎会扩展以容纳额外的字符。
为什么会出现这种情况,是否有更合适的方法将用户输入存储到字符数组中?
答案 0 :(得分:5)
它没有“看似扩展”,而是它不安全地传递了数组的边界,并且可能会导致内存损坏。
有“安全”功能会限制用户输入的长度。看看带有长度限制器的扫描(%xxxs
,其中xxx是最大长度),或扫描Windows上的scanf_s。
答案 1 :(得分:5)
是的! C ++中最合适的方法是使用std::string
。这样可以防止用户超出您分配的缓冲区末尾并破坏堆栈。如果您只想显示一定数量的字符,则可以使用std::string::substr()
限制输出(或在某些验证例程期间)。这是一个例子。
#include <iostream>
#include <string>
int main ()
{
std::string nameOne;
std::cin >> nameOne; // input: BillyBobThorton
std::cout << nameOne.substr(0, 5); // output: Billy
const std::string nameTwo = "BillyBobThorton";
std::cout << nameTwo.substr(0, 5); // output: Billy
return 0;
}
答案 2 :(得分:2)
std :: cin不知道缓冲区的大小。它只知道它必须填充从给定地址开始的char数组。当它填充char *时,它会读取输入,直到遇到换行符(\ n)。
如果你想阅读用户提供的任何内容作为输入,你可以使用std :: string而不是char数组(std :: cin&gt;&gt; string;或std :: getline(std ::) cin,string);也从输入缓冲区中删除换行符。)
如果要限制要读取的字符数,则应使用std :: cin.get(char *,size)或std :: cin.get(streambuf&amp;,size);
最好限制输入长度以避免读取很长的字符串(几千个字符或更多字符串)。
答案 3 :(得分:1)
扩展这一点,无论缓冲区的大小如何,从cin流入固定大小的缓冲区几乎总是不好的做法。这就是导致臭名昭着的buffer overflow的原因。来自标准输入的数据可以是任意长度,您应该始终检查您正在复制的缓冲区是否足以容纳您想要放入的任何内容。
当您使用std :: cin和std :: string检查缓冲区是否足够大以及根据需要重新分配它时,所有这些都将为您完成。
话虽如此,当然,还有一种限制cin提取量的方法,请参阅How to set maximum read length for a stream in C++?