Can't exit for-loop, seemingly stuck - c++

I recently picked up coding C++ and I was learning using Bjarne Stroustrup's introductory book, and I was presented with this code:
// simple dictionary: list of sorted words
int main() {
vector<string> words;
for(string temp; cin>>temp;) // read whitespace-separated words
words.push_back(temp); // put into vector
cout << "Number of words: " << words.size() << '\n';
sort(words); // sort the words
for (int i = 0; i < words.size(); ++i)
if (i == 0 || words[i–1] != words[i]) // is this a new word?
cout << words[i] << '\n';
}
That I replicated myself:
int main() {
//variables.
vector<string> dictionary;
//prompts user to input words.
cout << "input words in the dictionary:" << endl;
while (dictionary.size() < 10) {
for (string word; cin >> word;) {
dictionary.push_back(word);
}
}
//prints out number of words in the dictionary.
cout << "number of words in the dictionary:" << dictionary.size() << endl;
//sort the words and prints them out one by one, checking for repetitions.
sort(dictionary.begin(), dictionary.end());
for (int i = 0; i < dictionary.size(); ++i)
if ((i == 0) || (dictionary[i-1] != dictionary[i]))
cout << dictionary[i] << '\t';
return 0;
}
But here's the problem, I can't exit the initial loop of inserting words inside the dictionary (the while loop I added was to try to fix it, but it seemingly doesn't work either).
Thank you for your time :).

The inner for loop will run until cin >> word is false which might not be the case if you keep adding valid strings. Moreover you do not need an extra while wrapping the for-loop. You can just do something like below or add a break statement when necessary.
for (string word; cin >> word && dictionary.size() <10;) {
dictionary.push_back(word);
}

Related

String array filled with random names

It's the first time I'm trying something with String Arrays in C++ and yep... I'm stuck.
I'm trying a small programm which will let the user enter max. 10 random Names. If the user enters '.' or has entered 10 nNames the input dialog will end. After he has done this all names will be printed out.
I tried it with a vector, but I guess I be doing something completely wrong...
#include <iostream>
#include <vector>
using namespace std;
int main()
{
char name;
int i, counter;
vector<string> namen_vec;
cout << endl << "Eingabedialog von maximal 10 Namen. " << endl;
cout << "Eingabe kann fruehzeitig mit '.' beendet werden. " << endl;
cout << "--------------------------------------------------" << endl << endl;
counter = 0;
do
{
cout << "Eingabe Name: ";
cin >> name;
namen_vec.push_back(name);
counter++;
} while (name != '.' && counter <= 9);
for (int i = 0; i < namen_vec.size(); i++)
{
cout << namen_vec[i] << endl;
}
return 0;
}
Maybe someone has one or two advices?
First of all, you have declared the variable name as char but your container vector namen_vec accepts a string. Still, the program won't be compiled successfully because the following line
while (name != '.' && counter <= 9);
as name would be a string then you have to change this as
while (name != "." && counter <= 9);

Why is one of the while loops not being executed (C++)?

I am using the book "Programming : Principles and Practice Using C++(Second Edition)" by "Bjarne Stroustrup". I am stuck in the last exercise question of the chapter 4. I have tried to look up the solutions for this particular question but I am not getting the solution for the Second Edition.
There are two extensions for this question and each one requires a while-loop. Only the first while-loop is getting executed and it doesn't matter which one I place first.
The question is "Write a program where you first enter a set of name-value pairs. Terminate input with NoName 0. Each and every name entered must be unique."
Extension for the question is "Modify the program so that when you enter the name, corresponding score will be the output."
Extension for the question is "Further modify the program so that when you enter the score, corresponding names will be the output."
int main()
{
cout << "Enter a name and score side-by-side and enter 'NoName 0' when done :\n";
int scores_temp{ 0 };
string names_temp{ 0 };
vector <int> scores;
vector <string> names;
int adder{ 0 };
while (cin >> names_temp >> scores_temp)
{
if (names_temp == "NoName")
{
if (scores_temp == 0)
{
break;
}
}
else
{
for (int i = 0; i < names.size(); i++)
{
if (names_temp == names[i])
{
adder++;
}
}
if (adder == 0)
{
names.push_back(names_temp);
scores.push_back(scores_temp);
}
else
{
cout << "\nYou can't enter the same name twice.\n\n";
break;
}
}
}
for (int j = 0; j < names.size(); j++)
{
cout << names[j] << "\t" << scores[j] << "\n";
}
cout << "Enter the name to get the corresponding score and enter Ctrl+Z when done : \n";
string name_score{ 0 };
int counter{ 0 };
while (cin >> name_score)
{
for (int l = 0; l < names.size(); l++)
{
if (name_score == names[l])
{
cout << "Score of " << names[l] << " is " << scores[l] << ".\n";
}
else
{
counter++;
}
}
if (counter == names.size())
{
cout << "Name not found.\n";
}
counter = 0;
}
cout << "Enter the score to get the corresponding names and enter a character when done : \n";
int score_name{ 0 };
int incrementer{ 0 };
while (cin >> score_name)
{
for (int k = 0; k < scores.size(); k++)
{
if (score_name == scores[k])
{
cout << "Score of " << scores[k] << " was obtained by " << names[k] << ".\n";
}
else
{
incrementer++;
}
}
if (incrementer == scores.size())
{
cout << "Score not found.\n";
}
incrementer = 0;
}
keep_window_open();
return 0;
}
The header file for the program is given by Bjarne himself. The website for the header file is :
http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h
There are two extensions for this question and each one requires a while-loop. Only the first while-loop is getting executed and it doesn't matter which one I place first.
while (cin >> name_score)
This first loop continues until cin fails. If cin has already failed, it won't even loop once.
while (cin >> score_name)
Since we only get to this second loop if cin has failed, and this loop won't even loop once if cin fails, the code inside this while loop can never execute.
You either need some way to exit that first while loop without input having to fail, like the NoName 0 does in the very first loop or you need to clear cin's fail flag between these while loops.
See Why would we call cin.clear and cin.ignore() after reading input? for more details.

c++ input for-loop followed by another input

c++ Microsoft visual studio on a windows.
im very new to coding. currently going through Programming -- Principles and Practice Using C++ by Stroupstrup and I came across a difficulty. I am to create a "score chart" with vector name and vector score from the user input. I used for-loop to get the input. now I am to modify the program so that with 2nd input from the user I can search the list and "cout<<" the score for a person. the problem is the the program completely ignores the 2nd "cin>>" command.
I search online and could not find a reasonable answer to this problem. Is there any special interaction between a for-loop input being terminated and another input (not looped)
syntax:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> name;
vector<int> score;
string temp2;
int i;
for (string temp; cin >> temp >> i;) //input terminated with "Ctrl+Z"
name.push_back(temp), score.push_back(i);
for (int i = 0; i < name.size(); ++i) {
for (int j = i + 1; j < name.size(); ++j) {
if (name[i] == name[j]) {
name[j] = "error";
score[j] = 0;
}
}
}
for (int i = 0; i < name.size(); ++i) {
cout << name[i] << "------" << score[i] << "\n";
}
cout << "name"; //this line shows in the console
cin >> temp2; //but I cannot prompt the user to input again?
return 0;
}
CTRL-Z is interpreted as "End-Of-File", such that any subsequent access to this stream will not read in items any more. The only secure way is to change program logic such that the list of names is terminated by, let's say "END", and not a CTRL-Z. Then you can continue in a save manner.
Often input from a terminal is read in line by line and parsed afterwards. This makes error handling easier. See the following code following such an approach:
#include <sstream>
int main() {
string line;
map<string,int> scoreboard;
cout << "enter name score (type END to finish):" << endl;
while (std::getline(cin, line) && line != "END") {
stringstream ss(line);
string name;
int score;
if (ss >> name >> score) {
scoreboard[name] = score;
} else {
cout << "invalid input. Type END to finish" << endl;
}
}
cout << "enter name:" << endl;
string name;
if (cin >> name) {
auto item = scoreboard.find(name);
if (item != scoreboard.end()){
cout << "score of " << name << ":" << item->second << endl;
}
else {
cout << "no entry for " << name << "." << endl;
}
}
}

First word of a phrase is dropped when I try and put it in a vector?

Sorry for the vague header. Difficult to describe. I am trying to get a phrase from the user and put that phrase into a vector, word by word, separated by spaces. For some reason when the vector is printed it completely leaves out the first word of the phrase, if that makes sense. Here's the code I have so far:
void printVector(vector<string>& words){
cout << "Print words: " << endl;
for (int i = 0; i < words.size(); i++){
if (i < words.size()){
cout << words[i] << ", ";
}
else
cout << words[i];
}
cout << endl;
}
int main(){
string phraseInput;
string stop = "done";
do{
cin >> phraseInput;
if(phraseInput == stop){
cout << "Program finished." << endl;
return 0;
}
else {
getline(cin, phraseInput);
istringstream iss(phraseInput);
vector<string> words;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(words));
printVector(words);
}
}while(phraseInput != stop);
}
Here you have taken input for two times only first one skipped
Now you should change this
else{ string temp;
getline(cin, temp);
phraseInput+=temp;
istringstream iss(phraseInput);
//.....
I think I found your answer
I tested your code with the phrase "this is line."
Your variable "phraseInput" first take "this" string.
After getline(cin, phraseInput) line.
Your variable "phraseInput" take "is line" string.
Therefore when it prints, it simply skips the first keyword.
Result is: the first string "this" is missing
I think in this way: You take two input from user.
Therefore I thought " What happens if I commented first cin? "
After commented on your first cin. I got all the string in variable "phraseInput"
Result is:
Then I thought "do while" loop also unnecessary, since it prints any word it took from user.
I also commented your "do while" loop
Here is the final version of your code.
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void printVector(vector<string>& words){
cout << "Print words: " << endl;
for (int i = 0; i < words.size(); i++){
if (i < words.size()){
cout << words[i] << ", ";
}
else
cout << words[i];
}
cout << endl;
}
int main(){
string phraseInput;
string stop = "done";
/*do{
cin >> phraseInput;
if (phraseInput == stop){
cout << "Program finished." << endl;
return 0;
}
else {*/
getline(cin, phraseInput);
istringstream iss(phraseInput);
vector<string> words;
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(words));
printVector(words);
//}
system("pause");
//} while (phraseInput != stop);
}

vector-related segmentation fault

void offer_help();
bool play_one_game();
int main() {
offer_help();
play_one_game();
}
void offer_help() {
int help_response;
cout << "Need help? (0/1) ";
cin >> help_response;
if (help_response == 1)
cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n Each guess that you enter will be a line containing 4 integers,\n separated by spaces, such as:\n\t 2 4 7 1\n FOr each guess, I will echo back a lost consisting of\n 0's and 1's, with a 1 in a given position meaning that\n you guessed the number, and a zero meaning that you didn't.\n For example, if the actual solution was 2 3 6 1, I'll respond\n\t 1 0 0 1\n See how many guesses it takes you to get the solution!\n\n If you want to give up, type a negative number for one of\n your guesses, and we'll tell you what the pattern was.\n\n";
}
bool play_one_game() {
srand(time(0)); //needed to start randint
vector<int> solution; //vector of 4 randomly generated
//solutions
vector<int> guess; //vector containing user guesses.
vector<int> result;
int guess_input;
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
int trial_number = 0; //int that shows what guess the user is on
while (play_one_game() == true) {
//ask user for inputs.
cout << "Guess #" << ++trial_number << "? ";
for (int i = 0; i < guess.size(); ++i){
cin >> guess_input;
guess.push_back(guess_input);
}
//outputs error if user inputs a letter.
if (!cin) {
cerr << "Bad input data! Feed me numbers!\n";
return 43;
}
if (cin < 0){
cout << "Too bad! Solution was " << endl;
for(int i = 0; i < result.size(); i++)
cout << (result[i]);
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
for (int i = 0; i < result.size(); i++) {
if (guess[i]==solution[i])
cout << 1 << " ";
else if (guess[i]!=solution[i])
cout << 0 << " ";
}
cout << endl;
// playagain();
cout << endl << "Play again (0/1)? ";
int replay;
cin >> replay;
if (replay == 0) {
play_one_game() == false;
return 5;
}
else if (replay == 1)
play_one_game() == true;
else {
cerr << "wat?\n";
return 10;
}
}
}
This is designed to allow a player to guess a pattern of random numbers.
No idea why I am getting a segmentation fault. The program is supposed to call the offer_help function, then the play_one_game function within main function. Then it should ask the player whether he wants to play again. If no, then bool play_one_game should be set to false and it should exit.
This is related to the play_one_game bool function.
You're getting a segmentation fault, because you end up in an endless recursion in the following line:
while (play_one_game() == true) {
play_one_game will call play_one_game in this line, and this will call play_one_game in the same line again. This will result in a stack overflow at last.
Better use some bool keepPlaying; and while(keepPlaying) instead.
EDIT: Well, this is a little bit more than a simple answer, but I like games, so... have a look at the following code:
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
bool play_one_game();
void offer_help() {
int help_response;
std::cout << "Need help? (0/1) ";
std::cin >> help_response;
if (help_response == 1)
std::cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n"
"Each guess that you enter will be a line containing 4 integers,\n"
"separated by spaces, such as:\n"
"\t 2 4 7 1\n"
"For each guess, I will echo back a lost consisting of\n"
"0's and 1's, with a 1 in a given position meaning that\n"
"you guessed the number, and a zero meaning that you didn't.\n"
"For example, if the actual solution was 2 3 6 1, I'll respond\n"
"\t 1 0 0 1\n"
"See how many guesses it takes you to get the solution!\n\n"
"If you want to give up, type a negative number for one of\n"
"your guesses, and we'll tell you what the pattern was.\n\n";
}
int main() {
offer_help();
srand(time(0)); // Initialize random numbers with current time as seed
while(play_one_game()); // if play_one_game returns true, play again
}
bool play_one_game() {
std::vector<int> solution(4); // Four solutions for our guessing game
std::vector<int> guess; // User guesses
for(unsigned i = 0; i < solution.size(); ++i)
solution[i] = rand() % 10;
int trial_number = 0; //int that shows what guess the user is on
bool keepPlaying = true;
while(keepPlaying){
std::cout << "Guess #" << ++trial_number << "? ";
guess.clear(); // Clear old guesses
for(unsigned i = 0; i < solution.size(); ++i){
int guess_input;
//outputs error if user inputs a letter.
if (!(std::cin >> guess_input)) {
std::cerr << "Bad input data! Feed me numbers!\n";
std::cerr << "Try again!" << std::endl;
std::cin.clear(); // Clear flags
continue;
}
if (guess_input < 0){
std::cout << "Too bad! Solution was " << std::endl;
for(unsigned i = 0; i < solution.size(); i++)
std::cout << (solution[i]);
keepPlaying = false;
break;
}else
guess.push_back(guess_input);
}
if(!keepPlaying)
break;
if(solution.size() != guess.size()){
std::cerr << "Wrong number of guesses, try again!" << std::endl;
continue;
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
bool correct = true;
for (unsigned i = 0; i < solution.size(); i++) {
if (guess[i] == solution[i])
std::cout << 1 << " ";
else{
correct = false;
std::cout << 0 << " ";
}
}
if(correct){
std::cout << "Congratulations - you won!" << std::endl;
break;
}
std::cout << std::endl;
}
int replay = -1;
do{
// Ask user for input until input is 0 or 1
std::cout << std::endl << "Play again (0/1)? ";
std::cin >> replay;
}
while(replay != 0 && replay != 1);
return static_cast<bool>(replay); // return user replay answer (false/true)
}
Try to keep your code as simple as possible. Welcome to SO. And don't expect future answers to be that excessive.
You're never inserting anything into your solution vector. You just declare the vector, and then say:
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
...which won't do anything since at this point solution.size() == 0. Later, when you iterate over your result vector, you end up accessing invalid elements in your empty solution vector. You also can't assume that the result vector and solution vector are the same size.