gpt4 book ai didi

c++ - getline 和 char 问题有人可以解释吗?

转载 作者:行者123 更新时间:2023-11-28 01:24:33 25 4
gpt4 key购买 nike

为什么这样做:我告诉程序我的字符最多有 2 个字符,对吧?

#include <iostream>
#include <string>

using namespace std;

int main() {

char name[2];

cout << "Please, enter your full name: " << endl;
cin.getline(name, 100);
cout << "Hello, " << name << "!\n";

return 0;
}

当我输入 Albert Einstein 时,它工作得很好,但是这里有 15 个字符,他们怎么能全部输入我的变量,该变量最多应该有 2 个字符?

但是使用 getline 我告诉他关联到名称,最多 100 个字符写在这一行中。

这行不通:我告诉程序我的字符最多有 1 个字符,对吧?

#include <iostream>
#include <string>

using namespace std;

int main() {

char name[1];

cout << "Please, enter your full name: " << endl;
cin.getline(name, 100);
cout << "Hello, " << name << "!\n";

return 0;
}

当我输入 Albert Einstein 时,它不起作用,但在我创建最多 1 个字符的变量名称时似乎合乎逻辑。

但是使用 getline 我告诉他关联到名称,最多 100 个字符写在这一行中。

我真正不明白的是,为什么当我创建它并告诉 2 个字符时,它有效,而当我告诉 1 个字符时它却不起作用?

有人可以解释一下吗?

谢谢

最佳答案

这不起作用,因为您的数组大小为 2 个字节(2 * char 的大小)。 C 和 C++ 不检查数组边界。这会导致您写入数组末尾。

因为 stack (请注意 wiki 上的插图在内存地址方面是颠倒的)是从高内存地址到低内存地址构建的,但数据是从低到高写入的,你很可能(取决于你的编译器的工作方式和它的设置,等)写入您在此之前声明的其他变量、函数参数、返回指针,甚至超出堆栈末尾的程序的有效范围。

这是 undefined behavior并且在很大程度上取决于堆栈的状态,而不太依赖于写入数组的输入。可能会发生程序崩溃,因为返回指针被覆盖并指向某个随机地址,该地址可能在也可能不在您的程序或 segmentation fault 中。如果您尝试写入您的程序不拥有的 protected 内存。

在最坏的情况下,你有一个 buffer overflow vulnerability其中攻击者可能会设计一个输入来覆盖堆栈上的函数返回地址,以使程序执行跳转到攻击者所需的地址,通常是堆栈本身(刚刚填充了攻击者数据的数组)并执行它.攻击者会用一些处理器指令填充数组的更多部分来做他想做的任何事情。虽然现代操作系统可以防止这种原始类型的溢出漏洞,但它本不应该发生。对于更基本的措施,例如地址随机化,有简单的解决方法。

数组是内存中一个接一个的多个存储单元。每个都可以包含一个字符(或您使用的任何数据类型。)

例如 char name[30]; 将告诉您的编译器为字符保留 30 个单元格。 name 将被视为指向 char 对象的指针,该对象具有数组中第一个单元格的地址 (name[0])。请注意,此时,随机数据可能在这些单元格中。当您通过 cin.getline 在这些单元格中输入一个字符串时,它可能看起来像这样:

['M', 'y', ' ', 'N', 'a', 'm', 'e', '\0', 'f', '&', '\0', '\0', 'y', '\0', ... 'i'] (30 characters total)

C++ 和 C 通过第一个 NULL 值识别字符串的结尾。因此,对于此空值,您的数组中的空间必须至少比最大预期字符限制多 1 个。在这种情况下,名称的最大长度为 29 个字符,因为 null 终止符需要 1 个额外的空格,这会填满所有 30 个单元格。循环中的 1 个索引越界或忘记空终止符是一个常见的错误。这很难调试,因为它很少会导致崩溃,而只会通过覆盖变量或其中的一部分导致细微的、通常无法重现的错误。

固定数组大小对于可变输入长度来说是不好的做法。您应该研究字符串的内存分配和处理指针。或者您可以使用方便的 std::string 对象。

另一个不好的做法是使用魔数(Magic Number),比如我的例子中的 30。最好定义一个具有强名称的常量并改用它。例如

const int MAX_NAME_LEN = 30;

如果您想做一些实验,您可以声明一个数组并用 [\xAB,\xAB,\xAB,\xAB, ...] 这样的数据模式填充它。当您的操作系统抛给您无效的跳转地址时,您将在错误消息的地址 (0xABABABAB) 中看到数据模式(如果您只是覆盖堆栈上的返回地址,而不是写入 protected 内存)。

关于c++ - getline 和 char 问题有人可以解释吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54533007/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com