I am new to programming in C++.
I am trying to ask the user an input (for example):
std::string numbers;
std::cout << What is your favorite number;
std::cin >> numbers
If the user entered
1, 2, 3
How do I extract only the number "2"? I know in python, you would do something like numbers[1], but is there a same way in C++ as well?
So, "what are your favorite numbers?"
The idea is the same as in python or any other language: split the input line by the separator character, trim if you care, and finally get the element you want, if it exists.
Splitting a string by a character
Eventually, trim
Finally, you should have a vector of string, and you can get the second with v[1] or similar, checking if it exists
you can get the length of string by numbers.length().
then you can use for loop.
for(int i =0 ; i < numbers.length();i++)
{
if(numbers[i] == '2')
// do what you want you do here with 2
}
Keep in mind, your cin won't get entire "1, 2, 3" string because of whitespace. You should use getline instead of cin.
such as..
getline(cin, numbers,'\n');
To catch a line of numbers:
int main()
{
std::vector<int> numbers;
std::string line;
std::getline(std::cin, line); // First read the whole line of input
std::stringstream linestream(line); // Set up to parse the line
int number;
while(linestream >> number) { // Read a number
char x; // for the comma
linestream >> x; // remove the comma
numbers.push_back(number); // Add to the vector (array)
}
// Print the number
std::cout << "The second number is: " << numbers[1] << "\n"; // vectors are 0 indexed
}
Related
I have written a program in which certain entries are made into a map. Later, using an iterator, I wanted to see the key-value pairs in this format
key=value.
But the output is coming as
=key value.
Here's the code
int main() {
map<string,string> mp;
int n;
string name, number;
cin>>n;
for(int i=0; i<n; ++i)
{
getline(cin,name);
getline(cin,number);
mp.insert(pair<string,string>(name,number));
}
string line;
map<string,string>::iterator fndr;
fndr = mp.begin();
cout << (*fndr).first << "=" << (*fndr).second;
return 0;
}
Here's the input
2
abhay 239487
hello 23478
Here's the output
=abhay 239487
Your .first is empty and the whole thing is going in .second. getline() is taking the whole string input and storing it in number variable. Quick solution (but won't work for names that contain spaces):
cin >> name;
cin >> number;
Explanation:
Before using getline(), you have used cin >> n to input the number of strings. After the input, when you press Enter a \n is appended at the end of your input. So your input actually looks like this:
2\n
abhay 239487\n
hello 23478\n
Now cin >> n uses 2 in the first line to store it in n variable but the \n is still there in the stream. When getline() is used for the next input, it finds the \n in the input stream and terminates thus storing nothing in name variable (\n is a delimiter for getline()). The next getline() finds the string abhay 239487 before it encounters another \n and terminates.
Thus, we need to ignore the \n after 2 before the first execution of getline()). We can use cin.ignore() between the last cin and the first getline(). This will ignore the next character in the input stream.
Code
int main() {
map<string,string> mp;
int n;
string name, number;
cin>>n;
cin.ignore();
for(int i=0; i<n; ++i) {
getline(cin,name);
getline(cin,number);
mp.insert(pair<string,string>(name,number));
}
string line;
map<string,string>::iterator fndr;
fndr = mp.begin();
cout << (*fndr).first << "=" << (*fndr).second;
return 0;
}
You can notice after using cin.ignore(), abhay 239487 goes in name and hello 23478 goes in number. The output is:
abhay 239487=hello 23478
which is expected for this case.
How to workaround the problem of segregating key: value pair ? There are two ways:
Either you can input the name (key) and the corresponding number (value) in two different lines (This method will work for strings which contains spaces in name) like this:
2
abhay nayar
239487
hello
23478
Or, you can use cin >> name >> number to get those values (but you cannot use names that contain spaces because any whitespace character is a delimiter for cin).
I am trying to read a line of string characters with numbers (e.g "30 40 50 20") and put them into a vector. I also need to avoid empty space and newlines. But when I read the input, it doesn't see the string "30", it sees the characters "3" and "4".
void Input() {
getline(cin,line, '\n');
for (int i = 0; i < line.length(); i++) {
if (! (isspace(line[i]))) {
cout << line[i] << ", ";
scores.push_back(line[i]);//(atoi(input));
}
}
cout << scores.size() << "! ";
}
A line like "30 40 50" won't give a vector size of 3, it will give a size of 6.
What are the optimal ways to get around this issue?
EDIT: I should have clarified in the original message that this is for a challenge, in which I am unable to include the string stream library in the original case.
I think you're doing the right thing grabbing the whole line before parsing, otherwise you get into a bit of a pickle. But you do actually have to do some parsing. Right now you're just pulling out individual characters.
The following isn't optimal but it'll get you started — continue using formatted stream extraction, but isolated to this line from the file.
So:
void Input()
{
getline(cin, line, '\n');
istringstream ss(line);
int val;
while (ss >> val)
scores.push_back(val);
cout << scores.size() << "! ";
}
Read the line and put into a std::istringstream, then read as "normally" using the >> operator from the string stream.
Putting the line into a std::istringstream and extracting the numbers from that is the best way.
Here's an alternative to a manual loop using the standard library:
std::istringstream numbers(line);
std::copy(std::istream_iterator<int>(numbers),
std::istream_iterator<int>(),
std::back_inserter(scores));
It is probably best to take advantage of an input stringsteam, example: http://www.cplusplus.com/reference/sstream/stringstream/stringstream/.
The extraction operator allows you to parse data from the stream to some variable of datatype T. Another advantage of input stringstreams is the ability to query whether the pass was successful, and in your case ignore whitespace characters by setting the skipws format flag.
Example:
int main () {
std::istringstream ss("30 40 50");
float val = 0.0f;
while( ss >> std::skipws >> val )
{
std::cout << val << "\n";
}
return 0;
}
Out: 30 40 50
I'm scanning a text document, and it is formatted like so:
3 10
1
2
2
1
3
1
1
1
2
2
The first two integers at the top represent the amount of candidates and the number of votes respectively. I'm having difficulty detecting the string for the amount of votes, "10"
Since I'm working in c++, I've tried doing this so far:
string line;
int candidateTally;
int voteTally;
ifstream file("votes.txt");
//detect the candidate tally "3"
getline(file, line);
candidateTally = atoi(line.c_str());
cout << candidateTally << endl;
//output the candidate tally "10" but it's only outputting "1"
getline(file, line);
cout << line;
I'm not quite sure how to pick up the second char for 0 to get the full string of "10"
It seems like the getline function cuts off before picking up 0, because that might represent the '\n' char?
I'd like to have it so that it detects the '0' and includes it in the string with "1" so that I can convert that to the int that it is supposed to be, 10.
How can I fix this?
Ask yourself what getline does... Yes, it gets a line.
So the first call 'gets' the entire line "3 10", and the second call gets the next line in the file : "1"
You should use the >> operator to read incoming values from the file. This will also remove the need to mess with atoi() and char pointers.
Use the following instead:
int candidateTally;
int voteTally;
ifstream file("votes.txt");
//detect the candidate tally "3", and the vote tally "10".
file >> candidateTally >> voteTally;
cout << candidateTally << endl;
cout << voteTally << endl;
The operator>> ignores whitespace. Its first call (file >> candidateTally) will "eat" the "3", and the second call (>> votetally) will skip the whitespace, then pick up "10". The precision can be read here, but the details are quite hard to read.
If you are going to get the line for the number of candidates and votes, there is no reason to use atoi:
std::string line;
int candidateTally;
int voteTally;
std::ifstream file("votes.txt");
if (std::getline(file, line))
{
std::istringstream iss(line);
iss >> candidateTally >> voteTally; // you should also add error handling here
// ...
}
else
{
// handle the error here
}
Ok, I'm trying to get good at using pointers so I'm trying to write a input validation for the user input to make sure that anything that isn't a number is handled correctly. When I use isdigit() isn't working for me. I still get an exception when I enter a alphabet. Any suggestions? Thanks. Check this out:
#include<iostream>
#include<algorithm>
#include<string>
#include<cctype>
using namespace std;
void EnterNumbers(int * , int);
int main()
{
int input = 0;
int *myArray;
cout << "Please enter the number of test scores\n\n";
cin >> input;
//Allocate Array
myArray = new int[input];
EnterNumbers(myArray,input);
delete[] myArray;
return 0;
}
void EnterNumbers(int *arr, int input)
{
for(int count = 0; count < input; count++)
{
cout << "\n\n Enter Grade Number " << count + 1 << "\t";
cin >> arr[count];
if(!isdigit(arr[count]))
{
cout << "Not a number";
}
}
}
If you test if (!(cin >> arr[count])) ... instead - isdigit(arr[digit]) tests if the value of arr[digit] is the ASCII code of a digit [or possibly matches Japanese, Chinese or Arabic (that is, as an Arabic script typeface, not that it's a 0-9 like our "Arabic" ones) digit]. So if you type in 48 to 57, it will say it's OK, but if you type 6 or 345, it's complaining that it is not a digit...
Once you have discovered a non-digit, you will also need to either exit or clean out the input buffer from "garbage". cin.ignore(1000, '\n'); will read up to the next newline or a 1000 characters, whichever happens first. Could get annoying if someone has typed in a million digits, but otherwise, should solve the problem.
You will of course also need a loop to read the number again, until a valid number is entered.
The way I do this kind of input validation is that I use std::getline(std::cin, str) to get the whole line of input and then I parse it using the following code:
std::istringstream iss(str);
std::string word;
// Read a single "word" out of the input line.
if (! (iss >> word))
return false;
// Following extraction of a character should fail
// because there should only be a single "word".
char ch;
if (iss >> ch)
return false;
// Try to interpret the "word" as a number.
// Seek back to the start of stream.
iss.clear ();
iss.seekg (0);
assert (iss);
// Extract value.
long lval;
iss >> lval;
// The extraction should be successful and
// following extraction of a characters should fail.
result = !! iss && ! (iss >> ch);
// When the extraction was a success then result is true.
return result;
isdigit() applies to char not to int as you're trying. The cin >> arr[count]; statement already ensures an integer numeric digits format is given in the input. Check cin.good() (!cin respectively) for possible input parsing errors.
I recently bought a C++ Primer and got stuck with a problem. I have to read a sequence of words using cin and store the values in a vector. After having unusual problems, I found out that while(cin >> words) invites problems (like infinite loop) if you expect invalid inputs: Using cin to get user input
int main()
{
string words;
vector<string> v;
cout << "Enter words" << endl;
while (cin >> words)
{
v.push_back(words);
}
for(auto b : v)
cout << b << " ";
cout << endl;
return 0;
}
Therefore, I'm trying to find an alternative to this problem. Help ?
That link you provided regarding input problems is a little different. It's talking about when you expect the user to enter a particular value, but you might fail to read the value (let's say it's an integer) because something else was entered. In that case, it's good to use getline to retrieve a whole line of input and then parse the value out.
In your case, you're just after words. When you read a string from a stream, it will give you all consecutive non-whitespace characters. And, ignoring punctuation for a moment, you can call that a "word". So when you talk about 'invalid input', I don't see what you mean. The loop will continue to give you "words" until there are none left in the stream, at which point it will error:
vector<string> words;
string word;
while( cin >> word ) words.push_back(word);
However, if you expect the user to enter all words on one line and press enter to finish, then you need to use getline:
// Get all words on one line
cout << "Enter words: " << flush;
string allwords;
getline( cin, allwords );
// Parse words into a vector
vector<string> words;
string word;
istringstream iss(allwords);
while( iss >> word ) words.push_back(word);
Or you can do this:
cout << "Enter words, one per line (leave an empty line when done)\n";
vector<string> words;
string line;
while( getline(cin, line) )
{
// Because of the word check that follows, you don't really need this...
if( line.size() == 0 ) break;
// Make sure it's actually a word.
istringstream iss(line);
string word;
if( !(iss >> word) ) break;
// If you want, you can check the characters and complain about non-alphabet
// characters here... But that's up to you.
// Add word to vector
words.push_back(word);
}