2011-12-13 46 views
0

我无法使用cin方法获取变量。当输入是一个数字时没有问题,但是当它是一个特殊字符,如点[。],while循环到无穷大时。 我在做什么错?当cin的输入是'点'时循环到无限

cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
    while(*race<1||*race>3) 
    { 
    system("cls"); 
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
    } 

我搜索的答案,我应该有刷新缓冲区,但我不“吨得到如何做到这一点。我是相当新的C + +。感谢名单

+2

什么是种族? –

+0

变数竞赛是一个INT – Rps

+0

@RPS:不,它不是。如果'race'的类型是'int',那么'* race'将是一个错误,编译器会拒绝它。 –

回答

2

race的字符,然后你将能够做到:

while (*race < '1' || *race > '3') 

这可能是你想达到什么

说明:

当您将cin >>转换为int时,它将给定的ASCII字符串转换为整数值。 .没有整数意义,所以它不会被读入race,并且failbit已被设置 - 除非您清除它们,否则它们将为空操作。但是,如果您将cin >>转换为char并将其与其他char s(以及它们的ASCII代码,实际上)进行比较,您将可以毫无困难地检查它。

+0

解决方案可能是实际需要的(尽管它没有解决所有问题),但解释是不正确的。当你把'cin >>'变成一个'int',并且输入流包含一个''.''时,''失败位'被设置在'cin'中,并且所有进一步的输入在清除之前变为空操作。 (当然,他也需要删除违规字符;'cin.ignore(INT_MAX,'\ n');'可能是最合适的。)如果有的话,你的解决方案将进入无限循环'cin'上的任何其他错误,就像文件结尾一样。 –

+0

嗯,看起来你通常是正确的,但在上一个陈述中是错误的 - 你不会从'stdin'获得EOF。 – Griwes

+0

既然什么时候?该标准肯定支持它,并且我知道了所有的实现。 'cin'遇到文件结尾时应该发生什么,如果不是文件结束的情况? –

1

除了一个接受的其他解决办法是清除CIN的failbit而忽略了最后一个输入象下面这样:

cout << "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
cin >> *race; 
while(*race<1||*race>3) 
{ 
    // Clears the state of cin to be in good state 
    cin.clear(); 
    // Ignores the last input read so that it's not read back again 
    cin.ignore(); 
    system("cls"); 
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Human\n2.troll\n3.zombie"<<endl; 
    cin >> *race; 
} 
+0

这不是你正在清除的'badbit',而是'failbit'。 (但'cin.clear()'将它们全部清除,并且是正确的解决方案。) –

+0

@JamesKanze:感谢您的更正。为那些对此解决方案感兴趣的人编辑答案。 –

1

这个例子正是再现您的问题:

#include <iostream> 

int main() 
{ 
    int i = 5; 
    while (i < 1 || i > 3) 
    { 
     std::cin >> i; 
    } 
} 

这里发生了什么:当operator>>未能读取一个整数(例如,当您键入一个点并按回车键)时,您键入的任何内容都会在流中保留,包括换行符。 因此,在while循环的下一次迭代中,下一个输入已经存在,因为它不是有效整数,所以循环永远不会中断。 您需要确保在operator>>失败时清空流并清除所有已设置的错误标志。

#include <iostream> 
#include <limits> 

int main() 
{ 
    int i = 5; 
    while (i < 1 || i > 3) 
    { 
     if (!(std::cin >> i)) 
     { 
      // clear streams internal error flags 
      std::cin.clear(); 
      // ignore what's left in the stream, up to first newline character 
      // or the entire content, whichever comes first 
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
     } 
    } 
} 
1

你的代码有几个问题。首先是你不要 验证你的输入成功;对于 while正确的条件应该是:

while (!cin || (*race < 1 || *race > 3)) 

书面,如果输入失败(这是发生了什么事,当你 输入'.',假设race的类型为int*),然后*race 包含其以前的价值,不管那是什么。

第二个是如果你从cin得到一个错误,你不清楚 它。一旦流处于错误状态,它将保持这种状态,直到您明确清除它为止。如果cin失败,你需要执行:

cin.clear(); 

某处循环。

第三个是,如果cin失败了,你不提取其 使它失败,使清除错误状态后,你需要 提取它的字符。鉴于你的结构化对话的方式,你可能 要不顾一切,直到行的末尾:

cin.ignore(INT_MAX, '\n'); 

您可能要做到这一点,即使cin没有失败,无论是在环 (如果由于*race < 1 || *race > 3条件而被输入),或者在 成功的情况下。或者,你可能要转移到阅读的线条, 并确保该行只包含 你感兴趣的字符后的空白。

这最后的解决方案是一个我会采用,因为它处理了相当多 所有上述问题。所以,我的代码看起来是这样的:

// return -1 on error in input, 
// throw exception on (unexpected) end of file 
int 
getRace(std::istream& source) 
{ 
    std::string line; 
    if (!std::getline(source, line)) { 
     throw std::ios_base::failure("Unexpected end of file"); 
    } 
    std::istringstream tmp(line); 
    int results; 
    return tmp >> results >> std::ws && tmp.get() == EOF 
     ? results 
     : -1; 
} 

// ... 
int race = -1; 
while (race < 0) { 
    std::cout << "What is your race\n" 
       "1. Human\n" 
       "2. Troll\n" 
       "3. Zombie\n" << std::flush; 
    race = getRace(std::cout); 
    if (race < 0) { 
     std::cout << "Wrong choice" << std::endl; 
    } 
} 

注意,通过线路输入,您避免出现任何问题与 重置格式错误,跳过错误输入或 情况下错误的重新同步。