【问题标题】:std::cin >> c; gets ignored after reading numbers into array标准::cin >> c;将数字读入数组后被忽略
【发布时间】:2021-03-02 08:39:44
【问题描述】:

我正在尝试将一些数字输入到数组中。 非常简单的任务。

int array[100], n = 0, length = 0;
std::cout << "Input numbers: " << std::endl;
while (std::cin >> n) {
    array[length++] = n;
}

我在 CLion 中按shift + F10,试图运行它并

它不会结束一段时间(我连续按了 5 次 Enter),它会一直持续下去。 我在这里做错了吗?

我尝试在每次输入后使用std::cin.ignore()。好像没什么效果。

谢谢!

编辑:当我按下ctrl-D 时它确实成功结束,但我遇到了另一个问题。 (我修改了标题)

我有这个程序:

void read_input(int arr[], int &length) {
    int n = 0;
    std::cout << "Read input: " << std::endl;
    while (std::cin >> n) {
        arr[length++] = n;
    }
}

int main() {
    int array[100], length = 0;
    int c = -1;

    while (true) {
        std::cout << "Menu: (TO DO)\n";
        std::cout << "Your option: ";
        std::cin >> c;

        if (c == 1) {
            read_input(array, length);
        }
        if (c == 0) break;
    }
}

会发生什么,我输入选项:

1
Read input:
1
2
3
4
^D

Menu: (TO DO)
Your option:
Read input:
Menu: (TO DO)
Your option:
Read input:
Menu: (TO DO)
Your option:
Read input:
...

基本上,在它进入 read_input() 并给它一些数字之后,我按 ctrl-D 并且它不会再次询问我输入/选项,它只会再次读取1 for std::cin &gt;&gt; c;一次又一次,它将永远持续下去。

【问题讨论】:

  • 使用特定于平台的 EOF 键盘快捷键(Linux/macOS 上为Ctrl-D,Windows 上为Ctrl-Z)。
  • 请查看编辑。
  • 当您给 EOF 输入时,输入流处于无法再次使用的状态。你需要clear那个状态才能再次使用它。
  • 我不知道我做的对不对,但是我把std::cin.clear();放在了while循环之后read_input()的末尾,这样我就可以让输入再次可用,如果我理解的没错。但是现在,在我按下ctrl-D 之后,它就退出了程序(它退出了 while(true) 循环)。
  • 您是否也在 ignore()'ing Ctrl-D 本身,因此它不会在输入缓冲区中逗留?

标签: c++ iostream clion


【解决方案1】:

Ctrl+D 之前读取用户输入的方法不是一个好主意,因为它会给您的程序带来很多问题,并且在其他平台上运行时可能会出现潜在错误。 Ctrl+D 关闭系统级管道,所以我不确定在被EOF 停止后是否有适当的方法来恢复输入流。正如我所说,即使您找到了适用于您的环境的解决方案,但仍有可能出现潜在错误。因此,我的建议是使用哨兵(这里是eof 作为字符串)来替换Ctrl+D

#include <iostream>
#include <string>


void read_input(int arr[], int &length) {
    std::cout << "Read input (enter `eof` when you are done): " << std::endl;

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

    std::string number; 
    while (std::getline(std::cin, number) && number != "eof")
    {
        arr[length++] = std::stoi(number);
    }
}

int main() {
    int array[100], length = 0;
    int c = -1;

    while (true) {
        std::cout << "Menu: (TO DO)\n";
        std::cout << "Your option: ";
        std::cin >> c;

        if (c == 1) {
            read_input(array, length);
        }
        if (c == 0) break;
    }
}

输出:

Menu: (TO DO)
Your option: 1
Read input (enter `eof` when you are done): 
1
2
3
eof
Menu: (TO DO)
Your option: 1
Read input (enter `eof` when you are done): 
1
2
3
4
5
eof
Menu: (TO DO)
Your option: 2
Menu: (TO DO)
Your option: 0
Process exited with status 0

你可以用任何你喜欢的东西替换eof,除了这个任务的数字。

【讨论】:

    【解决方案2】:

    你应该使用 for 循环:

    for(int i=0; i<5; i++)
    {
      std::cin>>n;
      array[i]=n;
    }
    

    或者如果您想在换行符上完成输入:

    std::string input="";
    while(input!="\n")
    {
      getline(std::cin,input);
      n=std::stoi(input);
      array[length++]=n;
    }
    

    【讨论】:

    • sizeof(array) 将在任何标准 PC 上为您提供 400,这将超出数组的范围。如果用户想提前停止,不要停止。
    • 您的编辑也不起作用,因为字符串的 &gt;&gt; 运算符读取 空格分隔 字符串,而换行符是一个空格,不会被读取。
    【解决方案3】:

    不会从输入序列的开头丢弃空格。您可以使用 std::ws 函数丢弃空格,该函数是一个操纵器,旨在从输入流的开头提取和丢弃前导空格。

    你可以使用 from getline() 来做。

    #include <iostream>
    #include <string>
    
    void read_input(int arr[], int& length) {
        int n = 0;
        std::cout << "Read input: " << std::endl;
        std::string num_str{};
        while (std::getline(std::cin >> std::ws, num_str)) {
            try
            {
                n = std::stoi(num_str);
                arr[length++] = n;
            }
            catch(...)
            {
                break;
            }
        }
    }
    
    int main() {
        int array[100], length = 0;
        int c = -1;
        
        while (true) {
            std::cout << "Menu: (TO DO)\n";
            std::cout << "Your option: ";
    
            std::string str;
            std::getline(std::cin >> std::ws, str);
            try
            {
                c = std::stoi(str);
            }
            catch(...)
            {
                c = -1;
            }
            
            if (c == 1) {
                read_input(array, length);
            }
            if (c == 0) break;
        }
    }
    

    【讨论】:

      【解决方案4】:

      您很可能只需要在 read_input 循环结束时清除流,并确保忽略输入缓冲区中剩下的任何内容:

      void read_input(int arr[], int &length) {
        int n = 0;
        std::cout << "Read input: " << std::endl;
        while (std::cin >> n) {
          arr[length++] = n;
        }
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      }
      

      虽然Ctrl-D 标记序列的结束似乎是一个不寻常的选择,但为什么不使用专用字符来标记输入的结束并安全地丢弃它。

      【讨论】:

      • 因为我不知道什么是正确的做法。我按照建议添加了 cin.clear() 和 cin.ignore() 现在,它返回菜单,没有无限循环,但是如果我输入另一个选项(数字)它不会做任何事情,它不会读取值,即使我按ctrl-D
      • @yierstem 我不太明白,您能否通过示例输出澄清一下?
      • @yierstem 我回答的第二部分是关于使用 Ctrl-D 来停止输入序列 - 这可能不是最好的,因为它在大多数 *nix 系统中关闭了系统级管道。因此建议使用专用字符/字符串作为标记来标记输入的结束。 Thang 的回答中似乎已经详细阐述了这种方法。
      【解决方案5】:

      您的问题似乎是n 的值;你输入\n时是0吗?

      我喜欢here 给出的解决方案:用返回字符串的getline() 捕获cin。然后您可以通过isempty() 检查是否有任何输入。您需要使用stof()stol() 转换为数字,但这应该是可行的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-28
        • 1970-01-01
        相关资源
        最近更新 更多