Detect Repeated Words - c++

I'm a beginner in C++ and I've using Programming: Principles and Practice from Bjarne Stroustrup. I've gotten to the assignment chapter and came across this example
int main()
{
string previous = " "; // previous word; initialized to “not a word”
string current; // current word
while (cin>>current) { // read a stream of words
if (previous == current) // check if the word is the same as last
cout << "repeated word: " << current << '\n';
previous = current;
}
}
But I don't quite understand the logic behind it, mainly in the first through of the loop, where previous=" ", i dont know how previous get to equal anything at all from the input in current given that it values " ". If I compile and input " the cat cat eats" it identifies cat as the repeated word but how does it know since, like the comment says, its initialized to no word, why does it cout the repeated word: cat in that first case.

At the end of the loop iteration, you are assigning current value to previous (previous = current). At the start of new iteration, you are assigning user entered value to current value and comparing with previous.

Related

C++ variable appears to have different values in different functions

This is a simplified and more informative version of a question that has now been deleted.
BACKGROUND
I am currently trying to familiarize myself with basic C++ programming and decided to make a game of hangman. However, I noticed that an integer variable called preset_count—which is meant to count how many letters have been pre-guessed by the game— always returns a value of 0 in the main() function whereas in other functions, it has a value of 2 (or anything greater than 0).
What I am trying to accomplish here is that the program will automatically fill in the vowels of the word the player is trying to guess. Depending on how many vowels are filled in, the score the player gets when guessing a character right increases.
For example, the player is trying to guess the word "eraser," so the hangman program will print out
"e _ a _ e _ " they will gain 334 points if they guess correctly.
In a word like "circle," though (which will be printed as "_ i _ _ _ e ") the player will gain 250 points per guess because of the fact that the player has to guess 4 characters instead of 3.
THE ISSUE AND CODE
In order to accomplish this, I added code meant to count how many vowels have been filled in by the game in a special function.
The code below is a simplified version of the one in the actual hangman program that re-creates the issue I have with the program. See, the game outputs a different value of the preset_count value in each function.
Essentially, the main() function has a
cout << "preset_count in main(): " << preset_count;
//This line of code prints out 0. However, the variant of this in find_preset():
cout << "preset_count in find_preset(): " << preset_count;
//Which, on the other hand, prints out 3.
Is there any reason behind these contradictory variable reports? Is there any way to solve this?
#include <iostream>
using namespace std;
void find_preset (int, const string, string); //Prototyping for find_preset()
int main() {
int preset_count = 0; //Amount of times a character in PRESET_LETTERS appears in the word variable.
const string PRESET_LETTERS = "AEIOUaeiou"; //The letters the program is looking out for.
string word = "eraser"; //The word being analyzed.
cout << "\nmain(): main() executed, variables declared, about to execute find_preset() function.";
find_preset(preset_count, PRESET_LETTERS, word); //find_preset() function; finds how many PRESET_LETTERS characters are in word.
cout << "\nmain(): find_preset() finished executing.\n"; //Announces that find_preset() function finished executing.
cout << "\n\nDEBUG word: " << word << endl; //Report on the set word value.
cout << "DEBUG preset_count in main(): " << preset_count << endl << endl; //Report on preset_count's value in main().
//This is where my issue takes place in. This reports a value whereas in find_preset(), the value of preset_count is 2.
return 0;
}
//find_preset() function; finds how many PRESET_LETTERS characters are in word.
void find_preset(int preset_count, const string PRESET_LETTERS, string word) {
int word_index = 0; //How many characters of word that find_preset() has gone through.
cout << "\nfind_preset() executed, now counting amount of instances of PRESET_LETTERS in word.";
//While word_index is less than the size of word. While the entire word variables hasn't been scanned yet.
while (word_index < word.size()) {
//If a PRESET_LETTERS character is found in word.
if(word.find(PRESET_LETTERS)) {
preset_count++; //preset_count increased by 1.
cout << "\nfind_preset(): preset_index and preset_count increased by 1."; //Reports preset_count++; has been executed.
}
word_index++; //Word index increased by 1.
cout << "\nfind_preset(): word_index increased by 1."; //Reports that word_index++; has been executed.
}
cout << "\nfind_preset(): while (word_index < word.size()) finished executing, now printing debug menu for find_preset().\n";
//Reports that the while loop has finished executing.
cout << "\n\nDEBUG: preset_count in find_preset(): " << preset_count; //Report on preset_count's value in find_preset().
//This is also where my issue takes place in. This reports that preset_count's value is 2 whereas in main, it reports 0.
cout << "\nDEBUG: word_index value: " << word_index << endl << endl; //Report on word_index's value.
}
The arguments in C++ are copies of what are passed by default. Therefore, modifications of arguments in callee functions won't affect what are passed in caller. You should add & to make the arguments to references if you want to have functions modify what are passed.
Both declaration and definition should be modified.
void find_preset (int&, const string, string); //Prototyping for find_preset()
void find_preset (int& preset_count, const string PRESET_LETTERS, string word) //find_preset() function; finds how many PRESET_LETTERS characters are in word.
{

Assigning a string variable to the space character " " in order to find repeated words

int main()
{
std::string previous = " ";
std::string current;
while (std::cin >> current)
{
if (previous == current)
std::cout << "\n repeated word: " << current;
previous = current;
}
};
The program works, but I don't know why. What exactly is the computer doing here? From what I understand, the computer first reads user input then checks if the word matches with "previous" which is initialized to a space character. Is the computer checking if both string variables are space characters? At what point does previous take on a different value?
In every step of the loop, current is checked against previous, and then previous is assigned to the value of current (in the last statement of the loop). Then another word is read into current, and so on.

While loop in C++ (using break)

I'm currently working through the book C++ Primer (recommended on SO book list). An exercise was given that was essentially read through some strings, check if any strings were repeated twice in succession, if a string was repeated print which word and break out of the loop. If no word was repeated, print that. Here is my solution, I'm wondering a) if it's not a good solution and b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected. Here is my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<string> words = {"Cow", "Cat", "Dog", "Dog", "Bird"};
string tempWord;
unsigned int i = 0;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
break;
}
else
{
tempWord = words[i];
}
// add 1 to i to test equality as i starts at 0
if (i + 1 == words.size())
cout << "No word was repeated.";
++i;
}
return 0;
}
The definition of "good solution" will somewhat depend on the requirements - the most important will always be "does it work" - but then there may be speed and memory requirements on top.
Yours seems to work (unless you have the first string being blank, in which case it'll break); so it's certainly not that bad.
The only suggestion I could make is that you could have a go at writing a version that doesn't keep a copy of one of the strings, because what if they're really really big / lots of them and copying them will be an expensive process?
I would move the test condition outside of the loop, as it seems unnecessary to perform it at every step. For readability I would add a bool:
string tempWord;
unsigned int i = 0;
bool exited = false;
while (i != words.size())
{
if (words[i] == tempWord)
{
cout << "Loop exited as the word " << tempWord << " was repeated.";
exited = true;
break;
}
else
{
tempWord = words[i];
}
++i;
}
// Doing the check afterwards instead
if (!exited)
{
cout << "No word was repeated.";
}
a) if it's not a good solution
For the input specified it is a good solution (it works). However, tempWord is not initialized, so the first time the loop runs it will test against an empty string. Because the input does not contain an empty string, it works. But if your input started with an empty string it would falsely find as repeating.
b) is my test condition for no repeated words ok? Because I had to add 1 to the variable to get it to work as expected.
Yes, and it is simply because the indexing of the array starts from zero, and you are testing it against the count of items in the array. So for example an array with count of 1 will have only one element which will be indexed as zero. So you were right to add 1 to i.
As an answer for the training task your code (after some fixes suggested in other answers) look good. However, if this was a real world problem (and therefore it didn't contain strange restrictions like "use a for loop and break"), then its writer should also consider ways of improving readability.
Usage of default STL algorithm is almost always better than reinventing the wheel, so I would write this code as follows:
auto equal = std::find_adjacent(words.begin(), words.end());
if (equal == words.end())
{
cout << "No word was repeated" << endl;
}
else
{
cout << "Word " << *equal << " was repeated" << endl;
}

The end-of -input character doesn't work

before I was doing a very simple programming exercise and I have a problem with the end-of-input character. I wrote this program to check if two words repetead in the text :
string previous = ""; //initalized to "not a word"
string current; //current word
while (cin >> current) { //input operation
if (previous == current) // check if the word is the same as last
cout << "repetead words : " << current << '\n';
previous = current;
}
cout << previous << "\n" << current << "\n";
My book says that if I want to terminate the input operation and to fall out the while loop I must insert the end-of-input character, but, if I insert that character on the same line of my input words I will not fall out the loop.Just if I insert it on a newline it works.Why ? I must insert the end-of-input character on a newline to make it work ?
std::cin::operator>> will return false instead of another reference to std::cin when it reaches end-of-stream. Passing a single eof is a way to signal end-of-stream.
When std::cin parses only an eof, it interprets it specially instead of considering it more data in the stream. If it parses any data in combination with eof, it's just considered data in the stream.

Counting a String within a string

I'm told to ask the user for a string ( a sentence). Then the user is asked to input another string to search in string 1 (the sentence). The program has to count the number of times the second string shows up in the first string. I'm not getting any errors but it's is not counting the letters. This is the result i get:
Enter a sentence:i love to eat soup
Enter string to search: ou
There are 0 of the string ou in the first string you provided.
Can someone please tell me what i'm doing wrong? I'm a beginner at c++ so i'm having some trouble understanding.
#include <iostream>
#include <string>
using namespace std;
int main() {
string sentence;
string search;
int count = 0;
cout<<"Enter a sentence:";
getline (cin, sentence);
cout<<"Enter string to search:";
getline (cin, search);
cout << "There are " << count << " of the string " << search << " in the first string you provided." <<"\n";
for (int i=0; i < sentence.size(); ++i)
{
if (sentence == search)
count++;
}
return count;
}
Two issues:
You print count before you calculate it.
You are not actually searching for a substring. You should look at the documentation for std::string to find an appropriate way to search for substrings. However, you are on the right track.
Well, you're trying to output the results before calculating them.
Also, == is for exact matches, not substring searches.
You have your cout print line after the loop where you search for the string and set the count. Move it below that loop.
looks like you should put the cout statement in the end of this method. Because in your code, count is always 0 when you output it
You should modify your loop so that it really searches for substrings and count their occurrences:
string::size_type pos = sentence.find(search);
while (pos != string::npos)
{
pos = sentence.find(search, pos + search.size());
count++;
}
Also, you most likely want to move this line after the point where you actually compute the value of count:
cout << "There are " << count << ...
Otherwise, it will obviously output the value to which count was initialized originally (i.e. 0).