input stream with string - c++

If I type john when prompted for a char, the while statement will loop 4 times, one for each letter of john, before it asks again for user input.
Why does this program do not allow me insert more input before the whole 4 chars of john are consumed ? I would expect it to discard the 3 remaining letters of the string john and asked me for more input on the second loop.
The whole example can be found at page 44 of Bjarne Stroustrup The C++ Programming Language 4th edition.
#include <iostream>
using namespace std;
bool question() {
while (true) {
cout << "Continue ?\n";
char answer = 0;
cin >> answer;
cout << "answer: " << answer << endl;
}
return false;
}
int main () {
cout << question() << endl;
}
The output becomes:
Continue ?
john
answer: j
Continue ?
answer: o
Continue ?
answer: h
Continue ?
answer: n
Continue ?

You may be wondering why you're not being allowed to enter a character at each prompt. You have entered four characters into the input stream, so your loop runs four times to consume all of that input.
If you only want to use the first character in the input, you may want to get an entire line and work on just the first character.
#include <iostream>
#include <string>
bool question() {
while (true) {
std::cout << "Continue ?\n";
std::string line;
std::getline(std::cin, line);
std::cout << "answer: " << line[0] << endl;
}
return false;
}
Of course, you should also check that an empty line was not entered, which may be as simple as checking if line[0] is not '\0'.

Related

Printing words vertically

So I'm just starting in C++, so I'm not familiar with the language, though I do have knowledge of C. I'm trying to print words vertically. Here is the problem given.
Create an array of 25 strings.
Use a sentinel loop that reads from cin until the array is full or the end of input is reached
(when the user presses Ctrl-D), whichever comes first.
After the sentinel loop is over, use a for loop to move through the array.
Remember not to travel farther than the last array element that was input.
Print one array element (one string) followed by a newline
Use a for loop to move through the characters of the string you just printed
print one character followed by a newline
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int main()
{
char word;
int count = 0;
cout << "Enter a word: (press Ctrl-D to quit)";
cin >> word;
int array1[25];
while (!cin.eof())
{
count = count + 1;
cout << "Enter a word: (press Ctrl-D to quit)";
cin >> word;
} //end while
for (word = 0; word <= array1[count]; word++)
{
cout << 'end1' << 'end1' << "There were " << count << "Words Entered" << 'end1';
}
} //end main
Code is rough, it compiles, but when it is in an infinite loop with numbers comes out after the texts.
Just for the hell of it
#include <iostream>
#include <string>
#include <iomanip>
#include <vector>
using namespace std;
int main() {
string word;
int count = 0;
vector<string> arrayOfStrings;
cout << "Enter a word: (press Ctrl-D to quit)";
while(cin >> word){
if(count < 25){
arrayOfStrings.push_back(word);
count = count + 1;
cout << "Enter a word: (press Ctrl-D to quit)";
} else {
cout << "25 strings was entered";
break;
}
}//end while
for ( int j = 0; j < arrayOfStrings.size(); j++ ){
cout << '\n' << '\n' << $j << "-st string entered " << arrayOfStrings[j] << '\n';
}
}//end main
This code reads exactly 25 strings, remembers them, and even outputs them later.
This is just an educational example, which basically ignores memory managment
I strongly suggest not to use this in any actual code.
It took me about 5 mins to write this.
There are a few errors in this code - perhaps if you are familiar with C, then quickly write a version in C and translate it to a more modern "C++ like" version. Perhaps look into std::string and std::vector to make life even easier.
int array1[25]; needs to store strings, therefore it is of the wrong type.
The while (!cin.eof()) loop needs to also check that it doesn't go over the bounds of the above array (i.e. at most 25 words).
The for (word = 0; word <= array1[count]; word++) loop that needs to loop exactly n times, where n is the number of words inputted, i.e. in the above while loop.

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;
}

C++: How can I allow user to retry if they accidentally enter more than one character in char variable?

Question: In C++, ow do I make a program throw out an error when a user enters multiple characters for an input requesting a single character? I'd like to have the program re-prompt for a single character, but it just keeps going and entering the multiple characters on later lines.
This is a very simple program I wrote to test out character inputs and their properties to help me with another assignment. I wanted to see how it would react to multi-character inputs.
//Include statements
#include <iostream>
#include <string>
using namespace std;
//main statement
int main ()
{
//name variables
int numChar;
char letterEntry;
string finalWord = "";
//begin entry
cout << "This program will let you enter characters and combine them into a string." << endl;
cout << "First tell us how many characters you want to enter." << endl;
cin >> numChar;
//convert characters to string and add to string variable
int counter = 0;
while (counter<numChar)
{
cout << "Enter a character!" << endl;
cin >> letterEntry;
finalWord = finalWord + string(1, letterEntry);
counter++;
}
//Display final word
cout << "Your word is " << finalWord << endl;
return(0);
}
This is an output that demonstrates my issue.
This program will let you enter characters and combine them into a string.
First tell us how many characters you want to enter.
3
Enter a character!
DOGS
Enter a character!
Enter a character!
Your word is DOG
I want the program to not save anything if the user types in more than one character. I want it to print an error message that says "You entered more than one character, please retry," and lets them try again. Is there a way to do this with type char?
Thanks!

NOTE:(getline was not the issue) C++ getline() stops working in user defined function but works in main function

NOTE: SOLVED, problem was not getline() but find function with an
Improperly filled array!
I've looked up several questions before posting my own, but I could not find an answer for my problem. This is my first question posted, but I did do some research and tried other solutions from other questions before posting my own. So I am not entirely sure this isn't a duplicate. My apologies! Thank you for understanding in advance!
I am trying to use getline() (c++) to get user input. It works fine in my main, but does not in my user defined function. I thought it might have to do with the buffer, so i used cin.ignore() as suggested in:
C++ getline method not working
and i checked:
How does getline work with cin?
to make sure I properly understood getline(). However my program still does not work correctly.
My program takes English Text as a string from user input (console input) and converts it into Morse Code and outputs result as a string (console output).
basically my problem is this:
getline works in my main function for both strings and strings with spaces ex: "This" and "This Code".
However, in my user defined function, it ONLY works for strings without spaces ex: "This".
Thanks for the help! Code snippets below!
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[]);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
resultString = textToMorse(alphabet, morseAlphabet); // function where I use
// getline() but does not work
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
// does not work
string textToMorse(const string alphabet, const string morseAlphabet[])
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with strings without spaces,
//but breaks with others. ex: "This" works as input
//but "This code" breaks and the console seems to freeze
// then crashes out
cin.clear();
// rest of code, but program breaks before this.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
However if I edit my code and get the input from my main and pass it in as a parameter, it works.
#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;
using namespace std;
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput);
int main()
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
..",".---","-.-",".-..","--","-.","---",".--.",
"--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
"...--","....-",".....",
"-....","--...","---..","----.",".-.-.-","--..--","..--.."};
int userSelection;
string resultString;
cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
cout << "Please select an option by typing the integer shown: " << endl << endl;
cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
cin >> userSelection;
while(userSelection == 1 || userSelection == 2)
{
if(userSelection == 1)
{
string userInput;
cout << endl << "Enter English text to encode to Morse code,
with only a space between words: " << endl << endl;
cin.ignore();
getline(cin,userInput); //code works with both "This" and "This code"
cin.clear();
resultString = textToMorse(alphabet, morseAlphabet, userInput); //function modified
//to take one more
//parameter
cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
cout << resultString << endl << endl << endl << endl;
}
}
return 0;
}
string textToMorse(const string alphabet, const string morseAlphabet[], string userInput)
{
//code, but program works.
string encodedEnglishText = "";
for(int i = 0; i < userInput.length(); i++)
{
userInput[i] = toupper(userInput[i]);
}
for(int i = 0; i < userInput.length(); i++)
{
encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
encodedEnglishText += " "; // extra spacing added for output clarity
if(userInput[i] == ' ')
{
encodedEnglishText += " "; // extra spacing added for output clarity
}
}
return encodedEnglishText;
}
I didn't include all of the code, just the parts I felt were relevant to the question.
by works I mean:
getline successfully takes input. getline successfully assigns a string such as "this" and "this code" to the variable userInput when used in main function.
it only successfully assigns strings without spaces such as "this" when used in my user defined function. In that function, for some reason it does not work when I enter a string like "this code" or any string with a space inbetween.
note: program is not finished, as I plan to add other methods to do the reverse (as seen in code with
extra user options, but these are not yet implemented or defined, code still runs and compiles for problem I am facing.
The problem is that there is no morse code for a space.
Make a verification:
int n = alphabet.find(userInput[i]);
encodedEnglishText += (n == string::npos) ? " ": morseAlphabet[n];
Then it will work.
When you are looking for your input character in the alphabet string you won't find ' ' and std::string::find() return std::string::npos (normally -1 converted to the type std::string::size_type but the value isn't guaranteed). Using this value to index morseAlphabet won't do you much good: it is undefined behavior. This problem does not arise when you enter just one string as all characters are found in alphabet.
The proper way to deal with the situation is to look for the character and capture the result. Before using the result, you'd test the input, e.g.:
std::string::size_type pos(alphabet.find(userInput[i]));
if (pos == std::string::npos) {
// deal with the character not being part of the alphabet
}
else {
encodedEnglishText += morseAlphabet[pos];
}
Note that there are a few other things wrong with your program:
The selection of options should be inside the loop! The way it is implemented entering, e.g. 2 results in an infinite loop.
Using std::toupper() with a char can also result in undefined behavior! The problem is that std::toupper() expects a non-negative value of the value EOF but char may be signed. To avoid this problem you should use any of the functions from <cctype> or <ctype.h> with unsigned char:
userInput[i] = toupper[static_cast<unsigned char>(userInput[i]));
If the user doesn't enter an integer but, e.g., foo reading userSelection will fail and stream will get into failure state where it won't do anything until std::cin.clear() is entered. The best approach to deal with this situation is to test the result of reading the value before doing anything. If the input failed you can recover from the situation by clearing the status and skipping the offending character, e.g.:
if (std::cin >> userSelection) {
// use the selection
}
else {
std::cout << "ignoring invalid input\n";
std::cin.clear();
std::cin.ignore();
}
Note that your use of std::cin.clear() should be needed. Also, you should verify that the input you read with std::getline() is successful: in general, all user inputs should be tested for success.
If you enter a space character after the integer when reading userSelection, your call to std::cin.ignore() will ignore this space not the newline! To avoid this problem you could either read all charactors up to the first newline or skip all whitespace prior to the non-whitespace character:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // all till newline
std::cin >> std::ws; // skip all whitespace to first non-whitespace character
Do not use std::endl! It does not only create a newline but it also flushes the stream. This can easily create a performance problem.
You should probably pass std::string arguments by reference rather than by value. Passing the argument alphabet by value creates a copy with is inefficient (the morseAlphabet argument is passed by pointer although it looks like an array).
Some string literals seem to be split across multiple lines. Doing so is illegal (I guess, however, that this problem was introduced when pasting the code to the question above at some point).

C++ Issue with cin and CTRL + Z

I'm reading c++ primer 5th and I have a little problem with an exercise:
Read a sequence of words from cin and store the values a vector. After
you’ve read all the words, process the vector and change each word to
uppercase. Print the transformed elements, eight words to a line.
My code is this:
#include <iostream>
#include <vector>
#include <string>
#include <cctype>
using std::vector;
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main(){
vector<string> words;
string wordBuffer;
vector<string> output(1);
while (cin >> wordBuffer){
words.push_back(wordBuffer);
}
for (string &word : words){
for (char &letter : word){
letter = toupper(letter);
}
}
unsigned currentLine = 0;
for (decltype(words.size())index = 0; index < words.size(); ++index){
output[currentLine] += words[index] + " ";
if ((index+1) % 8 == 0){
++currentLine;
output.push_back("");
}
}
for (string s : output){
s[s.size() - 1] = 0; //removing the whitespace
cout << s << endl;
}
system("pause");
return 0;
}
Now, everything works well, but i have an issue with the input of the words by console.
If I write
I am writing a random words ^Z
and press Enter nothing happens. I have to rewrite the ^Z after I have pressed the Enter, like here:
I am writing a random words
^Z
Can you expain me why? Thanks!
PS: I'm saying that because in my previous programs writing ^Z in the same line worked fine. Like in this code:
#include <iostream>;
int main(){
int currval = 0,val = 0;
int count = 1;
while (std::cin >> val){
if (currval == val){
++count;
}
else {
std::cout << "The number " << currval << " appears " << count << " times" << std::endl;
currval = val;
count = 1;
}
}
std::cout << "The number " << currval << " appears " << count << " times" << std::endl;
system("pause");
return 0;
}
I can't figure out why :(
The ^Z has to be first in order for Windows to treat it as Ctrl+Z, otherwise it is just treated as meaningless characters.
If you would like it to work like you wrote i'd suggest:
String wordBuffer("")
while (strcmp(wordBuffer[strlen(wordBuffer)-3], "^Z") != 0){
words.push_back(wordBuffer);
cin >> wordBuffer
}
EDIT: in your second example it works because when you read integers c++ knows to divide the given string of numbers in the space (or ENTER if the numbers are entered separately in every line) to read every number separately so if you'll enter:
123 2323 4545 43 ^Z
It will read 123, then 2323, ... and then ^Z and so it will be as though it got it in a separate line but when you read string, it cant do that because a string contain every symbol and so it separate the input in the ENTER pressed and that why the second one works
As far as I know Ctrl+Z is placed in the keyboard buffer before any other entered symbols. Thus any entered characters before Ctrl+Z will be discarded. You need to do the following
I am writing a random words ENTER
^Z ENTER