using strings in C++ // how do i? - c++

I need help changing my current program so that it displays the letters already entered by the user, and displays the letters again immediately before prompting the user to enter another letter. what I have so far is below.
int main()
{
char another = 'Y';
string message = "";
while (toupper(another) == 'Y')
{
cout << "Enter a message: ";
getline(cin, message);
for (int x = 0; x < message.length(); x += 1)
cout << message.substr(x) << endl;
cout << endl << "Another message (Y/N)? ";
cin >> another;
cin.ignore(100, '\n');
}
system("pause");
return 0;
}

If you want all the characters (you entered at any time) printed, you can do the following:
Start off with two empty strings. One is a buffer, that stores the string that's currently added and the other holds all of the strings already added, like so:
string buf = "";
string messages = "";
Read your characters into your buffer, via:
getline(cin, buf);
Append the string to the other messages, already entered:
messages.append(buf);
Append a string delimiter to your messages, so you know which sequence of characters (including whitespaces) belong to the message you entered:
messages.append(";");
(BTW: Using "-quotes here is really important, to let the compiler know you are comparing strings, not characters, as there is no string::append(char s)-method defined, only string::append(string s).)
Iterate through your messages-string, and check if the character at position x is equal to ';' (Using '-quotes here is also important, because string::operator[] return a character not a string!!!). For instance you might code:
for (int x = 0; x < messages.length(); x++) {
//Test if string delimiter is reached, if so, jump to next line.
if(messages[x] == ';') {
std::cout << "\n";
}
//Else just print the string:
else {
std::cout << messages[x];
}
}
Test if another message should be entered.
OR you create a linked list of strings. Adding new strings to the list, every time you enter a new string. This might be the more elegant way to do this, however it is slightly more involved. (I'm assuming you're fairly new to programming, if not I apologize!). Check Wikipedia or cplusplus.com for more info on linked lists!
Hope I could answer your question,
lindebear

Related

Accept only Alphabet/Letters for input of a variable, reprompt if not letters

I've been stuck on this for two days. I've searched through page 20 on google and can't figure this out.
I need to accept only alphabetical letters for the input on townName.
I've tried every way of looping (that I can think of or find). Also, I've read that isalpha() only works on characters. However, I've searched for and implemented ways to convert a string from input to characters, I'm just not getting anywhere.
This is my last attempt:
// Input, validate, and set string name of town
cout << "Enter name of town: ";
getline(cin, townName);
cin >> townName; cin.ignore();
while (townName != isalpha()) {
cout << "Enter the town name - alphabet only.";
cin >> townName; }
I'm aware now that is not the proper use of isalpha. I've also tried isalpha(townName), using bools but I need to return a prompt to re-enter if it contains anything other than alpha/white space, and if it's only alpha to continue with main.
You were somewhat on the right track. You need to check each character of your string with isalpha. You might even want to allow for spaces i.e. "New York" etc.? I recommend writing your own method to do this in a loop over your whole input string. Put the whole thing in a while loop and you should be all set to do what you want.
#include <iostream>
#include <string>
#include <cctype>
// check for only alphabetical letters in string (or spaces)
bool lettersOrSpaces(const std::string& str)
{
for (size_t i = 0; i < str.size(); i++)
{
// make sure each character is A-Z or a space
if (! std::isalpha(str[i]) && ! std::isspace(str[i]))
{
return false; ///< at least one "no match"
}
}
return true; ///< all characters meet criteria
}
int main()
{
std::string townName;
std::cout << "Enter name of town: ";
while (std::getline(std::cin, townName) && !lettersOrSpaces(townName))
{
std::cout << "Enter the town name - alphabet only: ";
}
std::cout << "The name of town is: " << townName << std::endl;
return 0;
}

Having problems with C++ related issues

I wrote a C++ program that does a Vigenere cipher, but I have bumped into couple c++ issues. One is that the program encrypts, but it doesn't decrypt its encryption.Another issue is how the last for loop is, it doesn't seem to work correctly.The third issue is that c++ is not adding space on where I type space. and also it only prints out one letter. I don't really get c++ because I'm new to it.
#include <iostream>
using namespace std;
int main()
{
string Message; //What The User Inputs
string Key; // What Key To Go By
string Encryption; // The Secret
cout << "\n\nEnter Your Message: ";
getline(cin, Message);
cout << "\nEnter The Main Key: ";
getline(cin, Key);
cout << "\n\n"<<endl;
for (int i=0; i<=Message.size(); i++) //letter i is less than the length of the message
{
int k=0;
Encryption[i] = (( (Message[i]-97) + (Key[k]-97)) %26) + 97; //The Algorithm
k++;
if ( k==Key.size() )
{
k=0;
}
}
for (int i=0; i<=Message.size(); i++)
{
string Result;
Result = Encryption[i];
if ( i == Message.size() )
{
cout <<"Encryption: "<< Result <<endl;
cout << "\n\n"<<endl;
}
}
return 0;
}
/*
INPUT:
Enter Your Message: Hello There
Enter The Main Key: Secret
OUTPUT:
Encryption: Z
*/
Point 1: Program does not decrypt the encrypted message
Of course it doesn't. The program does not contain any code that would decrypt the encrypted message. I can't help on point 1.
Point 2: The last for loop does not work.
You do not need a loop to print out the encrypted message.
cout << "Encryption: " << Encryption<< endl;
cout << "\n\n" << endl;
Point 3: "c++ is not adding space on where I type space"
I do not understand what you mean here. Please explain.
Point 4: Only one character is printed out
As per Point 2, this loop is not needed, but to explain what went wrong:
for (int i=0; i<=Message.size(); i++)
{
string Result;
Create an empty temporary string named Result. A new Result will be created every time the loop goes around and the previous one will be destroyed.
Result = Encryption[i];
Set Result to the ith character in string Encryption. Result now contains exactly one character.
if ( i == Message.size() )
{
If i has reached the length of the message
cout <<"Encryption: "<< Result <<endl;
print out the one character in Result.
cout << "\n\n"<<endl;
}
}
In addition:
No space was allocated inside string Encryption;. By default a string is created empty. It has no string length, so attempting to index the string, as in Encryption[i], is meaningless. There is no Encryption[i] to be accessed, and attempting to do so has no defined result. It may crash your program. It may look like it is running, and crash your program later. It may do anything including look like it is working.
To fix this, one needs to allocate space with string::resize. After the message to be encoded has been read in,
cout << "\n\nEnter Your Message: ";
getline(cin, Message);
add
Encryption.resize(Message.size());
to allocate the storage you need.

String to ascii function

I actually wrote a function to convert string into ascii values.
However I managed to confuse my self and don't understand why my own code works.
here it is:
void convertToString()
{
char redo;
int letter;
int length;
do {
cout<< "How long is your word \n";
cin >> length;
cout << "Type in the letter values \n";
for (int x = 0; x < length; x++) {
cin >> letter;
cout << char (letter);
}
cout << "\n To enter another word hit R" << endl;
cin >> redo;
} while (redo == 'R');
}
In the terminal I can type in all the ASCII values I want with out changing line, however I though this would cause a problem, anyways my question is, is hitting the enter button the same as hitting space? if not i dont understand how my code is able to print out the chars since i write it all in one line...Does it assign the interger "letter" a new value everytime there is a space?
Please help/explain
This is to expand a bit on what Igor said in his comment and to give a little example.
As Igor said, istream::operator>>(&int) will read non-whitespace. This means for each call on the operator, it scans along the input stream (what you typed in) for non-whitespace and reads until the next whitespace again. The next call will pick up where you left off. So, entering a space or a newline is exactly the same for this situation where you're taking in an int.
You can verify this with a simple bit of code that scans until EOF:
#include <iostream>
int main()
{
int number;
while (std::cin >> number)
{
std::cout << number << std::endl;
}
return 0;
}
This will wait for user entry to be complete (pressing enter), but print a new line for each integer in your input as separated by whitespace. So "1 2 3 4" will print each of those numbers on separate lines, regardless of if you separate them with spaces, tabs, or newlines.

How do I keep track of letters guessed in a Hangman game in C++?

I have been trying to fix this program for the past two days and it is proving to be quite troublesome. It is an assignment for my intro to C++ course and has given me nothing but trouble. I have searched this board, posted on Cplusplus.com and spent hours on Google, looking for some assistance.
Here is my problem. I have been given a program and need to add a few features to it:
I have to save the users entries.
I have to display an error message if the user enters the same entry twice.
Seems simple? Not for a beginner such as myself. Here is the code, with what I have attempted to add to it in order to meet the problem's requirements.
int main()
{
//declare variables
string origWord = "";
string letter = "";
char dashReplaced = 'N';
char gameOver = 'N';
int numIncorrect = 0;
string displayWord = "-----";
string letterGuess[26];
//get original word
do //begin loop
{
cout << "Enter a 5-letter word in uppercase: ";
getline(cin, origWord);
} while (origWord.length() != 5);
//clear the screen
system("cls");
//start guessing
cout << "Guess this word: " <<
displayWord << endl;
while (gameOver == 'N')
{
cout << "Enter an uppercase letter: ";
cin >> letter;
//Entry Storage and Error Message. This is my problem.
for (int x = 0; x < 26; x++)
{
letterGuess[x] = letter;
for (int i = x; i < 26; i++)
{
if (i != x)
{
if (letterGuess[x] == letterGuess[i])
{
cout << "Letter already entered. Choose another letter."
<< endl;
}
}
}
}
//search for the letter in the original word
for (int x = 0; x < 5; x += 1)
{
//if the current character matches
//the letter, replace the corresponding
//dash in the displayWord variable and then
//set the dashReplaced variable to 'Y'
if (origWord.substr(x, 1) == letter)
{
displayWord.replace(x, 1, letter);
dashReplaced = 'Y';
} //end if
} //end for
//if a dash was replaced, check whether the
//displayWord variable contains any dashes
if (dashReplaced == 'Y')
{
//if the displayWord variable does not
//contain any dashes, the game is over
if (displayWord.find("-", 0) == -1)
{
gameOver = 'Y';
cout << endl << "Yes, the word is "
<< origWord << endl;
cout << "Great guessing!" << endl;
}
else //otherwise, continue guessing
{
cout << endl << "Guess this word: "
<< displayWord << endl;
dashReplaced = 'N';
} //end if
}
else //processed when dashReplaced contains 'N'
{
//add 1 to the number of incorrect guesses
numIncorrect += 1;
//if the number of incorrect guesses is 10,
//the game is over
if (numIncorrect == 10)
{
gameOver = 'Y';
cout << endl << "Sorry, the word is "
<< origWord << endl;
} //end if
} //end if
} //end while
system("pause");
return 0;
} //end of main function
My only edit to the program is directly under the header of Entry Storage and Error Message. I have tried a single for loop, but that simply displayed the error message for every letter entered. Not only that but it displayed it 26 times. Adding a Break command fixed that and it only displayed once. However, it still displayed on every entry.
A member of Cplusplus, pointed out that I was incorrectly testing the same variable against the array in the same location. That is why it displayed the error on every entry. Now with this loop, the error only displays when an entry is entered twice. However, the error message displays all 26 times once more. On top of that, it will only error if the letters are entered one after another.
For example, if I enter A then X then A again, no error is shown. If I enter, A then A again, the error is displayed 26 times. Something is clearly wrong with how the letter variable is being entered into the array on top of the whatever is causing the error message to display multiple times.
Any amount of assistance would be greatly appreciated.
Edit: My professor has gotten back to me and suggested using the following instead of what I have been tinkering with:
for (int x=0; x<5; x++)
if (origWord[x] == letterEntered)
origWord[x] = '-';
Is it just me, or does this miss the mark completely? I haven't tried converting it into my program as a simple copy and paste job produces compile errors. However, I don't see how that does anything with what I'm trying to do.
This set's all entries of your letterGuess array to the most recently guessed letter.
letterGuess[x] = letter;
This isn't what you want.
You need to think about the actual algorithm you need to implement:
The user enters a guess
Check to see if they've already guessed that letter
If they have, display an error message, return to 1.
If they have not, save that guess, continue with the game logic.
If you have already learned about standard containers, this can be trivially done with a std::set, or a std::vector that has been sorted.
You need to compare each element in the array to the guessed word. Best use a for loop for this. No more needs to be said if this is an assignment.
Also don't use system("cls") in your program, it is a massive security flaw and may lose you marks.

How to make an integer validation function that does not accept floating point values?

getRegionTotal() is the function I'm using for validation right now. It works pretty well in that if the user enters something like "twenty" or -7, it will not accept that and it will keep asking for new values until it gets one that is valid. However if the user enters 60.7 for the number of accidents in the north region, it will accept 60 and drop the .7 part. Then it will give both the regular instructions and the more specific instructions when it asks for the number of accidents in the south region.
//These will hold the number of accidents in each region last year
int northTotal = 0;
int southTotal = 0;
int eastTotal = 0;
int westTotal = 0;
int centralTotal = 0;
//passing 0 for northTotal, southTotal etc. because main doesn't know
//values of them until the function returns a value. When it returns a value
//it will go into the variables on the left. getRegionTotal will get the number
//of accidents for a region from the user and prompt the user using the string that
//is in the first argument.
northTotal = getRegionTotal("North", northTotal);
southTotal = getRegionTotal("South", southTotal);
eastTotal = getRegionTotal("East", eastTotal);
westTotal = getRegionTotal("West", westTotal);
centralTotal = getRegionTotal("Central", centralTotal);
int getRegionTotal(string regionName, int regionTotal)
{
//instructs user to enter number of accidents reported in a particular region
cout << "\nNumber of automobile accidents reported in " << regionName << " " << cityName << ": ";
//while regionTotal is not an integer or regionTotal is negative
while (!(cin >> regionTotal) || (regionTotal < 0) )
{
//give user more specific instructions
cout << "\nPlease enter a positive whole number for the number of\n";
cout << "automobile accidents in " << regionName << " " << cityName << ": ";
cin.clear(); //clear out cin object
cin.ignore(100, '\n'); //ignore whatever is in the cin object
//up to 100 characters or until
// a new line character
}
//returns a valid value for the number of accidents for the region
return regionTotal;
}
Parse the whole line and make sure you've consumed the whole line.
With iostreams:
#include <iostream>
#include <sstream>
#include <string>
for (std::string line; std::getline(std::cin, line); )
{
std::istringstream iss(line);
int result;
if (!(iss >> result >> std::ws && iss.get() == EOF))
{
// error, die. For example:
std::cout << "Unparsable input: '" << line << "'\n";
continue;
}
// else use "result"
}
With stdlib:
#include <errno>
#include <cstdlib>
char const * input = line.c_str(); // from above, say
char * e;
errno = 0;
long int result = std::strtol(input, &e, 10);
if (e == input || *e != '\0' || errno != 0)
{
// error
}
The two approaches are fundamentally identical, but the former may be more "idiomatic C++". That said, if you already have an existing string, the strtol-approach is a neat alternative, since it gives you precise error handling: did you consume the whole string (if not, e points to the next character); did you consume any of the string (if not, e points to the beginning); was there an overflow or underflow (check errno). On the other hand, the iostreams approach lets you consume trailing whitespace (thanks to >> std::ws), which the strtol-solution doesn't.
There's also std::stol which wraps strtol (and similarly for strtoull/strtod etc.), but it throws an exception on error, and I believe that exceptions are not the right tool for structuring control flow of normal behaviour like reading user input. Also, you cannot control how those wrappers operates; for example, the succeed even if they don't consume the entire string (but don't tell you how far they got), and you cannot specify the number base.