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.
Related
I have a custom String class that contains a char array, and I need to overload the >> operator for this class. For the life of me I can't figure out how to do two things.
1 - Read the user input until a ; is reached
2 - Include whitespace from user input
I cannot use namespace or c++'s built-in string. Unfortunately that rules out the use of getline and any of the convenient find functions (I think it does, anyway?). Some things I have tried:
std::istream& operator >> (std::istream& output, String& input) {
output >> input.str;
return output;}
This works but only up until the first whitespace, after which point it stops reading the user input.
std::istream& operator >> (std::istream& output, String& input) {
while (output != ';') {
output >> input.str;
}
return output;}
An istream I guess isn't equivalent to the user input so you cannot compare it to a char like I tried to in my while loop.
So, my questions are, how does one read input until a specified character is encountered, and how does one include all whitespace when using >> ?
The global operator>> for string/character input stops reading when it encounters whitespace, so it is not worthwhile to implement your custom operator>> in terms of the global operator>>.
You ruled out use of std::getline(), but you can use std::istream::getline() instead. Like std::getline(), it also has an optional delim parameter (the default is '\n'), and will read characters - including whitespace - until the delimiter or EOF is reached.
std::istream& operator >> (std::istream& input, String& output)
{
return input.getline(output.str, yourmaxstrsize, ';');
}
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.
When using stdio.h, I can easily read certain kinds of formatted input like this:
FILE* fin = fopen(...);
fscanf(fin, "x = %d, y = %d", &x, &y);
The great thing about this is that I don't really have to worry about how many spaces there are between the character 'x' and the following '=', and other minor details.
In C++ it appears to me as though,
ifstream fin(...);
string s;
fin >> s;
may result in s being "x" or "x=", or even "x=12" depending on the spacing of the input.
Is there a convenient way to get behavior similar to scanf/fscanf using iostream/fstream?
This is actually surprisingly easy, given a prerequisite. I have these three functions that I stick in a header somewhere. These allow you to stream in character literals, and string literals. I've never quite understood why these aren't standard.
#include <iostream>
//These are handy bits that go in a header somewhere
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e(&sliteral)[N]) {
e buffer[N-1] = {}; //get buffer
in >> buffer[0]; //skips whitespace
if (N>2)
in.read(buffer+1, N-2); //read the rest
if (strncmp(buffer, sliteral, N-1)) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
template<class e, class t>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, const e& cliteral) {
e buffer(0); //get buffer
in >> buffer; //read data
if (buffer != cliteral) //if it failed
in.setstate(std::ios::failbit); //set the state
return in;
}
//redirect mutable char arrays to their normal function
template<class e, class t, int N>
std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, e(&carray)[N]) {
return std::operator>>(in, carray);
}
Given those, the rest is easy:
in>>'x'>>'='>>data.first>>','>>'y'>>'='>>data.second;
Proof here
For more complex situations, you probably want to use std::regex or boost::regex, or maybe a real lexer/parser.
like you specify format in fscanf/scanf using %xx you can specify format using stream manipulators as detailed in this tutorial -
http://www.tenouk.com/Module18.html
very comprehensive. stream manipulator is near the bottom of the page.
The short answer is "no".
A slightly longer answer is "You can probably build something that does that". For example, you could read the line of text, and then use a suitable "replace spaces with empty string" type function. Or perhaps something like this:
int x, y;
string s;
getline(cin, s, '=');
cin.get(); // Get rid of =
cin >> x;
getline(cin, s, '=');
cin >> y;
Alternatively, using cin.ignore to skip things (since the string reading is not really useful uness you want to know that 'x' and 'y' are actually 'x' and 'y'=:
int x, y;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> x;
cin.ignore(1000000, '='); // Skip up to a '='
cin >> y;
This will "break" if someone enteres over 100k characters without an = sign, and there is need for error checking to see that "garbage" isn't coming in - just like fscanf does. if (cin >> x) would take care of the "detect that something went wrong, but you need to then do something sensible with the fact that it's gone wrong, which I'm not sure of right now...
Of course, since C++ supports (nearly) all of C, you can of course always use whatever members of the <cstdio> functions that you would like to use, as well. [And in at least some cases, they are actually a bit better].
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;
}
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.