The cin statement is ignored - c++

I am trying to write a program to find specific word in several sentences, but something went wrong when I tried to input a word, I've tried cin.ignore(),cin.sync() and cin.clear(), all not working.
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> svec;
cout << "please input text:(at most 10 lines): " << endl;
while(svec.size() < 10) {
string sentence;
getline(cin, sentence);
transform(sentence.begin(), sentence.end(), sentence.begin(), ::tolower);
svec.push_back(sentence);
if(cin.eof())
break;
}
// I tried to clean up cin here by
// cin.ignore() , cin.sync() and cin.clear()
// none of them work
string wordToFind;
cout << "please input the pattern: ";
cin >> wordToFind; // This line isn't working
// If I print out wordToFind, it contains nothing
transform(wordToFind.begin(), wordToFind.end(), wordToFind.begin(), ::tolower);
bool isFind = false;
int whichLine = 1;
for(vector<string>::iterator iter = svec.begin(); iter != svec.end(); iter++, whichLine++) {
size_t pos = 0;
while((pos = iter->find(wordToFind, pos)) != string::npos) {
cout << "Found at" << endl;
cout << "Line " << whichLine << " column " << pos++ << endl;
isFind = true;
}
}
if(isFind == false)
cout << wordToFind << " not found";
return 0;
}
I have no idea what is going on for cin, is that a problem of the cin buffer or other related issue?

Related

How can I store input after a comma as an integer?

I've been working on a program to display user input in a table and a histogram, I've got those down, but I can't figure out how to take the user input and separate it by a comma and save the first part as a string and the second as an integer. I used streams but it separates it by spaces and the string might need to have spaces in it, so that's not reliable. I also tried substrings but I need the second half to be an int. Any tips are appreciated. Thank you.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <ctype.h>
using namespace std;
int main() {
string title, col1, col2, userInput, one, two;
istringstream inSS;
string lineString;
string author;
int books;
vector<string> vecAuthors;
vector<int> vecBooks;
bool inputDone;
cout<<"Enter a title for the data:"<<endl;
getline(cin, title);
cout<<"You entered: "<<title<<endl;
cout<<"Enter the column 1 header:"<<endl;
getline(cin, col1);
cout<<"You entered: "<<col1<<endl;
cout<<"Enter the column 2 header:"<<endl;
getline(cin, col2);
cout<<"You entered: "<<col2<<endl;
while (!inputDone) {
cout<<"Enter a data point (-1 to stop input):"<<endl;
getline(cin, lineString);
while (lineString.find(',') == string::npos) {
if (lineString == "-1") {
break;
}
cout << "Error: No comma in string.\n" << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
string::size_type position = lineString.find (',');
if (position != string::npos)
{
while (lineString.find (',', position+1) != string::npos) {
if (lineString == "-1") {
break;
}
cout << "Error: Too many commas in input." << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
}
one = lineString.substr(0, lineString.find(','));
two = lineString.substr(lineString.find(',') + 1, lineString.size() - 1);
inSS.clear();
inSS.str(lineString);
inSS >> author;
inSS >> books;
if (inSS.fail()) {
if (lineString == "-1") {
break;
}
cerr << "Error: Comma not followed by an integer." << endl << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
inSS.clear();
inSS.str(lineString);
inSS >> author;
if (author == "-1") {
cout<<"Finished."<<endl;
inputDone = true;
}
else {
inSS >> books;
author.pop_back();
vecAuthors.push_back(author);
vecBooks.push_back(books);
cout << "Data string: " << author << endl;
cout << "Data integer: " << books << endl;
}
}
cout<<setw(33)<<right<<title<<endl;
cout<<setw(20)<<left<<col1<<"|";
cout<<setw(23)<<right<<col2<<endl;
cout<<setfill('-')<<setw(43)<<""<<endl;
cout<<setfill(' ');
for(int i=0; i<vecAuthors.size(); ++i){
cout<<setw(20)<<left<<vecAuthors[i]<<"|"<<setw(23)<<right<<vecBooks[i]<<endl;
}
cout<<endl;
for(int i=0; i<vecAuthors.size(); ++i){
cout<<setw(20)<<right<<vecAuthors[i];
for(int k = 0; k<vecBooks[i]; ++k) {
cout<<left<<"*";
}
cout<<endl;
}
return 0;
}
Code to get the first part to a string and second part to an int:
#include <iostream>
#include <string>
int main()
{
std::string input{};
std::cin >> input;
int commaSlot{};
for (int i = 0; i < input.length(); i++) {
if (input[i] == ',') {
commaSlot = i;
break;
}
}
std::string firstPart = input.substr(0,commaSlot);
int secondPart = std::stoi(input.substr(commaSlot+1));
std::cout << firstPart << " " << secondPart;
}
because what you need is quite custom (you need comma as a separator and not space ) you can get a line and parse it as you want with the getline function of std afterwards you can separate the string on the comma (the simplest way I can think off is a simple for loop but you can use std's algorithm's also) and then you can use the stoi function to convert a string to an int ,all of them together:
std::string row{};
unsigned positionofcomma{};
std::getline(std::cin,row);
for (unsigned i=0;i<row.length();i++)
if (row[i]==','){
positionofcomma=i;
break;
}
std::string numberstring=row.substr(positionofcomma+1, row.length());
int number=std::stoi(numberstring);

How to print `[` and `,` and `]` in streams that extract from keyboard by `cin`

I'm new in c++. I want to print [ at the beginning and ] at the end of stream when i print some string by keyboard. also it must be print , between each of string. notice number of strings is unknown. for example if i print in screen: ggg hhh jj klk the result of program must be: [ggg,hhh,jj,klk]. I've tried this:
string cur = "";
while (cin >> cur)
{
cout << "[" << cur << ",";
}
but this wrong!
Edit: by #NadavS 'sanswer we have this:
by #asmmo 's answer we have this:
but my expectation is:
sss ddd fff ggg
[sss,ddd,fff,ggg]
ddf hjh lk iop
[ddf,hjh,lk,iop]
If your compiler supports it, std::experimental::ostream_joiner does this.
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
int main()
{
std::cout << "[";
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::experimental::make_ostream_joiner(std::cout, ","));
std::cout << "]";
}
Outputs [ggg,hhh,jj,klk] from ggg hhh jj klk
I always program these loops with some code duplication. There are other solutions, but the general concept is separating the first case from the others.
string cur = "";
cout << '[';
if (cin >> cur) {
cout << cur;
while (cin >> cur) {
cout << ',' << cur;
}
}
cout << ']';
Demo
edit: Despite the fact this solution works, the question asker views his "stdin" and "stdout" in "the same window", so the output doesn't look pretty, and the solution should be to store a list of strings from cin and only then start printing.
string cur = "";
std::vector<string> all_strings;
while (cin >> cur) {
all_strings.push_back(cur);
}
cout << '[';
bool first = true;
for (auto& a : all_strings) {
if (first) {
first = false;
} else {
cout << ", ";
}
cout << a;
}
cout << ']';
You must make the loop stop at some point but you didn't. So you can send an EOF at the end of your inputs to make it stops (using ctrl+z on windows and ctrl+D on other OSs). And to get the wanted format change your loop to
int main()
{
string cur = "";
cout << "[ ";
if( cin >> cur) cout << cur;
while (true)
{
cin >> cur;
if( !cin )
{
cout << "]" ;
break;
}
cout << "," << cur;
}
}
If you want to separate the inputs and outputs, you can do the following
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> vec;
std::string temp{};
while(std::cin >> temp) vec.push_back(temp);
std::cout << "\n[ " << vec[0];
for(int i {1}; i < vec.size(); i++) std::cout << ", " << vec[i];
std::cout << "]";
}
To make cin stop inputting on pressing Enter, use std::cin.peek() which can know the next character without taking it from the stream, as follows
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> vec;
std::string temp{};
while(std::cin >> temp && !(std::cin.peek() == '\n')) vec.push_back(temp);
std::cout << "\n[" << vec[0];
for(int i {1}; i < vec.size(); i++) std::cout << ", " << vec[i];
std::cout << "]";
}

string iterator not decrementable

I have an issue with string::iterator. VS says string iterator not decrementable. My first project works fine with the same function Is_Palindrom
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator>
#include <algorithm>
#include <iterator>
#include <cctype>
using namespace std;
string Is_Palindrom(string str)
{
string::iterator iter = str.begin();
transform(str.begin(), str.end(), str.begin(), tolower);
for (iter; iter != str.end(); iter++)
{
if (ispunct(*iter) || *iter == *" ")
{
str.erase(iter);
iter--;
}
}
return str;
}
void main()
{
ostream_iterator<string, char>out(cout, "\n");
string tmp;
vector<string>str;
while (getline(cin, tmp) && tmp != "quit")
str.push_back(tmp);
transform(str.begin(), str.end(), out, Is_Palindrom);
}
But if I load some words from a .txt and apply Is_Palindrome function it crashes, but if I change string::iterator to a simple loop with a [ ] access it works correct.
Here the problem code.
#include <cstdlib>
#include <ctime>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <valarray>
#include <functional>
#include <iterator>
#include <algorithm>
#include <iterator>
#include <cctype>
using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::tolower;
using std::endl;
using std::ifstream;
string Is_Palindrom(string str);
int main()
{
vector <string> wordlist;
std::srand(std::time(0));
ifstream fin;
fin.open("text.txt");
if (fin.is_open() == false)
{
std::cerr << "Can't open file. Bye.\n"; // не удается открыть файл
exit(EXIT_FAILURE);
}
string item;
int count = 0;
getline(fin, item, ' ');
wordlist.push_back(item);
transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);
while (fin) // до тех пор, пока нет ошибок ввода
{
cout << count << " : " << wordlist[count] << endl;
++count;
getline(fin, item, ' ');
wordlist.push_back(item);
transform(wordlist.begin(), wordlist.end(), wordlist.begin(), Is_Palindrom);
}
cout << "Done\n";
fin.close();
char play;
cout << "Will you play a word game? <y/n> "; // запуск игры в слова
cin >> play;
play = tolower(play);
while (play == 'y')
{
string target = wordlist[std::rand() % wordlist.size()];
int length = target.length();
string attempt(length, '-');
string badchars;
int guesses = 6;
cout << "Guess my secret word. It has " << length
<< " letters, and you guess\n"
<< "one letter at a time. You get " << guesses
<< " wrong guesses.\n";
cout << "Your word: " << "attempt" << endl; // вывод слова
while (guesses > 0 && attempt != target)
{
char letter;
cout << "Guess a letter: ";
cin >> letter;
if (badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
{
cout << "You already guessed that. Try again.\n";
continue;
}
int loc = target.find(letter);
if (loc == string::npos)
{
cout << "Oh, bad guess !\n";
--guesses;
badchars += letter; // добавить к строке
}
else
{
cout << "Good guess!\n";
attempt[loc] = letter;
// Проверить, не появляется ли буква еще раз
loc = target.find(letter, loc + 1);
while (loc != string::npos)
{
attempt[loc] = letter;
loc = target.find(letter, loc + 1);
}
}
cout << "Your word: " << attempt << endl;
if (attempt != target)
{
if (badchars.length() > 0)
cout << "Bad choices: " << badchars << endl;
cout << guesses << " bad guesses left\n";
}
}
if (guesses > 0)
cout << "That's right!\n";
else
cout << "Sorry, the word is " << target << " . \n";
cout << "Will you play another? <y/n> ";
cin >> play;
play = tolower(play);
}
cout << "Bye\n";
return 0;
}
string Is_Palindrom(string str)
{
string::iterator iter = str.begin();
//for (int i = 0; i < str.length(); i++)
for (iter; iter != str.end(); iter++)
{
//if (ispunct(str[i]) || str[i] == *" ")
if (ispunct(*iter) || *iter == *" ")
{
//str.erase(i, 1);
//i--;
str.erase(iter, iter+1);
if (iter == str.end())
break;
iter--;
}
}
return str;
}
The problem in your code is
if (ispunct(*iter) || *iter == *" ")
{
str.erase(iter);
iter--;
}
First, if you want to check a character you should use ' not ". So your
statement should be
if (ispunct(*iter) || *iter == ' ')
//or even better
if (ispunct(*iter) || isspace(*iter))
Secondly, you are using erase(). When you call erase it invalidates all references and iterators to the current element to the end. Since you are using the same iterator that you used to delete the element this is undefined behavior. Just because it works in the first example doesn't mean it will work in another piece of code. Luckily erase() returns an iterator to the element after the erased element. We can capture that iterator and use that for the next iteration. In order to do this, you need to change your for loop into a while loop like:
while(iter != str.end())
{
if (ispunct(*iter) || isspace(*iter))
iter = str.erase(iter); // erase and don't increment as we are already on the next character
else
iter++; // increment since it was a valid character
}

C++: Save information from console, then when reopened, information is still there

I have a program that saves your favorite games for you onto a list. How would I make it so that if I close the console and reopen it, the list is still there, and all the elements in the array are saved?
using namespace std;
int main()
{
vector<string> games;
vector<string>::iterator iter;
while(true)
{
system("cls");
string response;
cout << "\tFavorite Videos Games \n\n";
cout << "Type 'add' to add a game.\n";
cout << "Type 'remove' to remove a game.\n";
cout << "Type 'list' to list all games.\n\n";
cout << "Type 'quit' to close and save the program.";
cout << "What would you like to do: ";
cin >> response;
cout << endl;
if ((response == "add") || (response == "remove") || (response == "list"))
{
int number;
string gameName;
if(response == "add")
{
cout << "What is the name of the game you would like to add?\n";
cout << "Name: ";
cin >> gameName;
games.push_back(gameName);
cout << gameName << " was added to the system.\n\n";
Sleep(2000);
continue;
}
if(response == "remove")
{
vector<string>::iterator linesIn;
int spacesIn;
cout << "What game should be deleted?\n\n";
cout << "All Games:\n-----------\n";
for(iter = games.begin(); iter != games.end(); ++iter)
{
number ++;
cout << number << ". " << *iter << endl;
}
cout << "Number: ";
cin >> spacesIn;
spacesIn = spacesIn -1;
linesIn = games.begin() + spacesIn;
cout << *linesIn << " was deleted.";
games.erase(linesIn);
Sleep(2000);
}
if(response == "list")
{
cout << "All Games:\n-----------\n";
for(iter = games.begin(); iter != games.end(); ++iter)
{
number ++;
cout << number << ". " << *iter << endl;
}
cout << "\n\nPress any key to continue...";
getch();
}
}
else if (response == "quit")
break;
else
{
cout << "\nInvalid action.\n\n";
Sleep(2000);
continue;
}
}
return 0;
}
The easiest way would be to save it out to file.
Example from http://www.cplusplus.com/doc/tutorial/files/:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
Perhaps add another option called save, and just iterate through the games and add them to a file called "mygames.txt."
Then add an option called "load saved games" and do something like:
string line;
ifstream myfile ("example.txt");
if (myfile.is_open()){
while ( getline (myfile,line) ){
games.push_back(line);
}
myfile.close();
Obviously, these are just examples, but I feel it is clear enough that you can take it form here.
Save the information to file.
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
else if ( response == "quit") {
std::ofstream f( "list.txt");
if( !f) return -1;
std::vector<std::string> games;
std::copy( std::istream_iterator<std::string>(f), // copy file content
std::istream_iterator<std::string>(), games.begin()); // to vector
}
On the start of program:
int main()
{
std::ifstream f( "list.txt");
if( !f) return -1;
std::copy( istream_iterator<std::string > (f), // copy file content to vector
std::istream_iterator<std::string > (), std::back_inserter(games));
//...
Complete example:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main( int argc, char** argv) {
fstream f;
f.open( "list.txt", std::ios::in);
if (!f) return -1;
vector<string> games;
copy( istream_iterator<string > (f), // copy file content to vector
istream_iterator<string > (), back_inserter(games));
f.close();
string response;
while ( 1) {
cin >> response;
if ( ( response == "a")) {
int number; string gameName;
cout << "What is the name of the game you would like to add?\n";
cout << "Name: "; cin >> gameName;
games.push_back(gameName);
cout << gameName << " was added to the system.\n\n";
} else if ( response == "q") {
f.open( "list.txt", std::ios::out);
if ( !f) return -1;
copy( games.begin(), games.end(), // copy from vector to a file
ostream_iterator<string > ( f, "\n"));
f.close();
return 0;
}
}
}

Questions on while loop exercise

int main()
{
int number_of_words = 0;
int prevnum = -1;
string previous = "";
string current;
while (cin >> current)
{
++number_of_words;
if (previous == current)
{
cout << "word number: " << number_of_words << "\n"
<< "Repeated Word: " << current << "\n";
previous = current;
}
else while (prevnum == number_of_words)
{
number_of_words = 0;
prevnum = 0;
break;
}
}
}
In this app, I'm trying to display repeated words and their position number within the text. When it finishes running the inputted statement, it keeps the number_of_words for the next input. I tried fixing this with the else while condition, at which the while loop would break.
What should I do differently?
Does the while loop run again after breaking or would i need to put this into another while loop that prompts the user on whether or not they are ready to type in some text?
*this is Ch. 3 so I'm guessing I should just move on but was curious
Try this:
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
int number_of_words;
string previous;
string current, input;
while (true)
{
previous = "";
number_of_words = 0;
cout << "\nWrite the data\n";
getline(std::cin, input);
stringstream ss;
ss << input;
while (ss >> current)
{
++number_of_words;
if (previous == current)
cout << "word number: " << number_of_words << "\n"
<< "Repeated Word: " << current << "\n";
previous = current;
}
}
}
I have used an stringstream variable to break every loop of input, so i could reset the counters.