Mixed number class istream issues - c++

I assigned myself some homework over the summer, and the project I am 98% finished with has come to a standstill due to this one problem.
I have a class called Mixed. It contains member data for a whole number, a numerator, and a denominator. I need to overload all of the common operators to allow multiplication, addition, comparison and streaming of objects of type Mixed. I have all the operators overloaded except for >> (the extraction operator).
All mixed numbers read in will be of format:
whole numerator/denominator
ex: 1 2/3, 0 7/8, -3 18/5, 0 -1/89
Header: friend istream& operator>> (istream &, Mixed);
CPP file: istream& operator>> (istream &in, Mixed m) {...}
For the assignment, I am limited to the iostream and iomanip libraries. My plan was to read in the values from the stream and assign them to temporary int variables (w, n, d) which I would then use with the Mixed constructor to create object m. Unfortunately, I cannot think of a way to separate the numerator and denominator. They are both ints, but they have a char (/) between them.
I cannot use getline() with its delimiter, because it assigns data to a char array, which I do not believe I can convert to an int without another library.
I cannot use a char array and then segment it for the same reason.
I cannot use a while loop with get() and peek() because, again, I do not think I will be able to convert a char array into an int.
I cannot use a string or c-string and then segment it because that requires external libraries.
Once again, I need to split a value like "22/34" into 22 and 34, using only iostream and iomanip. Is there some fairly obvious method I am overlooking? Is there a way to implicitly convert using pointers?

You could first extract the nominator, then the separating character, and then the denominator.
Example for illustration:
istream& operator>> (istream &in, Mixed &m) {
int num, denom;
char separ;
in >> num;
in.get(separ);
if (separ != '/')
in.setstate(ios::failbit);
in >> denom;
if (in) {
// All extraction worked
m.numerator = num;
m.denominator = denom;
}
return in;
}

Once again, I need to split a value like "22/34" into 22 and 34, using
only iostream and iomanip.
Couldn't you just read in the first integer, use get to get the next character, and then read the second integer? Something like this:
#include <iostream>
int main() {
using std::cin;
using std::cout;
int num;
int den;
while(cin) {
cin >> num;
if (cin.get() != '/') {
// handle error
}
cin >> den;
cout << num << "/" << den << std::endl;
}
return 0;
}
You can then make sure that the character read between the two integers was a '/' and handle appropriately if it isn't.

Related

How to overload cin and use getline

I am trying to finish my lab, however I don't know how to allocate memory to a string. So I keep getting the error
warning: ‘_name’ is used uninitialized in this function [-Wuninitialized]
I don't also understand if my getline line is correct.
std::istream& operator>>(std::istream& is, Grade& RO){
int _mark;
char* _name;
std::cout<<"Subject name: ";
is.ignore();
is.getline(_name, (strlen(_name) + 1));
std::cout<<"Mark :";
is>> _mark;
RO=Grade(_name, _mark);
return is;
}
Ok #Jessica, (to general question and few info) I guess,
Grade is a class with two data members: int mark and string name. And you want to overload the insertion operator >> to populate these values.
(I recommend you leave all the cout expression outside this function). Here is one possible implementation:
istream& operator>> (istream& is, Grade& RO){
// declare local variables to insert the input values
int mark;
string name;
// extract values from input stream
is >> mark >> name;
// assuming you have member functions that set values for the object RO
RO.set_mark(mark);
RO.set_name(name);
return is;
}

c++ How to istream struct contains vector

How to istream struct that contains vector of integer as member, I tried the following code but it failed to read the file
struct Ss{
std::vector<int> a;
double b;
double c; };
std::istream& operator>>(std::istream &is, Ss &d)
{
int x;
while (is >> x)
d.a.push_back(x);
is >> d.b;
is >> d.c;
return is;
}
std::vector <std::vector<Ss >> Aarr;
void scanData()
{
ifstream in;
in.open(FileInp);
std::string line;
while (std::getline(in, line))
{
std::stringstream V(line);
Ss S1;
std::vector<Ss > inner;
while (V >> S1)
inner.push_back(std::move(S1));
Aarr.push_back(std::move(inner));
}
}
I did search for similar problems but i could not find one.
The immediate problem here is that the same condition that terminates your while loop prevents the successive reads from working. The stream is in an error state. So your double values are never read.
Actually, the integer part of the first double is read as an integer, leaving the fractional part in the stream. You can't recover from this.
One way to solve this might be to read in your values as strings, converting them to integers using stoi and putting them in the vector. But before you do the integer conversion, check for a decimal point in the string. If it contains one, break out of the loop. Convert the double values using stod.

Reading a txt file

For my project I have to overwrite the operator>> method to read in an array of numbers from a text file. This is my first time doing any of this and I am pretty lost. My code so far looks like this.
std::istream& operator>>(std::istream& in, bigint array){
bool semi = false ;
while(!semi){
if(get() = ';')
semi = true ;
in <<get();
}
return in ;
}
And the file looks like this.
10000000000000000000000000000000000345;
299793000000
00000000000000000000067;
4208574289572473098273498723475;
28375039287459832728745982734509872340985729384750928734590827098752938723;
99999999; 99999999;
Each new array stops when it hits a ";'. The white spaces and endlines are confusing me too. Any help would be appreciated thank you.
You will want to use
bigint& array
to take the value by reference (or you couldn't possibly insert the digits read into it).
Also, you will want to use
char ch;
in >> ch;
instead of in << get() (which doesn't compile). Better yet, add error handling:
if (!(in >> ch))
{
// we're in trouble (in.rdstate(), in.eof(), in.fail() or in.bad() to know more)
}
If you wanted to use in.get(), you should be prepared to skip your own whitespace (including newlines). I'd prefer std::istream_iterator here, because it will automatically do so (if the std::ios::skipws flag is in effect, which it is, by default).
So here's a simplist approach (that mostly assumes input data is valid and whitespace ignorable):
#include <vector>
#include <istream>
#include <iterator>
struct bigint
{
std::vector<char> v; // or whatever representation you use (binary? bcd?)
};
std::istream& operator>>(std::istream& in, bigint& array)
{
for (std::istream_iterator<char> f(in), l; f != l; ++f) {
if (*f>='0' && *f<='9')
array.v.push_back(*f - '0');
else if (*f==';')
break;
else
throw "invalid input";
}
return in;
}
#include <iostream>
#include <sstream>
int main()
{
std::istringstream iss(
"10000000000000000000000000000000000345;\n"
"299793000000\n"
"00000000000000000000067;\n"
"4208574289572473098273498723475;\n"
"28375039287459832728745982734509872340985729384750928734590827098752938723;\n"
"99999999; 99999999;\n");
bigint value;
while (value.v.clear(), iss >> value)
std::cout << "read " << value.v.size() << " digits\n";
}
See it Live on Coliru
There's quite a lot of confusions here. I'll just list some points, but you have a way to go even if you fix these things.
What exactly are you reading? You say you are reading an array of numbers, but your code says this
std::istream& operator>>(std::istream& in, bigint array){
I might be wrong but bigint sounds like a single number to me. I would expect something like this
std::istream& operator>>(std::istream& in, std::vector<bigint>& array){
Which brings me to the second point, operator>> is expected to modify it's second argument, which means it cannot be passed by value, you must use a reference. In other words this is wrong
std::istream& operator>>(std::istream& in, X x){
but this is OK
std::istream& operator>>(std::istream& in, X& x){
You are trying to read an array of bigints, so you need a loop (you have that) and each time round the loop you will read one bigint. So you need a way to read one bigint, do you have that? There nothing in your question or your code that indicates you have the ability to read a bigint, but it's obviously crucial that you do. So if you do not have any code yet to read a bigint, you can forget about this whole exercise until you have that code, so work on that first. When you can read one bigint, only then should you come back to the problem of reading an array of bigints.
The other tricky part is the stopping condition, you stop when you read a semi-colon (possibly preceded by whitespace). So you need a way to read the next non-space character, and crucially you need a way to unread it if it turns out not to be a semicolon. So you need something like this
if (!(in >> ch) || ch == ';')
{
// quit, either no more input, or the next char is a semicolon
break;
}
in.putback(ch); // unread the last char read
// read the next bigint
Hope this helps.

Overloaded input operator failing automated simple input test

So I'm failing a simple input test for one of assignment questions. I'm to parse two integers separated by a white space. The two integers are used in the private members num and denom of the Rationalnumber type I have defined as a class. Is there something obviously unconventional I am using in or missing from this code? This code works for all my tests.
std::istream &operator>>( std::istream &is, Rationalnumber &r ) {
Rationalnumber::in++; // increment counter
// get the num
string n;
getline(cin,n,' ');
stringstream ssnum(n);
ssnum >> r.num;
// get the denom
string d;
getline(cin,d,'\n');
stringstream ssdenom(d);
ssdenom >> r.denom;
return is;
}
Your code fails in, at least, two obvious ways:
If a different whitespace than space is used, e.g., '\t', it isn't recognized by your code.
The input operator doesn't indicate failure when it is given invalid inputs, e.g., when the input is "a b" rather than numbers.
Conventionally, when input fails, the valuevread remains unchanged. This is also not true for your implementation. To fix things up the code can actually be simplified and made a lot fadter in the process. As this is clearly a homework assignment I don't think it is appropriate to provide the code, though.
This code passes the test!:
std::istream &operator>>( std::istream &is, Rationalnumber &r ) {
Rationalnumber::in++; // increment counter
int in;
is >> in;
r.numerator(in);
is >> in;
r.denominator(in);
return is;
}

Override >> operator like int

this is part of a homework assignment. I don't want an answer just help. I have to make a class called MyInt that can store any sized positive integer. I can only use cstring cctype iomanip and iostream libraries. I really don't understand even where to begin on this.
6) Create an overload of the extraction operator >> for reading integers from an input stream. This operator should ignore any leading white space before the number, then read consecutive digits until a non-digit is encountered (this is the same way that >> for a normal int works, so we want to make ours work the same way). This operator should only extract and store the digits in the object. The "first non-digit" encountered after the number may be part of the next input, so should not be extracted. You may assume that the first non-whitespace character in the input will be a digit. i.e. you do not have to error check for entry of an inappropriate type (like a letter) when you have asked for a number.
Example: Suppose the following code is executed, and the input typed is " 12345 7894H".
MyInt x, y;
char ch;
cin >> x >> y >> ch;
The value of x should now be 12345, the value of y should be 7894 and the value of ch should be 'H'.
The last state of my code is as follows:
istream& operator>>(istream& s, MyInt& N){
N.Resize(5);
N.currentSize=1;
char c;
int i = 0;
s >> c;
N.DigitArray[i++] = C2I(c);
N.currentSize++;
c = s.peek();
while(C2I(c) != -1){
s >> c;
if(N.currentSize >= N.maxSize)
N.Resize(N.maxSize + 5);
N.DigitArray[i] = C2I(c);
i++;
N.currentSize++;
}
}
It almost works! Now it grabs the right number but it doesn't end when I hit enter, I have to enter a letter for it to end.
You can create an operator>> overload for your class this way (as a free function, not inside the class):
std::istream& operator>>(std::istream& lhs, MyInt& rhs) {
// read from lhs into rhs
// then return lhs to allow chaining
return lhs;
}
You can use the members peek and read of istream to read in characters, and isspace to test if a character is a space, and isdigit to check if a character is a number (isspace and isdigit are in the <cctype> header).
First of all, your operator>> should be concerned only with extracting the sequence of chars from the stream and knowing when to stop based on your rules for that. Then, it should defer to a constructor of myInt to actually ingest that string. After all, that class will probably want to expose constructors like:
myInt bigone ("123456123451234123121");
for more general-purpose use, right? And, functions should have a single responsibility.
So your general form will be:
istream& operator>> (istream& is, myInt x)
{
string s = extract_digits_from_stream(is);
x = myInt(s);
return is; // chaining
}
Now how do you extract just digits from a stream and stop at a non-digit? Well, the peek function comes to mind, as does unget. I'd look at source code for the extraction operator for regular integers and see what it does.