Assignment:
Read in info from text file (done)
Retrieve only parts of text file using substr method (done)
Store info into instance variables (need help)
Here is the code I am having trouble with:
string* lati;
lati = new string(data.substr(0, data.find_first_of(",")));
double* latDub;
latDub = new double(atof((char *)lati));
this->latitude = *latDub;
I need to store the latitude into the instance variable latitude.
The variable data is the read-in text file.
this->latitude is declared as a double.
I have tested and the variable lati is the correct value, but once I try to convert it into a double the value changes to 0 for some reason. I am specifically supposed to use the atof method when converting!
(char *)lati doesn't do what you think it does. What you're clearly trying to do there is get the char sequence associated with lati, but what you're actually doing is just squeezing a string* into a char* which is all kinds of bad.
There's a member function on std::string that will give you exactly what you want. You should review the documentation for string, and replace (char *)lati with a call to that function.
Why your code compiles, but gives meaningless results has already been explained by adpalumbo. There are two fundamental problems in your code leading to that error, on which I want to expand here.
One is that you use a C-style cast: (T)obj. Basically, that just tells the compiler to shut up, you know what you are doing. That is rarely ever a good idea, because when you do know what you are doing, you can usually do without such casts.
The other one is that you are using objects allocated dynamically on the heap. In C++, objects should be created on the stack, unless you have very good reasons for using dynamic objects. And dynamic objects are usually hidden inside objects on the stack. So your code should read like this:
string lati(data.substr(0, data.find_first_of(",")));
double latDub = /* somehow create double from lati */;
this->latitude = latDub;
Of course, latDub is completely unnecessary, you could just as well write to this->latitude directly.
Now, the common way to convert a string into some other type would be streaming it through a string stream. Removing the unnecessary variables you introduced, your code would then look like this:
std::istringstream iss(data.substr(0, data.find_first_of(",")));
if( !iss >> this->latitude ) throw "Dude, you need error handling here!";
Usually you want to pack that conversion from a string into a utility function which you could reuse throughout your code:
inline double convert3double(const std::string& str)
{
std::istringstream iss(str);
double result;
if( !iss >> result )
throw std::exception("Dang!");
return result;
}
However, since the very same algorithm can be used for all types (for which operator>> is overloaded meaningfully with an input stream as the left operand), just make this a template:
template< typename T >
inline T convert3double(const std::string& str)
{
std::istringstream iss(str);
T result; // presumes default constructor
if( !iss >> result ) // presumes operator>>
throw std::exception("Dang!");
return result;
}
Related
I am working on my assignment and need help in completing the following function. I have been provided with the following signature:
void merge(const std::vector<istream>& inputStreams, ostream& o);
The function is supposed to take k integer streams as input and sort them and store the result in an ostream object.
I have completed the function definition but the problem is I cannot test the function by providing it the input (ie: vector of istream objects). If I try to pass the function a vector of istream objects, the compiler throws too many errors for me to debug.
Here is the function definition:
void merge( vector<istream>& inputStreams, ostream& o){
vector<long long int> input_vec;
long long int input_vec_size = inputStreams.size();
for(int i=0; i<input_vec_size;i++)
{
long long int temp;
while(inputStreams[i]>>temp)
{
input_vec.push_back(temp);
}
}
sort(input_vec.begin(),input_vec.end());
for(int i=0;i<input_vec.size();i++)
{
o<<input_vec[i];
}
}
And to pass a vector of istream objects i did the following:
int main()
{
//ifstream a1,a2,a3,a4;
filebuf fb1,fb2,fb3;
fb1.open("fb1.txt",ios::in);
fb2.open("fb2.txt",ios::in);
fb3.open("fb3.txt",ios::out);
istream a1(&fb1);
istream a2(&fb2);
ostream out(&fb3);
vector<istream> inp;
inp.push_back(a1);
inp.push_back(a2);
merge(inp,out);
}
can anyone help me?
For starters, it's fairly unusual to see the type istream being used as the actual type of an object. The reason for this is that istream is meant to be used as a base class, and those base classes are what more often get used. For example, you'll see variables of type istringstream or type ifstream much more regularly than just plain old istream. It's not wrong, per se, to have a variable that's an honest-to-goodness istream, but it is unusual.
Typically, if you wanted to work with a function that manipulated some sort of input stream, you'd structure it so that it either took in a reference to the istream or a pointer to the istream. That's the general C++ way of handling polymorphic types.
In your case, the fact that you're trying to use a vector<istream>, regardless of whether the code will compile or not, should therefore make you pause a minute to think about whether you're doing the right thing. It's entirely possible that, yes, you indeed do have a bunch of istream objects, and those objects aren't istringstreams or ifstreams. But more probably, what you were aiming to do here was say "I take in some list of input streams, and I don't really care what kind of input streams they are as long as they inherit from istream."
If that's what you're hoping to do, there are several ways you could address this. Perhaps the easiest is to change vector<istream> to vector<istream *> (or perhaps vector<shared_ptr<istream>>, depending on context). That would mean "I'd like to take as input a list of streams, and since I can't say for certain what specific type each of those streams will be, I'll just have the client give me pointers to each of them." That's going to require you to make some changes to your code so that, as you access the elements of the vector, you treat them as pointers rather than as actual, honest-to-goodness istream objects. For example, the line
while (inputStreams[i] >> temp) { ... }
might need to get rewritten as
while (*inputstreams[i] >> temp) { ... }
to explicitly dereference the pointer.
The other question you asked was how to test this code at all, and that's a separate step. Remember, it's fairly unusual to create objects of type istream, so you'd probably want to make either objects of type istringstream or ifstream. Here's an example of how you might make a few streams and then pass them into your function:
istringstream stream1("137 2718");
istringstream stream2("27 182 818");
istringstream stream3("3 14 15 92 653");
merge({ &stream1, &stream2, &stream3 }, cout);
Here, rather than declaring a local variable of type vector<istream *>, we just use a brace-initializer to say "please make me a vector out of these pointers."
From the sample code you've provided it looks like you want to read data from a bunch of files. Here's how you might do that. Rather than making filebuf objects and wrapping them in istreams, which is legal but fairly uncommon, we'll just use ifstream:
ifstream stream1("fb1.txt");
ifstream stream2("fb2.txt");
ifstream stream3("fb3.txt");
vector<istream *> inputs;
inputs.push_back(&stream1);
inputs.push_back(&stream2);
inputs.push_back(&stream3);
merge(inputs, cout);
Hope this helps!
istream is not copyable or moveable, hence you can't make a vector of istreams. Try using std::vector <std::istream *> instead (and modify your code accordingly).
Live demo: https://wandbox.org/permlink/20I2VQqsRI8ofaxP
I'm quite new to reading and writing to files. But basically, I have an assignment where part of it requires me to determine whether a line from a file is an integer or double.
This is the part of the assignment I need help on:
Open the text file and read it's contents one line at a time. Determine if the line read from the file is a double or an integer. You are to place the integers in a vector called iNumbers and the doubles in a vector called dNumbers. The vector iNumbers should hold pointers to the Integer class and dNumbers should hold pointers to the Double class. When you add a value to one of the vectors you should use new and call the constructor that takes a string. For example:
iNumbers.push_back(new Integer("12.23"));
Sample of the file:
12
20
80.5
99.345
70
From what I understand, I think I write code that will read the lines in the file and if they have a "." then those will be doubles, but I am not sure as how to start with that.
Any help as to how I should get started would be very appreciated and thanks in advance.
Beware, in C++ (and not only C++), 1e4 is also double (with value of 10000).
If this is not allowed in the task (and finding . in the number is sufficent), then I would create std::ifstream for the file, read from it using std::getline into a std::string s, then in the string I would s.find('.') and if it is to be found (the result of find != s.npos, pass it into dNumbers as new Double(s), if such constructor exists for your class.
To be pedantic, in the general case the best way to figure out whether or not a string is an integer is to try to convert it to an integer without any error or leftover characters.
Here is a very simple method to do just that (for any type):
template <typename T>
T string_to( const std::string& s )
{
T value;
std::istringstream ss( s );
ss >> value >> std::ws;
if (!ss.eof()) throw std::invalid_argument("T string_to()");
return value;
}
You can now test for any standard integer vs double:
int n;
double d;
try {
n = string_to <int> ("12.3");
// it's an int
}
catch (...) {
try {
n = string_to <double> ("12.3");
// it's a double
}
catch (...) {
// it is neither integer nor double
}
}
If desired, you can specialize the int types to handle things like "0xF3" by unsetting the basefield: ss.unsetf(std::ios::basefield);.
Hope this helps.
Here is a straightforward way you could accomplish this task:
read from the stream using std::getline to a std::string
use std::stof and std::stoi with this string as the parameter to determine the type - if they throw std::invalid_argument or std::out_of_range, conversion could not be done
push_back to one of the arrays, depending on which type was
Glad to see that we are in the same class...
There is more to the assignment that you left out. We have our double.cpp and our integer.cpp files that include constructors that take a string as a parameter if you did your program correctly, that is. So the iNumbers.push_back(new Integer("12.23")); is basically saying "iNumbers" - the name of the vector, ".push_back" - the function that puts the string value onto the stack, "new Integer" - allocating memory for the type Integer, and "12.23" - the actually double value that was used as an example in the form of a string taken from the .txt file.
What you need to do is look through his lecture slides that include the content about I/O files and you should be fine. We even did an example in class.
As far as your basic question about integer and double types, its very simple and I have no idea how you got through the past assignments without knowing the difference, an integer does not have a decimal point and a double does. Now there may be a more complicated definition for an integer and a double type but for Stevenson's class this is the only thing you should think about. Forget what you learned in your math class about integers. The definition is not the same for this class.
Best of luck...
See you in class
-C
When I attempt to run this code it crashes. There are no error messages. When the program compiles and runs, it just displays the windows 7 message, "this program has stopped working.":
void readGameFile(string ** entries, int * num_entries, string ** story, int * num_lines)
{
ifstream madlib("madlibs1.txt");
string line;
getline(madlib, line);
*num_entries=stoi(line);
*entries=new string [*num_entries];
for (int i=0; i<*num_entries; i++)
{
getline(madlib,*entries[i]);
}
I did a few tests, and it seems to assign entries[0] a value, and then crashes when attempting to assign entries[1] a value. I am forced to use this function name, with those function parameters and parameter types specifically. I also may not use malloc, vector or other answers I've seen.
I think the issue is one of precedence: you almost certainly
want:
getline( madlib, (*entries)[i]) );
Otherwise, you're indexing from the string**, then
dereferencing: *(entries[i]).
You also want to check the results of getline, possibly in the
loop:
for ( int i = 0; madlib && i != *num_entries; ++ i )...
as well as before the std::stoi.
And finally: I don't know why you are forced to use this
function signature. It is horrible C++, and you should never
write anything like this. Logically, std::vector<string>
would be a better solution, but even without it: your function
has 4 out parameters. This would be better handled by returning
a struct. And failing that, out parameters in C++ are
usually implemented by non-const reference, not by a pointer.
While there are arguments for using the pointer in some cases,
when it results in a pointer to a pointer, it's evil. If
nothing else:
bool // Because we have to indicate whether it succeed or failed
readGameFile( std::string* &entries, int &num_entries, std::string* &story, int &num_lines )
// ...
(This actually looks more like it should be constructor,
however, of a class with two data elements, entries and
story.)
have a little problem here:
int IntegerTransformer::transformFrom(std::string string){
stream->clear();
std::cout<<string<<std::endl;;
(*stream)<<string;
int i;
(*stream)>>i;
std::cout<<i<<std::endl;
return i;
}
I by calling this function with the string "67" (other values dont work too) i get this output:
67
6767
Did you notice there are two std::cout in the function itself?
Beside that also add this:
stream->str(""); //This ensures that the stream is empty before you use it.
(*stream)<<string;
By the way, why don't you use boost::lexical_cast?
int IntegerTransformer::transformFrom(std::string s){
return boost::lexical_cast<int>(s);
}
stream->clear();
This does not "empty out" the stringstream's contents. It resets the error flags that get set when reading from the stream fails (e.g. because the text is not in the right format to read an integer).
The simplest way to deal with this is to just create a new, locally scoped stringstream:
int IntegerTransformer::transformFrom(std::string string){
std::stringstream parser(string);
int i;
parser>>i;
return i;
}
Notice how you also no longer have to mess around with pointers (and, I'm assuming, dynamic allocation), and that you can just use the constructor to set the initial value.
Having streams as data members of a class is a bad idea in general. They really aren't meant for that kind of use.
The next easiest solution is to use the member function that's actually intended for the job, .str(), as shown by Nawaz.
As also mentioned by Nawaz, scrapping the whole thing and just using boost::lexical_cast is probably a better idea anyway. Don't reinvent the wheel.
In java, if I wanted to create some application which could receive both doubles and strings as appropriate input, I would probably do the following:
String input = getInput();//
try {
double foo = Double.valueOf(input);
//Do stuff with foo here
} catch (NumberFormatException e) {
//Do other validation with input
}
How would you go about doing that in c++? atof() returns 0.0 for invalid input, but how would you differentiate that from a valid double of "0.0"? As an aside, I can only include <iostream>, <string>, <cstdlib>, and <cassert> in this project. I'm assuming I need to use cin in some way, but how can you grab the original input after cin fails to parse some string as a double?
Edit: I could probably use the following, but as I said before, I'm not allowed to import <sstream> on this assignment for some reason
string input;
getline(cin, input);
double x;
istringstream foo(input);
foo >> x
if(cin){
//do manipulations with x
}
else{
//since it's not a number, check if input is a valid command etc..
}
Exceptions should be reserved for exceptional situations. While you certainly can abuse them like this, it's a lousy idea -- clearly you're pretty much expecting things other than doubles, so treating it as an exception doesn't make any real sense.
The only real question is the exact circumstance under which you want the input treated as a string. Just for example, if the input string was something like "1.23e2 non-numeric data", do you want to just use the "1.23e2" as a number, or do you want to treat the whole thing as a string?
Either way, you'd want to us strtod for the conversion -- the difference is only how you react to what it returns. In particular, strtod takes two parameters instead of just one like atof does. The second parameter is a pointer to pointer to char. Assuming you pass a non-NULL pointer, strtod will set it to point at the last character in the input string that it successfully converted. If it's pointing to the beginning of the input string, nothing was converted. If it's pointing to the end, everything was converted. If it's somewhere in between, part of the string converted, and part didn't.
For the moment, I'm going to assume that you want a double value holding whatever number could be converted at the beginning of the string, and whatever couldn't be converted treated as a string:
#include <stdlib.h>
#include <stdio.h>
int main() {
char input[] = "12.34 non-numeric data";
char *string;
double value = strtod(input, &string);
printf("Number: %f\tstring: %s\n", value, string);
return 0;
}
C++ streams associate the good, bad and fail state flags. These are stored in ios_base::goodbit, ios_base::badbit and ios_base::failbit respectively, but are commonly accessed through ios::good(), ios::bad() and ios::fail(). There's also ios_base::eofbit and ios::eof() but let's ignore that for the moment.
If parsing fails then the bad bit raises. Also, stream objects are convertible to a boolean-compatible type. If a stream is in a good state, then the statement
if( stream )
evaluates stream as true. Otherwise, it evaluates it as false. With this at hand, grabbing a value from standard input boils down to this:
#include <iostream>
// ...
double d = 0;
if ( std::cin >> d ) {
// input is a double. handle that here.
} else {
// input isn't a double. handle that here.
}
try "strtod" in stdlib.h
The C++ standard library seems to avoid exceptions for a lot of things that people might expect them, and this may not be the answer that you want to hear but parsing doubles isn't exactly rocket science so maybe it'd be ok to do it "by hand"?
One note if you do this, you'll probably want to collect it into an integer and then convert to a double and divide by 10^number_of_digits_after_decimal_point.
You could have a look at boost::lexical_cast, which would allow you to write pretty much the equivalent of the Java code:
string input;
getline(cin, input);
try {
double x = boost::lexical_cast<double>(input);
//Do manipulations with x
} catch (boost::bad_lexical_cast &) {
//Do other validation with input
}