0
votes

This code takes multiple ints and puts it into a vector when the "Enter" key is pressed. The output shows all the elements within the vector; each element separated with commas. The problem is the "Enter" key does not exit the while cin loop when I enter a letter or space at the end. For example:

Input: 4 55 6 2 1g // pressing enter here will make it go to the next line, and does not break the while-loop

How it normally works:

Input: 4 55g 6 2 1 // If I press enter here, it will ignore the "g" and print the number elements from the vector, separated by a comma, which is what I want, but this does not happen if the "g" is at the very end

Output: 4, 55, 6, 2, 1

The problem only consists, when I enter a non-numeric input at the end, and not in between elements. Pressing space at the end also causes the problem

int main() {

vector<int> myv;
int value = 0;

while (cin >> value){
    myv.push_back(value);
    if (cin.get() == '\n'){
        break;
    }
}

auto iter = myv.begin();
    while(true){
        cout << *iter;
        ++iter;
        if(iter == myv.end()){
            break;
        }
        else{
            cout << ", ";
        }
    }
}
1
You are pushing back before you check if you should. - sweenish
@sweenish I tried using !cin.fail() , but the same problem persists. Any ideas? - Arîston Giltedged
List your requirements better. Are the ints always single digit? It also makes sense that your first while loop is infinite. It never fails. Every ASCII character can be converted to an int. - sweenish
@sweenish No, the ints are not always in single digits. Double digits also work. Cin breaks down numbers by spaces automatically. - Arîston Giltedged
You don't need to explain std::cin to me. I'm just trying to get clarification on your actual requirements. - sweenish

1 Answers

0
votes

Your biggest issues were:
- The letter you entered just before pressing enter is still in the stream. So your std::cin.get() check won't identify the Enter key, but will instead identify the letter.
- You pushed back to your vector before checking if you should have. Those letter 'g's are going into your vector.

This code is more complicated due to what appears a desire to enter the data all at once on one line and process it after the fact. So I simply read the line in using std::getline() and process that total input in the function break_up(). At this point I have a vector of strings containing all the separate pieces that were entered, valid or not.

Finally, the chunks are checked for validity. As soon as a chunk that cannot be fully converted to an integer is found, myv stops receiving data. Then it's printed. I replaced your while loop with a shorter for loop.

If each piece of data was entered individually and checked as you went, then this program becomes far easier. The toughest bit of breaking up the line goes away, and you can verify as you go and stop exactly when bad data is encountered, as opposed to entering a ton of data just to find that 80% of it didn't get added.

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string> break_up(std::string line) {
  std::vector<std::string> chunks;

  // Emtpy line check
  if (line.length()) {
    std::string::size_type loc = 0;
    std::string::size_type subStart = 0;
    while (loc != std::string::npos) {
      loc = line.find_first_of(" \t\r\n", loc + 1);
      loc != std::string::npos
          ? chunks.push_back(line.substr(subStart, loc - subStart))
          : chunks.push_back(line.substr(subStart));  // catches last item
      subStart = loc + 1;
    }
  }

  return chunks;
}

int main() {
  std::vector<int> myv;
  std::string values;  // Changed type

  std::getline(std::cin, values);
  std::vector<std::string> chunks = break_up(values);

  for (auto i : chunks) {
    // std::size_t pos;
    try {
      int num = std::stoi(i); // , &pos);
      // if (pos == i.length()) {
        myv.push_back(num);
      // } else {
      //   break;  // Remove this else block to add all valid numbers that
      // }         // were entered
    } catch (...) {
    }  // std::stoi throws two exceptions, don't need to
       // distinguish or take any action. Just don't want the program ending
  }

  // Replaced unnecessarily complicated while loop
  for (unsigned int i = 0; i < myv.size(); ++i) {
    std::cout << myv[i];
    if (i < myv.size() - 1) {
      std::cout << ", ";
    }
  }
  std::cout << '\n';
}

EDIT: I made some slight changes to the code to clear up the misunderstanding of what the desired output is. I left the older code commented out.