代码在 Visual c++ 中无法按预期工作(来自 bjarne stroustrup 编程和原则书 2n 版的示例)

Posted

技术标签:

【中文标题】代码在 Visual c++ 中无法按预期工作(来自 bjarne stroustrup 编程和原则书 2n 版的示例)【英文标题】:Code doesn't work as intended in visual c++ (examples from bjarne stroustrup programming and principles book 2n version) 【发布时间】:2017-05-21 08:02:11 【问题描述】:

好吧,因为我最近开始阅读有关 C++ 的内容,并尝试阅读我正在阅读的《编程原理和练习使用 C++ 第二版》这本书。

我是一个完全的新手,所以这可能就是原因,但就是这样。

好吧,所以在书中他们让你实现了一个头 .h 文件而不是 (iostream) 等。所以它只是一开始就包含所有这些,因为这本书不希望我们在一开始就专注于那些库的学习。 所以我实现了它并使用了它(不确定这是否与问题有关)。无论如何,在第 77 页,我被卡住了。

基本上这是一个错误的值,它应该只显示 -1(或 0),因为 int 得到一个错误值,等等 Carlos(字母,不是整数)所以 int 没有得到正确的值因此根据本书,应该可以工作的代码(并显示 0 或 -1,因为它是输入的错误值)是这样的:

#include "std_lib_facilities.h"


using namespace std;

int main()


cout << "Please enter your first name and age\n";
string first_name = "???"; // string variable // ("???” means “don’t know the name”)
int age = –1; // integer variable (–1 means “don’t know the age”)
cin >> first_name >> age; // read a string followed by an integer
cout << "Hello, " << first_name << " (age " << age << ")\n";

这就是我写的:

#include "std_lib_facilities.h"


using namespace std;

int main()

cout << "Please enter your first name and age" << endl;
string First_Name = "???";
int Age = -1;
cin >> First_Name >> Age;
cout << "Hello, " << First_Name << "(age" << Age << ")" << endl;
keep_window_open();
return 0;

但是,当我写 22 Carlos 时,Visual C++ 的结果是崩溃。 根据这本书它应该输出 Hello, 22 (age -1)

但对我来说,它只是在我输入 Carlos 作为年龄值后崩溃... 当我运行和编译它时,我没有收到错误或任何东西,但是当我为年龄提供错误值后它崩溃了。

我做错了什么? 补充:我知道我可以使用一个字符串来让它工作,但是我只是对它为什么不起作用感兴趣,因为我正在关注这本书我希望在没有这些问题的情况下遵循它工作。

这是我做的时候的 gif: http://imgur.com/a/ERjhz 解决方案:使用 system("pause");而不是 keep_window_open(); 然而,在知道书中的代码并不总是有效的情况下阅读这本书仍然很烦人:(

【问题讨论】:

您使用的是什么版本的 Visual Studio,它在 MSVC2015 中按预期工作。 您可以尝试包含#include &lt;iostream&gt;#include &lt;string&gt; 来代替您添加的包含吗?只是看看它是否可以这样工作。 这本书明显过时了。按照目前的标准,正确的输出是0,而不是-1。但是程序不应该崩溃。你确定程序可以编译吗?它包含在 C++ 程序中不合法的非标准减号。当使用 MS Word 或其他文字处理器进入程序时,它们会出现 ifteb。不要那样做。使用程序员的文本编辑器。 我正在使用 Visual Studio 社区 2017 版来编写我的代码。顺便说一下,我尝试包含 iostream 和字符串,但它也不起作用(是的,我删除了 keep_window_open();因为它引用了我之前使用的那个) 抱歉,第一个样本包含无效字符,第二个没有。 【参考方案1】:

这不是问题,但太快了,我们的眼睛无法注意到。

我正在添加keep_window_open()的函数定义

inline void keep_window_open()

    cin.clear();
    cout << "Please enter a character to exit\n";
    char ch;
    cin >> ch;
    return;

如您所见,它只需要我们输入的字符 转发您将了解输入流及其缓冲区 因此,当您输入一个字符代替整数时,流(背景)中会标记错误,并且只使用输入的一个字符(在您的情况下,“C”用于标记)。

我将输入用作 Carlos 22

所以现在输入流仍然有字符 'a','r','l','o','s',22 所以现在 'a' 被用作 keep_window_open 函数的输入 程序结束,无需等待您的输入 所以没有错误或崩溃,但由于字符已经存在用于 keep_window_open 函数的输入,所以它的速度非常快

【讨论】:

对于错误标记的函数 cin.clear 清除所有引发的错误标记并将流恢复正常【参考方案2】:

问题出在keep_window_open。这是一个棘手的功能,很难完全正确。您可以将其替换为避开问题但仅适用于 Windows 的代码:

inline void keep_window_open()

   system("pause");

或者用这个稍微复杂一点的代码来尝试考虑更多的情况:

inline void keep_window_open()

    cout << "Please enter a character to exit\n";
    if (!cin)
    
        cin.clear();
        cin.ignore(120, '\n');
    
    char ch;
    cin >> skipws >> ch;

(假设您输入的行不超过 120 个字符。如果您希望它不受任意限制,请将 120 替换为 numeric_limits&lt;streamsize&gt;::max()。在这种情况下,std_lib_facilities.h 中的其他函数确实使用 120。你很多或可能不必在您的程序中添加#include &lt;limits&gt; 指令)。

我已经在几个案例中进行了测试,它似乎可以在正确和不正确的程序输入下工作,但使用它需要您自担风险。如果您的程序需要更复杂的输入,它仍然可能正常工作,也可能无法正常工作。

【讨论】:

【参考方案3】:

一个好的规则是始终除非最终用户是白痴,因此您需要以一种可以处理各种输入而不会崩溃的方式编写程序。因此,始终将输入数字读取为std::string,然后尝试将其转换为intshortdoubleunsigned int 或您使用的任何数据类型。

您的代码应如下所示:

#include <cstdlib>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>

int main(int argc, char **argv)

    int age;
    std::string first_name;
    std::string input_age;

    std::cout << "Please enter your first name and age: " << std::endl;
    std::cin >> first_name >> input_age; // Read the age as 'std::string'

    try
    
            age = std::stoi(input_age); // Try to convert age from 'std::string' to 'int'
            std::cout << "Hello, " << first_name << " (" << age << ")" << std::endl;
    
    catch(std::invalid_argument& ex) // 'std::stoi()' will throw 'std::invalid_argument' if it's not able to convert 'std::string' to 'int'
    
            std::cerr << "Unable to convert input value ('" << input_age << "') to 'int'" << std::endl;
            std::cerr << "Debug info: " << ex.what() << std::endl;
    
    catch(std::out_of_range& ex) // 'std::stoi()' will throw 'std::out_of_range' if 'std::string' is too small or too big to store in a 'int'
    
            std::cerr << "The input value (" << input_age << ") is out of range, please input a value inside the range" << std::endl;
            std::cerr << "Debug info: " << ex.what() << std::endl;
    

    return EXIT_SUCCESS;

【讨论】:

问题不在于编写正确的代码。问题是为什么 Stroustrup 书中的代码不像宣传的那样表现得那么好。修改该代码并不能帮助您回答问题。 感谢您的回复,但作为@n.m,作为一个编程新手,您提供的所有代码对我来说有点高:) stoi、cerr、argc 等...学习:)【参考方案4】:

所以与代码无关,与输入有关。

例如,当我写 22 卡洛斯时。

问题是代码要求First_Name 然后Age,而不是Age 然后First_Name。因此,当您将 22 作为 First_Name 时,.exe 会变得混乱。

例如,假设我这样做了

int y = 0;
cout << "Give me INT: ";
cin >> y;
cout >> "You put: " >> y;

当我运行程序并将其输入时

Give me INT: ghaisewofasd
*crashed*

这是一个问题,因为用户在代码请求 int 时给出了一个字符串。

因此,对于您的情况,不要写 22 Carlos,而只需写 Carlos 22。 还要记住,这本书可能不太正确,因为它不应该打印出 Hello, (22)。如果发生这种情况,现在会出现类似崩溃的情况,可能是旧版本的 C++。

【讨论】:

不是这个。他的程序在应该执行Hello, 22 (age -1) 时崩溃。刚刚在 Unix 中尝试过,它确实有他所说的输出。 否,如果您尝试从包含非 int 字符的流中提取 int,则 value 保持不变并设置了 failbit。没有崩溃 OP 想要输入错误的数据。程序不应崩溃。 哦,我刚刚在 Visual C++ 中测试了我的代码,它没有崩溃。该死的,我很喜欢“在堆栈溢出时有一些问题可以得到 15 分”,看来我错了。虽然我有时会因为这些问题而崩溃 是的,除了我没有使用你的标题,我得到了 -1

以上是关于代码在 Visual c++ 中无法按预期工作(来自 bjarne stroustrup 编程和原则书 2n 版的示例)的主要内容,如果未能解决你的问题,请参考以下文章

Tupper 在 C++ 中的自引用公式没有按预期工作?

我的 C++ OpenGL SDL 程序没有按预期工作

远程进程的 Visual Studio 2012 调试未按预期工作

正则表达式无法与 C++ regex_match 一起按预期工作

这个 C++ 代码会一直按我的预期工作,还是不能保证执行顺序?

在 C++ 中读取文件:for 和 while 嵌套循环没有按预期工作:串行?