gpt4 book ai didi

c++ - 对 std::cin 的澄清

转载 作者:行者123 更新时间:2023-11-30 02:08:24 25 4
gpt4 key购买 nike

这直接摘自 Bjarne Stroustrup 的“C++ 编程语言”。我只想澄清一下他是如何将数字累加到变量 (int number_value) 中的。请不要撕毁代码,它不是我写的(帖子底部第 6 章的完整代码)。

特别是当解析器调用词法分析器时,词法分析器如何使用 cin 构建一个数字。我相信答案就在这八行中,但我想解释一下它是如何工作的。

if( isalpha( ch ) ) {
(*input).putback( ch );
(*input) >> string_value;
return curr_tok=NAME;
} else {
error( "bad token " );
return curr_tok=PRINT;
}

在我看来,第一次调用 get_token( ) 时,它将完整的 expression_list 放入 cin 或任何输入流输入指向(在 get_token( ) 内部)。

(*input) >> ch;

我知道 ch 被声明为 char,但是如果您键入 123.4+5.432 会发生什么; (假设输入是 cin)cin 现在包含其流中包含的“字符串”123.4+5.432。然后我们转到词法分析器中的 switch 语句 (get_token())。我假设::

ch == 1?

此时?接下来在 switch 语句中,我们将“通过”到“。”案件。在这里,我们将“1”放回流中并将其写出到 number_value?

(*input).putback( ch );
(*input) >> number_value;

现在 number_value = 1,我们返回解析器。由于我们找到了一个 NUMBER,它再次调用 get_token()。并再次调用 cin operator<<。下一次调用 (*input)>> number_value 不会将 2 放入数字值中以覆盖 1(假设输入仍然是 123.4+5.432)吗?这里发生了什么。我想我需要更好地了解流的工作原理。如果有人能花时间给我一个简短的解释并指出一个好的资源,我将不胜感激。

谢谢,

马修霍根

对于那些没有这本书的人,代码是:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <map>
#include <cctype>

std::istream *input;

double number_value;
int no_of_errors;
std::string string_value;
std::map<std::string,double> table;

enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};

Token_value curr_tok=PRINT;

double expr( bool );
double term( bool );
double prim( bool );
Token_value get_token( );
double error( std::string s ) {
no_of_errors++;
std::cerr << "error: " << s << std::endl;
return 1.0;
}

Token_value get_token( ) {
char ch = 0;
(*input) >> ch;

switch( ch ) {
case 0: {
return curr_tok=END;
}
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=': {
return curr_tok = static_cast<Token_value>( ch );
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.': {
(*input).putback( ch );
(*input) >> number_value;
return curr_tok=NUMBER;
}
default: {
if( isalpha( ch ) ) {
(*input).putback( ch );
(*input) >> string_value;
return curr_tok=NAME;
} else {
error( "bad token " );
return curr_tok=PRINT;
}
}
}
}

int main( int argc, char *argv[ ] ) {
switch( argc ) {
case 1: {
input = &std::cin;
break;
}
case 2: {
input = new std::istringstream( argv[1] );
break;
}
default: {
error(" To many arguments" );
return 1;
}
}
table["pi"] = 3.1415926535897932385;
table["e"] = 2.7182818284590452354;

while( (*input) ) {
get_token( );
if( curr_tok == END ) {
break;
}
if( curr_tok == PRINT ) {
continue;
}
std::cout << expr( false ) << std::endl;
}

if( input != &std::cin ) {
delete input;
}

return 0;
}

double expr( bool get ) {
double left = term( get );

for( ; ; ) {
switch( curr_tok ) {
case PLUS: {
left += term( true );
break;
}
case MINUS: {
left -= term( true );
break;
}
default: {
return left;
}
}
}
}

double term( bool get ) {
double left = prim( get );
for( ; ; ) {
switch( curr_tok ) {
case MUL: {
left *= prim( true );
break;
}
case DIV: {
if( double d = prim( true ) ) {
left /= d;
break;
}
else {
return error( "divide by 0" );
}
}
default: {
return left;
}
}
}
}

double prim( bool get ) {
if( get ) {
get_token( );
}

switch( curr_tok ) {
case NUMBER: {
double v = number_value;
get_token( );
return v;
}
case NAME: {
double &v = table[string_value];
if( get_token( ) == ASSIGN ) {
v = expr( true );
return v;
}
}
case MINUS: {
return -prim( true );
}
case LP: {
double e = expr( true );
if( curr_tok != RP ) {
return error( "')' expected" );
}
get_token( );
return e;
}
default: {
return error( "primary expected" );
}
}
}

最佳答案

“诡计”是由以下三行的不同行为引起的:

char ch;                   std::cin >> ch;
std::string string_value; std::cin >> string_value;
double number_value; std::cin >> number_value;

第一个只获取一个字符,第二个和第三个获取多个 个字符以构建正确类型的变量。

字符串重载全局operator>>函数为字符串提供一个版本,这个版本使用空格作为分隔符(如果你的字符串需要输入空格,你应该查看getline).

double 版本使用 istream& operator>> (double& val); 成员函数,并且只读取对形成 double 值有意义的字符。

那么,假设您输入 abc。代码 cin >> ch 将使用字符 'a' 填充 ch,并将其从输入流中移除。然后,您将在默认情况下使用 isapha 检测到它,因为它不匹配任何其他情况。

此时,您将该字符 'a' 推回输入流以便重新读取它,然后执行 cin >> string_value 得到整个字符串abc不是单个字符。

同样,如果您输入 3.14159,它会被 case '3' 检查捕获,该字符将被推回输入流,并且 cin >> number_value 将得到整个值。

关于c++ - 对 std::cin 的澄清,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6893650/

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