C++ multiple line input from keyboard - c++

For an assignment of mine, we're suppose to take in several lines of input from the keyboard. For example:
Please enter your name: (this is static. Always 1 input)
Justin
Please enter the names: (this can be any number of inputs, smallest being 1)
Joe
Bob
John
Jackson
In the end, I want to compare the named entered at the beginning with all of the names entered in after. I tried using getline and cin, but that seems to only work if I know the exact number of names I expect to be entered. Can anyone guide me in the right direction please. Thank you

Try this
void read_lines( std::istream& in, std::list< std::string >& list ) {
while( true ) {
std::string line = "";
std::getline( in, line );
if( line != "" ) {
list.push_back( line );
} else {
break;
}
}
}

You should have added some rough code showing your efforts on doing the assignment.
However, I will provide you with some initial naive code (please read the comments inside!):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string name, temp;
vector<string> names; // this is just one of the possible container that you can use
bool result = false; // flag used to store the result of the matching operation (default: false)
// first we ask the user to enter his/her name
cout << "Please enter your name:" <<endl;
cin >> name;
// then we need something a little bit more complicated to look for variable number of names
cout << "Please enter the names:" <<endl;
while(cin)
{
cin >> temp;
names.push_back(temp);
}
// This for-loop is used to go through all the input names for good-match with the user name
for( int i = 0; i < names.size(); i++ )
{
temp = names.front();
if (name == temp) result = true; // change the flag variable only in case of match
}
cout << "Valid match: " << (result?"yes":"no"); // ternary operator
}
You did not provide in your question enough details.. so the above code may not fully fit your requirements!

Related

Convert Text with spaces to Camel Case

i want to take a film name from user and change that to camel case , my code work if there is no numbers or spaces between letters
#include <iostream>
#include <string>
using namespace std;
int main()
{
int Count,Length=0;
string Films;
cout<<"Enter Film Count: ";
cin>>Count;
for(int i=0;i<Count;i++)
{
cout<<"Enter Film Names: ";
cin>>Films;
Length=0;
while(Length<1000)
{
switch(Length)
{
case 0: Films[Length]=toupper(Films[Length]); break;
default: Films[Length]=tolower(Films[Length]); break;
}
Length++;
}
cout<<"Results: "<<Films<<endl;
}
return 0;
}
i tried other topic solutions but i cant do it correctly.
Problem:
You've chosen the wrong approach to solve the problem. Your current code only changes the first character to uppercase and the rest to lowercase.
Solution:
Instead of using a while and a switch, use a for loop and an if statement that checks for spaces, delete them and change the following characters to uppercase.
Additional information:
using namespace std; is considered a bad practice (More info here).
The while loop can be replaced for a for loop to limit the Length scope and improve readability.
It's a good practice to check whether the std::cin inputs are valid or not to prevent Undefined Behavior.
Full code:
#include <iostream>
#include <string>
int main()
{
int count;
std::cout << "Enter film count: ";
std::cin >> count;
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
std::cin.ignore(10000,'\n');
for(int i = 0; i < count; i++)
{
std::string film;
std::cout << "Enter film name: ";
std::getline(std::cin, film);
if(std::cin.fail())
{
std::cout << "Invalid input." << std::endl;
exit(0);
}
if(film.size() == 0)
break;
film[0] = tolower(film[0]);
for(unsigned int i = 1; i < film.size() - 1; i++)
{
if(film[i] == ' ')
{
film.erase(i,1);
film[i] = toupper(film[i]);
i--;
}
}
std::cout << "Result: " << film << std::endl;
}
return 0;
}
Example:
Enter film count: 1
Enter file name: Love live! the school idol movie
Result: loveLive!TheSchoolIdolMovie
I could see really a lot of code to solve a simple problem. I will later show a one-liner that converts a string with words to camel case.
As a side note, code should always contain tons of comments. Otherwise, nobody will understand it, and later, even you will not understand your own code.
Anyway. Let us look at the requirements. What shall we do?
User shal input the number of film titles to convert
Title for title shall be read from the user
Titles have to converted to camel case style and shown to the user
Now, we think an how we want to solve the problem:
We will always instruct the user what to do next
We will make sanity checks for the users input
We will get the number of titles from the user
Then, we create a loop and read title for title
The current read title will be converted to camel case
The result will be shown to the user
Ok, we need to go into details for "The current read title will be converted to camel case"
Let us think again. We get a string, that consists of words. So, we need to extract words from the string. We consider that everything is a word, that is separated by white space.
Then, depending on the camle case style, please see here, we convert all first letters of a word to uppercase and discard all white spaces. The first word will have a starting lower case letter (selectable).
But how to extract words from a string? We remember the extractor operator >> will discard all white spaces and only read the text. That is what we need. So, we will pack the string into an std::istringstream and then extract word for word.
And with a simple boolean condition, we decide, if the first letter of the first word shall be in upper- or lower case.
So, let us implement or thoughts into code:
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index + 1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Put the complete string into an istringstream, so that we can extract the words
std::istringstream lineStream{line};
// Here we can select the style of our camel case
bool wordShallHaveFirstLetterInUpperCase{ false };
// Extract all words from the line stream and convert first letter
for (std::string word{}; lineStream >> word; std::cout << word) {
// Depending on the camel case style
if (wordShallHaveFirstLetterInUpperCase)
word[0] = std::toupper(word[0]);
else
word[0] = std::tolower(word[0]);
// From now on all words shall start with an uppercase character
wordShallHaveFirstLetterInUpperCase = true;
}
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
This is a rather straight forward implementation of our detailed design. And after running some tests, we see that it will work.
Now, for the more advanced users.
In professional software development, people try to avoid loops and branch statements. Because this will increase the code complexity (usually measured via the cyclomatic complexity). And complex code needs more tests cases for C0, C1 or even MCDC code coverage.
Therefore, often algorithms from the standard library are used. And they hide the loops somehow inside. But that is OK, because the standard library is thoroughly tested and sometimes even qualified with a certification.
So, as one example, you can do the whole camel case conversion with one statement. With std::transform and by using std::regex and iterators and a stateful Lambda.
The downside is, that it is not so easy to understand for the reader . . .
Please see yourself:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <regex>
#include <string>
#include <cctype>
// The separator will be white space
const std::regex re{ R"(\s+)" };
int main() {
// Instruct user, what to do
std::cout << "\nPlease end number of film titles to convert: ";
// Read input from the user and check, if that was valid
if (size_t numberOfFilms{}; std::cin >> numberOfFilms && numberOfFilms > 0) {
// Now, in a loop, read all the film titles that the user wants to be processed
for (size_t index{}; index < numberOfFilms; ++index) {
// Instruct user, what to do
std::cout << "\n\nPlease end film title " << index+1 << ": \t";
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(std::cin >> std::ws, line)) {
// Convert to camel case and show output
std::transform(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout),
[firstIsUpper = 0U](std::string s) mutable {if (firstIsUpper++) s[0] = std::toupper(s[0]); else s[0] = std::tolower(s[0]); return s; });
}
else std::cerr << "\n\n*** Error: Problem while a title\n\n";
}
}
else std::cerr << "\n\n*** Error: Problem while reading the number of ilm titles\n\n";
return 0;
}
Ultra compact, but difficult to read . . .
In case of questions, please ask.

Reading string then int line by line in C++

So, I have a file that contains a pattern of a string then an int alternating line by line.
Something like this:
John McClane
30
James Bond
150
Indiana Jones
50
In this example, I would set John McClane to a string variable and then 30 to an integer variable. My issue is dealing with two types. I want to use getline(), but that only works with strings.
Is there an efficient or "right" way of doing this?
There are a number of approaches you could try.
Get string input, and convert to an integer if valid
Convert every second string to an integer
Try to read an integer when you expect one (just using cin >> in;). If you want a robust program, you can check validity with cin.good()
I don't know if there is a "right" way of doing this per say, but it's not a very taxing operation, so whatever you choose should be fine.
You could make a variable like this
string ibuf;
Then convert it to an integer doing this
getline(cin, ibuf);
(Whatever your int variable is) = strtol(ibuf.c_str(), NULL, 10);
One thing about C++ is that there are a large number of ways to accomplish any one task. One way to get integers from strings is to use a stringstream. There is a tutorial on stringstreams here
As for your problem with reading the alternating file, consider the following pseudocode:
boolean isInt = false;
while(fileIsNotOver) {
//getline
if(isInt) {
//use stringstream to get int here
} else {
//do whatever with the name here
}
isInt = !isInt;
}
I don't know if this fully works as i didn't tested it however it just compiles fine and answer should be something like this i think.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
int counter = 0;
int number;
string test_string;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,test_string) )
{
cout << test_string << '\n';
++counter;
if(counter % 2 == 0 ){
number = atoi(test_string.c_str());
cout << number << '\n';
}else{
cout << test_string << '\n';
}
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
You can try like this to read a string then an int alternating line by line.
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int main()
{
string name;
int number;
freopen("input.txt", "r", stdin);
while (getline(cin, name))
{
cin >> number;
/*
process the input here
...
...
*/
getline(cin, name); // just to read the new line and/or spaces after the integer
//getchar(); //you can use getchar() instead of getline(cin, name) if there is no spaces after the integer
}
return 0;
}
Thanks !!!

Incorrect addition from a file

if (infile.is_open())
{
int count = 0;
while (infile)
{
string author, ratings;
getline(infile, author);
if (author != "")
{
getline(infile, ratings);
// TODO: Create new User object
User newuser(author, ratings);
// TODO: Add new User object to vector
userList.push_back(newuser);
count++;
}
}
cout << count << " users read in. Closing user file." << endl;
The output for this that I am getting is that 86 users were read in from the text file. the correct output is supposed to be 32. I think that it is because I am using a while loop but I am not fully sure.
Your condition should be something like
while (getline(author, infile) && getline(ratings, infile)) {
// validate input, then process it
}
Then the if (infile.open()) becomes trivial. There is a '}' missing in the code you posted, which makes it hard to really tell where your counting error is coming from, or maybe that's just the reason, incrementing your count in the wrong place. Please make sure your examples are complete and possibly even compile.
A little tip, you can just write
userList.push_back(User(author, ratings));
EDIT:
I created this minimal test code (for you) and tested it on the following file, resulting in the following output. Can you confirm? Please note: The current program doesn't accept newlines in your file, e.g. for grouping various users, however, this is a feature easily added, once the basic program works.
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct User {
string author, ratings;
User(string auth, string rat)
: author(auth), ratings(rat) {}
};
int main()
{
ifstream ist("test.txt");
if (!ist) {
cout << "Could not open file test.txt\n";
return 1;
}
vector<User> userList;
string author, ratings;
size_t count = 0;
while (getline(ist, author) && getline(ist, ratings)) {
if (author != "" && ratings != "") {
userList.push_back(User(author, ratings));
++count; // in this case, count++ is equivalent
}
}
cout << count << " users read in. Closing user file.\n";
}
The file test.txt
foo
bar
foobar
lalilu
myTotalUsersAre
3
Output:
3 users read in. Closing user file.

Reverse String Error?

I am creating this revese string App but i get a error if i include a space in the string !
#include <iostream>
#include <string>
using namespace std;
int main()
{
int inputa;
cout<<"%%%%%%%%%%%%%%%%%%String Reversing App%%%%%%%%%%%%%%%%%%%%%%%%"<<endl<<endl;
cout<<"\nEnter 1 to continue and 0 to exit"<<endl<<endl;
cin>>inputa;
if(inputa!=0)
{
do
{
string a,c="";
cout<<"\nEnter the string you want to Reverse : ";
cin>>a;
for(int x=a.length()-1; x>=0; x--)
{
c=c+a.substr(x,1);
}
cout<<"\nThe Reverse String is : "<<c<<endl;
cout<<"\nEnter 1 to continue and 0 to exit"<<endl<<endl;
cin>>inputa;
}
while(inputa!=0);
}
//not my home work
}
If I type the following string like "abc def" there i get an error . But otherwise it works perfectly ! Is there some mistake with the codes ! I am new to CPP so it would be helpful if you could help me !
operator>> will stop reading at the first space (as David pointed out) - use getline instead
std::string a;
getline(std::cin, a);
Full edit of your code
#include <iostream>
#include <string>
#include <limits>
int main()
{
std::cout << "%%%%%%%%%%%%%%%%%%String Reversing App%%%%%%%%%%%%%%%%%%%%%%%%\n\n";
std::cout << "\nEnter 1 to continue and 0 to exit" << std::endl;
int inputa;
std::cin >> inputa;
if(std::cin && inputa!=0)
{
std::cin.ignore(std::numeric_limits<int>::max( ), '\n');
do
{
std::string a,c;
std::cout<<"\nEnter the string you want to Reverse : ";
getline(std::cin, a);
for(int x=a.length()-1; x>=0; --x)
{
c+=a[x];
}
std::cout<<"\nThe Reverse String is : " << c << std::endl;
std::cout << "\nEnter 1 to continue and 0 to exit" << std::endl << std::endl;
std::cin >> inputa;
std::cin.ignore(std::numeric_limits<int>::max( ), '\n');
}
while(std::cin && inputa!=0);
}
}
Including David's verbatim answer because he answered with much more detail (David Rodríguez - dribeas) - please +1 him before he deletes it. His answer adds much more information that I did not mention so we are merging this into a single reply at Davids request,
The answer by Adrian is correct, deals with the immediate issue and provides a solution. As to why it enters an infinite loop, the reason is that after reading the first word, you are trying to read an integer std::cin >> inputa, which will fail as cde cannot be parsed as an integer. At this point the stream enters a fail state and subsequent reads will fail without doing anything (until you clear the error state).
What should you do?
If you want to process whole lines, then you should use std::getline, rather than operator>>. Beware on mixing both, as operator>> won't consume the spaces after the read (including new lines) and you might just read an empty line with the next std::getline. You can either always read with std::getline and then parse the line, or use ignore to clear up to the newline. Finally, whenever you perform IO operations, don't expect the operation to succeed: check the state of the stream. If you don't and your loop depends on IO to complete, it is quite easy to enter this sort of infinite loop, where the stream is marked as failed, no later reads succeed and you never break out of the loop.

How do I get a C++ program to count the number of words as a user enters input?

I'm trying to write a program that keeps taking input from the user until the user enters "quit." Each time the user enters input, I want the program to print out the number of words the user has entered. So the following input on the user's part:
hello how are you
would yield the following output:
You entered 4 words.
However, I am having trouble writing the program so that it counts the number of words on just one line; it doesn't clear the number before going onto the next line. So, if it took input from the user three times, it would add up the total number of words on those three lines. For example, the following input:
how are you
i am good thank you
quit
would yield the following output:
You entered 9 words.
when I want it to output the number of words following each line the user enters (except quit), i.e.
>>how are you
<<You entered 3 words.
>>i am good thank you
<<You entered 5 words.
>>quit
Here's the relevant bit of my code:
char *input;
int inum;
int inputLoop()
{
char quit[] = "quit";
inum = 0; //counts number of words
while (strcmp(input, quit) != 0)
{
cin >> input;
inum++;
}
cout <<"You entered " <<inum <<" words." <<endl;
I'd rather not use something like a vector; whatever I use will need to be converted to a *char eventually because my global variable is a *char. (And my global variable is a *char because, depending on certain conditions, *input may be set to *argv[] from main.)
I've tried all sorts of things, but I just can't seem to get past the fact that strcmp(input, quit) compares one word of the input at a time to quit rather than comparing the entire input line to quit. HELP.
None of your requirements precludes the use of std::string and std::vector. I recommend you use them.
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
std::vector<std::string> words;
int inputLoop()
{
char quit[] = "quit";
total_words = 0;
std::string line;
// grab a line at a time
while(std::getline(std::cin, line) && line != quit) {
// clear the vector of words
words.clear();
// make a string stream to read words from that line
std::stringstream ss(line);
// grab all the words into a vector
std::string word;
while(ss >> word) {
words.push_back(word);
}
std::cout <<"You entered " <<words.size() <<" words." <<endl;
}
}
int main(int argc, char** argv) {
// get the data from argv
words = std::vector<std::string>(argv, argv + argc);
}
You should use getline() to get an entire line of input into some buffer. Then, process that buffer of input to count the number of words in it. Assuming you define each word to be a block of characters separated by a space. Myself, I am a fan of strtok() for breaking up a buffer.
An alternative approach, just for fun:
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
unsigned num = 0;
std::for_each(
std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
[&num](const std::string& s)
{
if (s == "quit")
std::cin.setstate(std::ios::eofbit);
++num;
if (std::cin.peek() == '\n') {
std::cout << "You entered "
<< num
<< " word"
<< ((num == 1) ? "." : "s.")
<< '\n';
num = 0;
}
});
}
Doesn't waste resources by tokenizing a line into a vector :)
I would call distance
#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <sstream>
int main()
{
std::string line;
while(std::getline(std::cin, line) && line != "quit")
{
std::stringstream linestream(line);
std::cout << "You entered "
<< std::distance(std::istream_iterator<std::string>(linestream),
std::istream_iterator<std::string>())
<< " words\n";
}
}