简体   繁体   English

将char分配给int变量时的奇怪行为

[英]Weird behaviour when assigning a char to a int variable

Given this code: 鉴于此代码:

#include <cstdio>
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::string;

int main() {
        int a;
        string b;

        cin >> a;
        cin >> b;

        return 0;
}

I tried compiling it with g++ and running it. 我尝试用g ++编译并运行它。 When assigning a char to a , at the first cin , the following instruction seems to be skipped. 将char分配给a ,在第一个cin ,似乎会跳过以下指令。

Even if add two getchar() instructions between the last two lines, only the second getchar() seems to be executed. 即使在最后两行之间添加两个getchar()指令,也只会执行第二个getchar() Can somebody accurately explain what's happening at low level, which seemingly results in an apparent non execution of those lines? 有人可以准确地解释低水平发生了什么,这似乎导致这些线明显不执行?

EDIT: 编辑:

Using this debug code: 使用此调试代码:

#include <cstdio>
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
        int a;
        string b;

        cin >> a;
        cin >> b;
        cout << "a is "<< a << endl;
        cout << "b is "<< b << endl;
        getchar();

        return 0;
}

INPUT 1test INPUT 1test

OUTPUT a is 1 b is test * No getchar executed * 输出 a是1 b是测试*没有执行getchar *

INPUT 1 test INPUT 1测试

OUTPUT a is 1 b is test 输出 a是1 b是测试

INPUT ttest INPUT ttest

OUTPUT a is 0 b is 输出 a是0 b

INPUT t 输入 t

// Skips the second cin //跳过第二个cin

OUTPUT a is 0 b is 输出 a是0 b

NOTE: getchar() was not executed even once. 注意: getchar()甚至没有执行过一次。

You probably hit enter after the first character. 您可能在第一个字符后按Enter键。 You don't have any code to consume that enter, so you get an empty string. 您没有任何代码可以使用该输入,因此您将获得一个空字符串。 Your code doesn't expect any separator between the two inputs, so don't enter any. 您的代码不希望两个输入之间有任何分隔符,因此请勿输入任何分隔符。

Two things, judging from your output. 从你的输出来判断两件事。 The first is when you enter "ttest" , the cin >> a; 首先是当你输入"ttest"cin >> a; fails. 失败。 This puts cin in an error state, where it will remain until the error is cleared. 这会使cin处于错误状态,直到错误被清除为止。 And as long as it is in an error state, all other operations are no-ops. 只要它处于错误状态,所有其他操作都是无操作。 You really need to test the results of the input before trying to use the values: 在尝试使用这些值之前,您确实需要测试输入的结果:

std::cin >> a;
if ( !cin ) {
    std::cerr << "That wasn't an integer" << std::endl;
    std::cin.clear();
}
std::cin >> b;
if ( !cin ) {
    std::cerr << "Where was the string" << std::endl;
    std::cin.clear();
}

(And don't use a non-initialized variable, like a , until it has been successfully input.) (并且在成功输入之前不要使用非初始化变量,例如a 。)

The second is that the >> operator only extracts the characters necessary for its target: >> to an int will stop at the first non-numeric character, and >> to a std::string at the first white space (in both cases, after having skipped leading white space). 第二个是>>运算符只提取其目标所需的字符: >> int将停止在第一个非数字字符处, >>到第一个std::string处的std::string (在这两种情况下) ,跳过领先的白色空间后)。 This means that after something like "1test\\n" , there will still be a '\\n' in the buffer. 这意味着在"1test\\n" ,缓冲区中仍然会有'\\n' And while it's generally a bad idea to mix FILE* (like getchar() ) and iostream, if they're correctly synchronized, getchar() will read this '\\n' immediately and return. 虽然混合FILE* (如getchar() )和iostream通常是个坏主意,但如果它们正确同步, getchar()会立即读取此'\\n'并返回。

If you're reading line oriented input, the best solution is to use getline() , and then put the line into a std::istringstream to parse it. 如果你正在阅读面向行的输入,最好的解决方案是使用getline() ,然后将该行放入std::istringstream来解析它。 So your code might end up looking like: 所以你的代码可能最终看起来像:

std::string line:
std::getline(std::cin, line);
if ( ! std::cin ) {
    //  Something unexpected went wrong...
    std::cin.clear();
} else {
    std::istringstream l( line );
    l >> a >> b;
    if ( !l ) {
        //  Format error in input...
    } else {
        //  use your data here...
    }
}
std::cin.get();  //  Wait for one more character...

When you enter a char and wanted to read an int , the cin stream will have its failbit set. 当您输入char并想要读取intcin流将设置其failbit Calling cin.fail() will return true if the operation failed (ether failbit or badbit is set). 如果操作失败(调用ether failbitbadbit cin.fail()则调用cin.fail()将返回true You can act accordingly from there. 你可以从那里采取相应行动。

Note that cin can be converted to bool for testing, and according to the standard this boolean value is the same as !cin.fail() , and !cin is the same as cin.fail() . 请注意, cin可以转换为bool进行测试,根据标准,此布尔值与!cin.fail()相同,并且!cincin.fail()相同。 Both of the following are the same, but some people may consider the second more readable. 以下两个都是相同的,但有些人可能会认为第二个更具可读性。

if(!cin) {
  // cin is in failed state
}

if(cin.fail()) {
  // cin is in failed state
}

Once cin is in a fail state, any read operation with cin will be a no-op until you reset the stream to a good state. 一旦cin处于失败状态,在将流重置为良好状态之前,使用cin任何读操作都将是无操作。 You can do that by calling cin.clear() . 你可以通过调用cin.clear()来做到这cin.clear()

But you must also realize that the offending characters are still in the stream. 但是你也必须意识到有问题的角色仍在流中。 That is, the non-integer character that caused the failed state will still be in the stream. 也就是说,导致失败状态的非整数字符仍将在流中。 How you handle this depending on how you want to recover from the error. 如何处理此问题取决于您希望如何从错误中恢复。 One possibility is to call 一种可能是打电话

cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

This will clear out the current line. 这将清除当前行。 Then you can prompt for the input again. 然后,您可以再次提示输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM