yierstem
yierstem

Reputation: 2067

std::cin >> c; gets ignored after reading numbers into array

I'm trying to input some numbers into an array. Pretty simple task.

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

I press shift + F10 in CLion, trying to run it and

Clion terminal

it won't end the while (I pressed enter 5 times in a row), it goes on forever. am I doing something wrong here?

I tried using std::cin.ignore() after each input. It does not seem to have any effect.

Thank you!

EDIT: It does successfully end when I press ctrl-D, but I've encountered another problem. (I edited the title)

I have this program:

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;
    }
}

What happens is, I enter the option:

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:
...

Basically, after it goes into read_input() and I give it some numbers, I press ctrl-D and it won't ask me again for an input/option, it will just read 1 for std::cin >> c; again and again and it will go on forever.

Upvotes: 1

Views: 337

Answers (5)

alle_meije
alle_meije

Reputation: 2480

Your problem seems to be the value of n; is that 0 when you type \n?

I like the solution given here: to capture cin with getline() which returns a string. Then you can check with isempty() if there was any input. You will need to convert to a number with stof() or stol() but that should be doable.

Upvotes: 0

Thang Pham
Thang Pham

Reputation: 1026

The approach of reading user inputs until Ctrl+D is not a good idea since it causes many problems to your program and may have potential errors when running on other platforms. Ctrl+D closes the system level pipe so I am not sure if there is a proper way to restore the input stream after being stopped by EOF. As I said, even if you find a solution that works in your environment but there is still a chance of getting a potential bug. Therefore, my suggestion is to use a sentinel (here, eof as string) to replace 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;
    }
}

Output:

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

You can replace eof by whatever you like except numbers for this task.

Upvotes: 1

jester
jester

Reputation: 3489

You most likely just need to clear the stream at the end of the read_input loop and make sure that you ignore whatever is left in the input buffer:

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');
}

Although Ctrl-D to mark the end of the sequence seems an unusual choice, why not just use a dedicated character to mark the end of input and safely discard it.

Upvotes: 0

Alireza Abbasi
Alireza Abbasi

Reputation: 190

The whitespace will not be discarded from the beginning of the input sequence. You can discard the whitespace with using the std::ws function which is a manipulator designed to extract and discard leading whitespace from the beginning of an input stream.

You can use from getline() for do it.

#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;
    }
}

Upvotes: 0

mrkubax10
mrkubax10

Reputation: 1

You should use for loop:

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

Or if you want to finish input on newline:

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

Upvotes: 0

Related Questions