4

我正在测试“C++ Premiere”书中关于 C++ 中字符串的示例。

const int size = 9;
char name1[size];
char name2[size] = "C++owboy";   // 8 characters here

cout << "Howdy! I'm " << name2 << "! What's your name?" << endl;

cin >> name1;  // I input "Qwertyuiop" - 11 chars. It is more than the size of name1 array;

// now I do cout
cout << "Well, your name has " << strlen(name1) << " letters";  // "Your name has 11 letters".
cout << " and is stored in an array of " << size(name1) << " bytes"; // ...stored in an array of 9 bytes.

11 个字符如何存储在一个数组中,仅用于 8 个字符 + '\0' 字符?编译时会变宽吗?还是字符串存储在其他地方?

另外,我不能这样做:

const int size = 9;
char name2[size] = "C++owboy_12345";   // assign 14 characters to 9 chars array

但可以做我上面写的:

cin >> name1;   // any length string into an array of smaller size

这里的诀窍是什么?我使用 NetBeans 和 Cygwin g++ 编译器。

4

4 回答 4

9

将比数组大小更多的条目写入数组允许调用未定义的行为。计算机可能将该数据存储在任何地方,或者根本不存储它。

通常,数据存储在内存中接下来发生的任何内容中。这可能是另一个变量、指令流,甚至是椅子下方炸弹的控制寄存器。

简而言之:您编写了一个缓冲区溢出错误。不要那样做。


只是为了好玩未定义的行为是 C++ 标准没有评论的行为。它可以是任何东西,因为标准对它没有任何限制。

在一个特殊情况下,这种行为将我的银行余额从 10 美元增加到 18 亿美元:http: //ideone.com/35FQW

你能明白为什么那个程序会这样吗?

于 2012-07-12T15:34:21.903 回答
5

name1 被赋予一个内存地址。如果您向其写入 80 个字节,它将从该位置开始在内存中写入超过 80 个字节。如果有一个变量存储在 name1 的地址 + 20,那么它的数据将被您写入 name1 的 80 个字节覆盖。这就是 C/C++ 中的工作方式,这些被称为缓冲区溢出,可用于破解程序。

于 2012-07-12T15:35:14.800 回答
4

这是典型的缓冲区溢出。这就是为什么如果你将输入放在缓冲区中,你总是应该检查输入的大小。这是正在发生的事情:

在 C++(和 C)中,数组名只是指向数组第一个元素的指针。编译器知道数组的大小并且会做一些编译时检查。但是,在运行时,它只会将其视为 char*。

当你这样做时cin >> name1,你将一个 char* 传递给cin. cin不知道分配的空间有多大——它只有一个指向某个内存的指针。因此,它假定您分配了足够的空间,写入所有内容,并超过了数组的末尾。这是一张图片:

Bytes   1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
Before  |-----name1 array-------|  |--- other data-|
After   Q  w  e  r  t  y  u  i  o  p  \0 |-er data-|

如您所见,您已经覆盖了存储在数组之后的其他数据。有时这些其他数据只是垃圾,但有时它很重要并且可能意味着一个棘手的错误。更不用说,这是一个安全漏洞,因为攻击者可以用用户输入覆盖程序内存。

关于大小的混淆是因为strlen它将计算字节直到它找到一个'\0'(空终止符),这意味着它找到了 10 个字符。另一方面size(name1),使用编译器提供的数组的实际大小。

由于这些问题,每当您看到一个将数组作为参数的 C 函数时,它也会使用数组大小​​。否则无法判断它有多大。为了避免这些问题,最好使用像 std::string 这样的 C++ 对象。

于 2012-07-12T16:07:11.827 回答
3

这里没有技巧:)您正在写入缓冲区之外的内存,这是一种未定义的行为

于 2012-07-12T15:35:06.917 回答