I am working on a palindrome program for class. I've written the program and it works. The issue I'm having is the output. I can't figure out how to change the characters into the number they are associated with. Here is my code:
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int main ()
{
string word;
int i;
int length;
int counter = 0;
cout << "Please enter a word." << endl;
getline (cin,word);
cout << "The length of the word is " << word.length() << "." << endl;
length = word.length();
for (i=0;i < length ; i++)
{
cout << "Checking element " << word[i] << " with element " word[length-i-1] << "." << endl;
if (word[i] != word[length-i-1])
{
counter = 1;
break;
}
}
if (counter)
{
cout << "NO: it is not a palindrome." << endl;
}
else
{
cout << "YES: it is a palindrome." << endl;
}
return 0;
}
The output I'm getting displays all the characters of the string and looks like this:
my output
Please enter a word
hannah
Checking element h with element h
Checking element a with element a
Checking element n with element n
(etc)
Yes: it is a palindrome.
But, I need the output to display the characters as their placement number in the string, which looks like this:
what output should be
Please enter a word
hannah
Checking element 0 with element 5
Checking element 1 with element 4
Checking element 2 with element 3
Yes: it is a palindrome.
Any hints or tips would be great. I just feel like I've tried everything I know, and it still won't look right. Thank you!
Instead of using :
cout << "Checking element " << word[i] << " with element " word[length-i-1] << "." << endl;
why not use:
cout << "Checking element " << i << " with element " << (length-i-1) << "." << endl;
This line:
cout << "Checking element " << word[i] << " with element " word[length-i-1] << "." << endl;
should be written as
cout << "Checking element " << i << " with element " << length-i-1 << "." << endl;
will give you what you want.
Related
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 days ago.
I am trying to write a program that will count the number of words, and number of sentences, and then take the average of those sentences. It takes the input from a user and will stop taking the input upon seeing "###". My code is as follows:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <string>
using namespace std;
int main() ///Main
{
//1. Declaration of variables
string text;
double word_count = 0.0;
double sentence_count = 0.0;
double avg_words_per_sentence;
//2. Prompt user input
cout << "Enter a paragraph..." << endl;
getline(cin, text, '#'); //3. Use getline to read whole paragraph and not first word entered
//4. Loop to read through text inputted and determine number of words and sentences
for (int i = 0; i < text.length(); i++)
{
if (text[i] == ' ')
{
word_count++;
}
else if (text[i] == '.' || text[i] == '!' || text[i] == '?')
{
sentence_count++;
}
}
//5. Provides error if there is no text
if (word_count == 0 && sentence_count == 0)
{
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any text!" << endl;
}
//6. Provides an error if there are no sentences
else if (sentence_count == 0)
{
cout << "Word count: " << word_count + 1 << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any sentences!" << endl;
}
//7. Calculates and outputs word/sentence count and average # of words
else
{
word_count++;
avg_words_per_sentence = word_count / sentence_count;
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "Average words per sentence: " << fixed << setprecision(1) << avg_words_per_sentence << endl;
}
return 0;
}
For example: If I were to use the input:
ttt
###
I would expect my word count to be 1, but I am instead told that it is 2. I am unsure as to why it is counting 2.
I tried tweaking certain if/then statements such as if the string contain "#" to not count the word or only count words if there is a space after a proper character but I am still met with the same incorrect number of words
For starters, you have no need to store word and sentence counts as doubles, and this will cause you problems later in your comparisons for conditions:
if (word_count == 0 && sentence_count == 0) should never be done for non integer types.
Your other 'issue' is your own doing, you have 3 cases at the end:
if (word_count == 0 && sentence_count == 0)
{
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any text!" << endl;
}
All is as expected (assuming word_count and sentence_count are not floating point)
else if (sentence_count == 0)
{
cout << "Word count: " << word_count + 1 << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any sentences!" << endl;
}
When sentence count is 0 but word count is not, you add 1 to the number of words counted. This is what is causing the 'issue' you have described. You do something similar with:
else
{
word_count++;
avg_words_per_sentence = word_count / sentence_count;
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "Average words per sentence: " << fixed << setprecision(1) << avg_words_per_sentence << endl;
}
By adding 1 to word count when you get a nonzero word/sentence count.
I see your intention there, but I think to get your desired behavior, you would just want to account for a word without punctuation as I have added, get rid of the random +1 to word counts, and use integers for comparison as such:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <string>
using namespace std;
int main() ///Main
{
//1. Declaration of variables
string text;
int word_count = 0;
int sentence_count = 0;
double avg_words_per_sentence;
//2. Prompt user input
cout << "Enter a paragraph..." << endl;
getline(cin, text, '#'); //3. Use getline to read whole paragraph and not first word entered
//4. Loop to read through text inputted and determine number of words and sentences
for (int i = 0; i < text.length(); i++)
{
if (text[i] == ' '|| text[i] == '\n')
{
word_count++;
}
else if (text[i] == '.' || text[i] == '!' || text[i] == '?')
{
sentence_count++;
}
}
//5. Provides error if there is no text
if (word_count == 0 && sentence_count == 0)
{
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any text!" << endl;
}
//6. Provides an error if there are no sentences
else if (sentence_count == 0)
{
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "You did not enter any sentences!" << endl;
}
//7. Calculates and outputs word/sentence count and average # of words
else
{
avg_words_per_sentence = word_count / sentence_count;
cout << "Word count: " << word_count << endl;
cout << "Sentence count: " << sentence_count << endl;
cout << "Average words per sentence: " << fixed << setprecision(1) << avg_words_per_sentence << endl;
}
return 0;
}
Note that this is still not a perfect approach, as multiple newlines will be counted as words. For anything more advanced, you may want to look into a state machine type approach (keep track of if you have encountered a character before newlines and only count words then, for example). Some sample output from this version is below:
Enter a paragraph...
ttt
###
Word count: 1
Sentence count: 0
You did not enter any sentences!
Enter a paragraph...
ttt hehehe.
###
Word count: 2
Sentence count: 1
Average words per sentence: 2.0
Enter a paragraph...
ttt heheh
###
Word count: 2
Sentence count: 0
You did not enter any sentences!
Enter a paragraph...
###
Word count: 2
Sentence count: 0
You did not enter any sentences!
I'm working on a self-imposed practice exercise. The parameters are that I allow the user to enter a name that is stored in a vector. Printing the list of names in the vector gives you the position of each name. You can choose to encrypt a name in the list by providing the name's position. Encryption compares each letter in the name with another string that is the allowed alphabet for names. When it finds the letter in the alphabet, it pulls a corresponding character from another string of random characters and assigns the new character to the same position.
Using a range based for loop I almost got it to work. By adding output statements I can see the code correctly comparing the characters of a name to the allowed alphabet and finding the corresponding value in the encryption key. However when the loop is complete and I print the list of names again, the characters in the name to be encrypted are unchanged.
Trying to troubleshoot the issue, I have commented out the range based for loop and tried to do the same thing with a traditional for loop. With this code I get and error during encryption:
Position 1 A is the same as #
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 26) >= this->size() (which is 2)
The "Position 1 A is the same as #" line is a debug output that I added to show that the code is able to find the correct string, a letter in the string, and the corresponding letter in they key.
Any help in understanding why I get those errors would be appreciated.
Here's my code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
// Declare strings for Encryption and Decryption
string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "};
string key {"mnbvfghytcqwi1234567890`~!##$%^&*()-=_+[]\{}|;':,./<>?"};
//Declare collection of names for the list
vector <string> names {};
//Declare character to hold the user menu selection
char selection {};
string user_input{};
string banner (50, '=');
//Print menu
do
{
cout << "\n" << banner << endl;
cout << "A - Add name to list" << endl;
cout << "P - Print all names in list" << endl;
cout << "E - Encrypt a name in the list" << endl;
cout << "D - Decrypt a name in the list" << endl;
cout << "S - Show details of a name in the list" << endl;
cout << "C - Clear all names in the list" << endl;
cout << "Q - Quit" << endl;
cout << banner << endl;
cout << "Selection: ";
getline(cin, user_input);
if (user_input.size() != 1)
{
cout << "Error 4: Menu selection must be a single character" << endl;
selection = '1';
}
else
{
for (auto c: user_input)
{
if (!isalpha(c))
{
cout << "Error 5: Menu selection must be an alphabetic character" << endl;
selection = '1';
}
else
selection = c;
}
}
// cin >> selection;
// cin.clear();
// cin.sync();
switch (selection)
{
case 'a':
case 'A':
{
string temp_name{};
bool invalid_name {false};
cout << "Enter full name: ";
getline(cin, temp_name);
if (!isalpha(temp_name[0]))
cout << "Error 2: Names must begin with an alphabetic character" << endl << endl;
else
{
for (auto c: temp_name)
{
if (!isalpha(c) && !isspace(c) && c != '-')
{
invalid_name = true;
break;
}
else
invalid_name = false;
}
if (invalid_name)
cout << "Error 3: Name contains invalid characters" << endl << endl;
else
{
temp_name.at(0) = toupper (temp_name.at(0));
for (size_t i {1}; i < temp_name.size(); i++)
{
size_t position{i-1};
if (isspace(temp_name.at(position)) || temp_name.at(position) == '-')
{
temp_name.at(i) = toupper(temp_name.at(i));
}
}
names.push_back(temp_name);
cout << "Added name #" << names.size() << endl;
}
}
break;
}
case 'p':
case 'P':
{
for (size_t i {0}; i < names.size(); i++)
cout << i+1 << ". " << names.at(i) << endl;
break;
}
case 'e':
case 'E':
{
size_t encrypt_input{}, key_position{}, name_position {}, name_size {};
cout << "Enter the position of the name to encrypt: ";
cin >> encrypt_input;
cin.clear();
cin.sync();
if (encrypt_input < 1 || encrypt_input > names.size())
cout << "Error 6: Invalid selection for name to encrypt" << endl << endl;
else
{
name_position = encrypt_input - 1;
name_size = names.at(name_position).size();
cout << "Encrypting name: " << names.at(name_position) << " of size " << name_size << endl << endl;
cout << "Position 1 " << names.at(name_position).at(0) << " is the same as ";
key_position = alphabet.find(names.at(name_position).at(0));
cout << key.at(key_position) << endl;
for (size_t i {0}; i < name_size; i++)
{
key_position = alphabet.find(names.at(name_position).at(i));
cout << "Finding " << names.at(key_position).at(i) << " in key at position " << key_position << endl;
cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
cout << "Changing " << names.at(key_position).at(i) << " to " << key.at(key_position) << endl;
names.at(name_position).at(i) = key.at(key_position);
}
/*
for (auto c: names.at(encrypt_input-1))
{
cout << "Converting " << c << " to ";
key_position = alphabet.find(c);
cout << key.at(key_position) << endl;
c = key.at(key_position);
cout << "C is now " << c << endl << endl;
}
*/
}
cout << names.at(encrypt_input-1) << endl;
break;
}
case 'q':
case 'Q':
cout << "Goodbye" << endl << endl;
break;
default:
cout << "Error 1: Invalid menu selection" << endl << endl;
break;
}
} while (selection != 'Q' && selection != 'q');
return 0;
}
Welcome to Stackoverflow! I agree entirely with PaulMcKenzie that such a big function is not the best for a variety of reasons - the immediate reasons are that its hard to read and hard to find problems - but there are more reasons as well.
Having said that you have a bug that I can see in the E case.
for (size_t i {0}; i < name_size; i++)
{
key_position = alphabet.find(names.at(name_position).at(i));
cout << "Finding " << names.at(key_position).at(i) << " in key at position " << key_position << endl;
cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
cout << "Changing " << names.at(key_position).at(i) << " to " << key.at(key_position) << endl;
names.at(name_position).at(i) = key.at(key_position);
}
Should be
for (unsigned int i{ 0 }; i < name_size; i++)
{
key_position = alphabet.find(names.at(name_position).at(i));
cout << "Finding " << names.at(name_position).at(i) << " in key at position " << key_position << endl;
cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
cout << "Changing " << names.at(name_position).at(i) << " to " << key.at(key_position) << endl;
names.at(name_position).at(i) = key.at(key_position);
}
ie key_position should be name_position in 2 places.
There may be other bugs, but this should stop the crashing and do the encoding right.
EDIT: On request of OP have added a new code fragment.
int i = 0; // position counter
for (auto c: names.at(encrypt_input-1))
{
cout << "Converting " << c << " to ";
key_position = alphabet.find(c);
cout << key.at(key_position) << endl;
c = key.at(key_position);
cout << "C is now " << c << endl << endl;
names.at(name_position).at(i++) = c; // update the names variable.
}
This should solve the problem you mentioned for the auto loop.
You're accessing an invalid location of names vector and the error / exception is showing that.
When you do this:
names.at( key_position ).at( i )
// ^^^
// It should be name_position
in this statement,
cout << "Finding " << names.at( key_position ).at( i ) << " in key at position " << key_position << endl;
you're accessing an invalid index of names whereas it should be:
names.at( name_position ).at( i )
and, that'll work because it access a valid index.
You're making the same mistake in this statement as well:
cout << "Changing " << names.at( key_position ).at( i ) << " to " << key.at( key_position ) << endl;
Correct these and it should work!
Tip:
It's time you read How to debug small programs.
It'll help you figure out what's wrong with your program in a more systematic way.
A few points regarding your code organization in general:
You should divide your program in functions instead of cluttering the main function.
You may write functions corresponding to each of your case in switch statement e.g. addName(), encryptName(), decryptName(), etc.
This modularity will definitely help you and other people to read, debug, maintain and extend your code easily and efficiently. In your case, it would also help you write an Minimal, Complete, and Verifiable example in no time.
Hope that helps!
Best of luck!
Happy coding!
I'm creating a program that takes in a string sentence or a paragraph.
I am not quite familiar with using std::
I'm not asking for someone to do it for me, I am just wanting to see if someone can show me an example of this.
When the 4th choice (“Split Words”) is selected, the words should be put into an array or a structure and each word should be displayed with a loop. After this, duplicate removal should be performed and the program must determine the duplicate words and eliminate them. After this, the word list should be printed again.
Any help with this would be greatly appreciated. Thank you
Code: (I need help with case 'D')
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
int main()
{
string s;
char selection;
string w;
cout << "Enter a paragraph or a sentence : " ;
getline(cin, s);
int sizeOfString = s.length();
//cout << "The paragraph has " << sizeOfString << " characters. " << endl; ***Dummy call to see if size works.
//cout << "You entered " << s << endl; *** Dummy function !!
cout << "" << endl;
cout << " Menu " << endl;
cout <<" ------------------------" << endl;
cout << "" << endl;
cout << "A -- Convert paragraph to all caps " << endl;
cout << "B -- Convert paragraph to all lowercase " << endl;
cout << "C -- Delete whitespaces " << endl;
cout << "D -- Split words & remove duplicates " << endl;
cout << "E -- Search a certain word " << endl;
cout << "" << endl;
cout << "Please select one of the above: " ;
cin >> selection;
cout << "" << endl;
switch (selection) //Switch statement
{
case 'a':
case 'A': cout << "You chose to convert the paragraph to all uppercase" << endl;
cout << "" << endl;
for(int i=0; s[i]!='\0'; i++)
{
s[i]=toupper(s[i]);
}
cout << "This is it: " << s << endl;
break;
case 'b':
case 'B': cout << "You chose to convert the paragragh to all lowercase" << endl;
cout << "" << endl;
for (int i=0; s[i] !='\0'; i++)
{
s[i]=tolower(s[i]);
}
cout << "This is it: " << s << endl;
break;
case 'c':
case 'C': cout << "You chose to delete the whitespaces in the paragraph" << endl;
cout << "" << endl;
for(int i=0; i<s.length(); i++)
if(s[i] == ' ') s.erase(i,1);
cout <<"This is it: " << s << endl;
break;
case 'd':
case 'D': cout << "You chose to split the words & remove the duplicates in the paragraph" << endl;
cout << "" << endl;
case 'e':
case 'E': cout << "You chose to search for a certain word in the paragraph. " << endl;
cout << "" << endl;
cout << "Enter the word you want to search for: ";
cin >> w;
s.find(w);
if ( s.find( w ) != std::string::npos )
{
cout << w << " was found in the paragraph. " << endl;
}
else
{
cout << w << " was not found in the paragraph. " << endl;
}
}
return 0;
}
Write code that parses words out of the string s (Here's one method: Split a string in C++?). Print the words as you parse them and then put them in some sort of set container. A set container does not allow duplicates. Once done parsing words, iterate over the set and print the words out (there won't be duplicates).
If you need to print out the de-duped words in the order they appeared in the string, then you could keep a vector alongside the set. Like before, as you parse the words add them to the set but inspect the returned pair from the set's insert() method (it can tell you whether the inserted item was new to the set or if the insert operation was denied because the set already contained a value that was equal to the one you tried to insert: http://www.cplusplus.com/reference/set/set/insert/).
std:vector<std:string> wordVector; // Assume populated with raw parsed words
std:set<std:string> deDupedSet;
std:vector<std:string> deDupedVector;
for (int i = 0; i < wordVector.size(); i++)
{
if (deDupedSet.insert(wordVector[i]).second())
{
deDupedVector.push_back(wordVector[i]);
{
}
// Print the deDupedVector afterwards
I am trying to search a structure for a value I entered. However I want the search to work even if I only enter a part of the word. How do I do this?
Here is my Code:
for (int i = 0; i < size; i++)
{
if (searchName == ptrCandy[i].name)
{
cout << "Name: " << ptrCandy[i].name << "\n" << "Quantity: " << ptrCandy[i].quantity;
cout << "\n" << fixed << setprecision(2) << "Cost: $" << ptrCandy[i].cost << "\n" << endl;
}
}
I am assuming that if you type in n characters, you want to only match candy elements that begin with those n characters, and not attempt to do any autocorrection or spell-checking or the like. If these are correct assumptions, then let the STL do the work for you:
int searchLength = searchName.length();
for( int i=0; i<size; i++ ) {
if ( ptrCandy[i].name.length() >= searchLength &&
searchName == ptrCandy[i].name.substr( 0, searchLength ) ) {
// Found it!
}
}
For example, if you have a candy named "snickers" and "snack mix", then if you enter "sn", it will return both of these, but if you enter "sni", you will only get "snickers".
first, you need a threshold for how close the match has to be. is 1 letter ok?
second, decide if it must match from the beginning, or beginning of a word eg does do work for "odor"?
Then if you don't want to use another library, loop through each char and continue until you reach the threshold or the end of the string
In other words, if the name is "Long dude one" and the search string is "dude", then start at name[0] and do a 4-iteration loop (four letters in dude) and check each one with the corresponding one from name. If any letter does not match, exit that loop. Then do the same thing starting from name[1] to name[4], then from name[2] to name[5] etc all the way until you are checking the last 4 letters of the search string " one" against dude. However, you wouldn't get that far because on the 6th attempt, eg looping through name[5] to name[8] all 4 letters would match so you would set match=true and exit.
put that in a function and call it for each name.
Assuming these types are of std::string:
for (int i = 0; i < size; i++)
{
size_t pos = ptrCandy[i].name.find(searchName);
if (pos != string::npos)
{
cout << "Name: " << ptrCandy[i].name << "\n" << "Quantity: " << ptrCandy[i].quantity;
cout << "\n" << fixed << setprecision(2) << "Cost: $" << ptrCandy[i].cost << "\n" << endl;
}
}
If you wanted to do it case-insensitive, just convert both strings to either all upper or all lower case and then do the search on the modified strings.
You can use member function compare the following way
for (int i = 0; i < size; i++)
{
if ( ptrCandy[i].name.compare( 0, searchName.size(), searchName ) == 0 )
{
cout << "Name: " << ptrCandy[i].name << "\n" << "Quantity: " << ptrCandy[i].quantity;
cout << "\n" << fixed << setprecision(2) << "Cost: $" << ptrCandy[i].cost << "\n" << endl;
}
}
Hello this is a segment of my code of which i am trying to implement the Morris-Pratt algorithm.
When i am comparing my variables if find that they dont match, this is because one of my variables "Temp" is geting extra characters added to the end of the array.
here is my code...
// Calculate the next talbe
char test[searchLen];
for(int i = 0; i < searchLen; i++)
{
test[i] = fileContent[currPos+i];
}
cout << "SEARCHLEN: " << searchLen << endl;
cout << "TEST: " << '\t' << '\t' << test << endl;
cout << "SEARCH: " << '\t' << search << endl;
cout << strcmp(test,search) << endl << endl;
// Determine if a match is detected
if(strcmp(test,search)==0)
{
cout << "----------------------> Match detected at: " << currPos << endl;
}
currPos ++;
}
return numberOfComparisons;
}
The output looks like this...
SEARCHLEN: 8
TEST: athsoutg5?h
SEARCH: brilling
-1
As you can see the 5?H is not supposed to be there and is breaking my code.
You need to add a null terminator.
char test[searchLen + 1];
test[searchLen] = '\0';
It does look like your string is not terminated with \0, maybe you forgot to copy it / put it in there?