What I am trying to do is overloading the >> operator of my Book class to take an unknown number of integers from the user in one line. After that, I need to create an array of them.
I tried this:
istream& operator>>( istream& in, Book& b )
{
int x;
delete[] b.editionYears;
b.editionNo = 0;
b.editionYears = new int[0];
cin>>x;
b.addEdition(x);
return in;
}
And I call this with
cout << A << endl;
in the test class where A is a Book object.
I tried this but in here, when the user enters something like "1 2 3 4", it only deletes the array and adds 1 to it, in the second call it deletes 1 again and adds 2.
What I expect is, if the user enters "1 2 3 4", it should delete editionYears array, create again and add 1,2,3,4 to it.
So how can I do this? Thanks for any help.
Your problem is in the use of cin. Try using std::getline.
This other answer may help https://stackoverflow.com/a/5838803/5355195
Consider using std::vector instead of dynamically allocated arrays. There are multiple ways to do this. You may ask users to enter the number of integers they are going to enter, you may ask them to enter something like -1 when they are done, or you may ask them to enter all the integers in a single line, then read it into stringstream then convert to ints and push_back to a vector. The first two approaches are trivial to implement, so here's an example implementation for the third way:
#include <iostream>
#include <vector>
#include <sstream>
int main()
{
std::vector<int> vec;
std::cout << "please enter numbers in a line" << std::endl;
std::string line;
std::getline(std::cin, line);
std::istringstream ss(line);
int i;
while (ss >> i)
{
vec.push_back(i);
}
return 0;
}
Related
I want to write a program in which the names of n different chemical elements are read in the same line in the input (where 1 ≤ n ≤ 17 and n is also read in the input) (the names are made apart by a space). The names of the chemical elements should be stored in different strings for further uses.
As n is unknown, I don't know how to make something like an "array of strings". Of course I should not make 17 different strings st1,st2,st3,... :D.
Can you please help me? Any help will be high appreciated and they will help me a lot.
Thank you in advance.
It sounds like you want to read in a line and split it with spaces. Try something such as this:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main()
{
std::string input;
std::getline(std::cin, input); // takes one line, stops when enter is pressed
std::stringstream ss(input); // makes a stream using the string
std::vector<std::string> strings;
while (ss >> input) { // while there's data left in the stream, store it in a new string and add it to the vector of strings
strings.push_back(input);
}
for (std::string s : strings) {
std::cout << "string: " << s << std::endl;
}
}
You give input such as H He Li, terminated by hitting enter, and the strings are stored in strings (printed in last loop for demonstration).
Edit:
I now see that you want to read the number n in the input, too. In this case, you don't need the stringstream solution. You can do this instead:
int main()
{
int amount;
std::cin >> amount; // read in the amount
std::vector<std::string> strings;
for (int i = 0; i < amount; i++) {
std::string s;
std::cin >> s; // read in the nth string
strings.push_back(s); // add it to the vector
}
for (std::string s : strings) {
std::cout << "string: " << s << std::endl;
}
}
And pass input such as 3 H He Li.
I am trying to create an vector <int> whose size is not pre-defined. It should take in numbers as long as there are numbers in the input terminal and should stop reading when I hit Enter. I tried many solutions including the ones given here and here. In the second case, I can enter a non-integer to terminate the input to the vector. If I use the first solution (code added below), it listens to the input indefinitely.
Code:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
//cout << "Enter the elements of the array: \n";
//vector <int> arr ( std::istream_iterator<int>( std::cin ), std::istream_iterator<int>() );
vector <int> arr;
string buf;
cout << "Enter the elements of the array: \n";
while(getline(cin, buf))
{
istringstream ssin(buf);
int input;
while(ssin >> input)
{
arr.push_back(input);
}
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}
1) I don't feel that typing in a character or a very large number to end listening to input is very elegant. However, the solution with istringstream seems to be the way to go. I am not sure why it doesn't work.
2) Is there any way to detect the Enter from keyboard to terminate listening to input? I tried using cin.get(), but it changed the numbers in the vector.
3) Any other methods or suggestions?
Let's take things one step at a time.
We want to read up until enter is pressed. That means you probably want to use std:getline to read a line.
Then you want to parse it, so you want to put the line into an istringstream.
Then you want to read numbers. While you're reading them, you apparently want to ignore anything other than digits, and you want to keep reading even if you get to a group of digits that can't be converted to a number.
That leaves a few things that aren't entirely clear, such as what to do with that input that's too large to convert? Do you want to just skip to the next? Do you want to read some digits as a number, then read remaining digits as another number?
Likewise, what do you want to do if you get something like "123a456"? Should it be skipped completely, read as "123" (and the "a456" ignored)? Should it be read as "123" and "456", and just the "a" ignored?
For the moment let's assume that we're going to read space-separated groups of characters, and convert all those to numbers that we can. If something is too big to convert to a number, we'll ignore it (in its entirety). If we have a group like "123a456", we'll read the "123" as a number, and ignore the "a456".
To achieve this, we can do something like this:
std::string line;
std::getline(infile, line);
std::istringstream input(line);
std::string word;
std::vector<int> output;
while (input >> word) {
try {
int i = std::stoi(word);
output.push_back(i);
}
catch (...) {}
}
For example, given input like: "123a456 321 1111233423432434342343223344 9", this will read in [123, 321, 9].
Of course, I'm just taking a guess about your requirements, and I haven't worked at making this particularly clean or elegant--just a straightforward implementation of one possible set of requirements.
Please see the comments from #LearningC and #M.M.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>
using std::cout;
using std::cin;
using std::vector;
using std::string;
using std::istringstream;
int main()
{
vector <int> arr;
string buf;
int input;
cout << "Enter the elements of the array: \n";
getline(cin, buf);
istringstream ssin(buf);
while(ssin >> input)
{
arr.push_back(input);
}
cout << "The array: \n";
for(size_t i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}
I need to make a program that reads n numbers in a row. For example, the user first puts in a list of 2 numbers like this:
P n
I managed to read those with scanf but now I need to read the n following numbers, these numbers are given in a row as follows.
1 6 3 99 ... n times
These numbers must be read all at once (or give the impression of).
I already tried using
while(getline(cin,str)){
// do something with str
}
As explained in this thread but I need the actions inside the while loop to stop when I hit the intro key. With my current implementation they don't stop, it just keeps waiting for more lines to read.
In summary:
First, user must be able to input two numbers (P and n)(done!) then hit enter and start typing a list of n numbers (not done!).
Here is my code.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main(void){
int P,n;
scanf("%d %d",&P,&n);
string val;
int score[P];
int i;
for(i=0;i<P;i++){
score[i]=0;
}
while(getline(cin,val)){
printf("Val=%s\n",val.c_str());
stringstream stream(val);
int local;
while(stream >> local){
score[local]=score[local]+1;
printf("%d-%d\n",local,score[local]);
}
}
for(i=0;i<P;i++){
printf("%d-%d\n",i,score[i]);
}
return 0;
}
Use scanf() inside the n times loop instead of getline().
for(int i = 0; i < n; i ++){
scanf("%d",&variable);
}
Not sure I understood your question, but this code will read 2 numbers, then a line and then finish.
using namespace std;
int main(){
int P,n;
cin >> P;
cin >> n;
int *score = new int[P];
for(int i=0;i<P;i++){
score[i]=0;
}
int num;
string val;
cin.ignore();
getline(cin, val);
istringstream stream(val);
while (stream >> num) {
printf("Val = %d\n", num);
score[num]=score[num]+1; // potential segmentation fault here in your code
printf("%d-%d\n",num,score[num]);
}
delete [] score;
return 0;
}
The fault would occur because you are assuming that the number on the line is smaller than P, which is the size of the array. However, the following input would cause error:
1 2
5
This question is almost a classic. The classic question has this code:
cin >> n;
getline(cin, s);
and then the author is puzzled why s is empty. Your variation does the same, although it also uses C stdio function to make matters more confusing. The problem is that the first call is a field-based input, which will read a single value n and leave any other input in the buffer! If the user entered 42 and hit enter, the remaining input is the newline. The second getline() call then reads an empty string and discards the newline.
For interaction with the user, only use getline() and then try to parse each line. Using stringstreams or sscanf(), since you seem familiar with it, are both valid options. However, if you only want to read the input an not really interact, David Weston's suggestion is also a good one and probably the easiest one, too. However, since you're using C++, I'd suggest using cin >> variable instead.
Our professor gave us this assignment, where we have a .txt file with the following format:
John 23
Mary 56
Kyle 99
Gary 100
...etc. etc.
What we have to do is read the file, and store the names and scores in parallel arrays.
This is turning out to be a bit more challenging to me than I anticipated. What is confusing me, when searching around stack, is all the different libraries people use to do this. Our Prof just wants us to use string, fstream, and sstream to do this.
Below is what I've come up with so far, it compiles perfectly, splits the scores from the names but stores them in the same array:
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
const int SIZE = 50;
string names[SIZE];
int score [SIZE];
short loop = 0;
string line;
ifstream inFile("winners.txt");
if (inFile.is_open())
{
while(!inFile.eof())
{
istream& getline(inFile >> line);
names[loop] = line;
cout << names[loop] << endl;
loop++;
}
inFile.close();
}
else cout << "Can't open the file" << endl;
return 0;
}
I'm not looking for someone to solve my HW problem, I just want a push in the right direction!
If you want to read two things for each line of input, it seems reasonable to have two "read" statements:
std::string name;
inFile >> name;
int score;
inFile >> score;
std::cout << "Read score " << score << " for name " << name << '\n';
...then you can do that repeatedly until you've read the entire file.
Edit: After you get the basic logic worked out, you might want to think about error handling. For example, what is appropriate behavior for your program if the input file doesn't contain 50 pairs of (name, score)? How can you change your code to get that behavior?
Each line in the file consists of a name and a score separated by whitespace. You're reading each line but not splitting it into its parts (the name and the score).
Ideally you would use a vector for this, but since it seems that you were asked to use arrays we'll stick with arrays. What you have above looks good until you start reading entries. A more idiomatic way to accomplish this is to use std::getline, i.e.
ifstream inFile( "winners.txt" );
std::string line;
while( std::getline( inFile, line )) {
// Do work here.
}
Inside the loop you need to split the line on the space. Without solving the problem for you, I suggest you take a look at the find and substr functions of the string class: here. They will give you everything you need to solve the problem.
I want to get a line of strings and write every word into it's own variable, so that I can use them for example in if clauses.
I tried:
cin >> var1;
cin >> var2;
cin >> var3;
cin >> var4;
But this only works if 4 words are entered. I need a way to count the words because I don't know if it's 1,2,3,4 or more words the user enters.
Maybe there is a way with getting the whole string:
getline(cin, string1);
And cut it into words after that.
Sorry, I searched a lot but I can't find a way.
I also tried to write the cinbuffer into a variable, but the only way I can do this is with
cin >> varx;
Which is only usefull if there is something in the cinbuffer. If not, the user gets asked for input again.
EDIT: Just found this, works for me. Thanks Anyway!
C++ cin whitespace question
You’re on the right track. You can read a line with getline() then use an istringstream to treat that line as a stream of its own. Change this for whatever type T you happen to be using.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
int main(int argc, char** argv) {
using namespace std;
vector<T> values;
{
string line;
getline(cin, line);
istringstream stream(line);
// Read values into vector.
copy(istream_iterator<T>(stream), istream_iterator<T>(),
back_inserter(values));
}
cout << "Received " << values.size() << " values:\n";
// Copy values to output.
copy(values.begin(), values.end(),
ostream_iterator<T>(cout, "\n"));
return 0;
}
Writing things to different variables like this is usually the wrong answer. It seems like you want something like an array.
sounds like you use getline
http://www.cplusplus.com/reference/string/getline/
then use something like boost split to dump each item into an array
http://www.cplusplus.com/faq/sequences/strings/split/