Create class instances from text file stream.

  • (2 Pages)
  • +
  • 1
  • 2

21 Replies - 2101 Views - Last Post: 16 November 2014 - 07:57 PM Rate Topic: -----

#1 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Create class instances from text file stream.

Posted 10 November 2014 - 02:35 PM

Hey guys!

I am trying to do some exercises but am struggling at the moment. The first task was to create a class (Planet), then allow the user to edit their entry or view it.

The second one is to create class instances from a text file. The file contains a new planet on each line in the form: 'id x y z' where x/y/z are its coordinates. As the file can have more then one lines, it has to dynamically create an undefined amount of class instances.

To do this I used 'new' and it works ok - it prints each one out to the screen as you go so you can see it working. However... I'm trying to get into good habits here and am encapsulating the class which is where I am getting stuck. I can read from the class but cannot put the values from the file into the class.. ..using the member functions I have created anyway.

Any help would be great :)/>/> I have a few more questions but would like to get one out of the way at a time.

My code so far is:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Planet
{
private:
    int id=0;
    float x_coord=0.0, y_coord=0.0, z_coord=0.0;

public:
    int GetID(){return id;}
    float GetX(){return x_coord;}
    float GetY(){return y_coord;}
    float GetZ(){return z_coord;}
    void SetID(int identity){id=identity;}
    void SetX(float x){x_coord=x;}
    void SetY(float y){y_coord=y;}
    void SetZ(float z){z_coord=z;}
};



void set_planet_properties (Planet& pone);
void report_planet_properties (Planet& pone);



Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    cout << "\n" << endl;

    string line;
    while ( getline (planetlist,line) )
    {
        planetlist >> p->SetID() >> p->SetX() >> p->SetY() >> p->SetZ();
        cout << "Planet ID (" << p->GetID() << ") has landing site coordinates: ( " << p->GetX() << " , " << p->GetY() << " , " << p->GetZ() << " )" << endl;
    }

    return (p);
}



int main()
{
    int choice,tempid;
    float tempx,tempy,tempz;
    Planet pone;

    ifstream planetlist ("planets.txt");
    generate_planet(planetlist);

    return 0;
}



If I change the SetID etc to just p->id, p->x_coord etc it works fine. But I'd rather find a way to do it that keeps the encapsulation. Using p->z_coord etc requires that you change the class variables from private to public.

The question I have been given is this:
Define and implement a function, generate planet, that takes a stream argument that has
already been connected to a file (i.e. the argument is istream& fin). The function must
create a new instance of planet using new and read its details from the next line in the
file.
Each line of the file is in the format id x y z.
The function must return the newly created planet.

- encase you notice something or I'm misunderstanding the wording!

Also, how would you go about 'viewing' one specific class instance once they've been created? So say the file had 5 lines, line three was '4 6 2 6'. How would I go about viewing that planet afterwards? I don't think thats required but... I'm just wondering :) Although I'm also wondering, are we actually creating a new class instance for each line here? Or just destroying the previous one? I'm guessing 'new' means we're creating a new one each time but.. I'm 'new' to this. (pun intended).

Thanks!

Is This A Good Question/Topic? 0
  • +

Replies To: Create class instances from text file stream.

#2 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 10 November 2014 - 02:51 PM

Quote

encase you notice something or I'm misunderstanding the wording!

Look closely at this part of your instructions.

Quote

The function must create a new instance of planet using new and read its details from the next line in the file.


After re-reading your instructions please explain the purpose of the while loop.

Now look at this:

Quote

Each line of the file is in the format id x y z.

Why are you using getline() in that loop? The getline() function reads an entire line. So the next line reads the next line, which means you effectively skip a line.

Lastly you return the pointer to this newly allocated pointer but your calling function isn't doing anything with this return value, so you have a memory leak. You need to assign the return value to some variable.

Jim
Was This Post Helpful? 0
  • +
  • -

#3 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 10 November 2014 - 03:28 PM

The idea of the while loop was to keep creating planet instances until you reach the end of the file. So it just loops around creating planets until the end of the file (which is what the conditions are supposed to detect).

I was wondering why it was skipping out the first line, couldn't put my finger on it so just ignored it for now. Thanks for pointing out the culprit. I was looking at examples online on how to read from text files and trying to break them down into the bits I needed, so some bits may well be wrong. Should I just replace getline() with line then?

As for returning the pointer, I only did that as the instructions ask for it. Otherwise I can't see any reason to return anything? Since we would only need to return something if we wanted to do something afterwards - which is where my 'view the planets' question came from.

I may be going about this the wrong way. Should I be having the loop within main? Calling the function once for each new line, returning the pointer and then the loop can display the planet using the returned pointer?

Sorry if this all seems rather simple, I like to understand what I'm doing rather than just do it.
Thanks for taking the time!
Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 10 November 2014 - 09:50 PM

Quote

The idea of the while loop was to keep creating planet instances until you reach the end of the file. So it just loops around creating planets until the end of the file (which is what the conditions are supposed to detect).

But that's not what your instructions are telling you to do.

Quote

Define and implement a function, generate planet, that takes a stream argument that has
already been connected to a file (i.e. the argument is istream& fin). The function must
create a new instance of planet using new and read its details from the next line in the
file.

This is telling you to create one instance of planet and return this one instance to the calling function. The calling function is where the loop will be.

Quote

Thanks for pointing out the culprit. I was looking at examples online on how to read from text files and trying to break them down into the bits I needed, so some bits may well be wrong. Should I just replace getline() with line then?


You should be using the extraction operator to extract each bit of the information, not getline().

Quote

As for returning the pointer, I only did that as the instructions ask for it. Otherwise I can't see any reason to return anything? Since we would only need to return something if we wanted to do something afterwards - which is where my 'view the planets' question came from.

You are returning the new pointer to the calling function, where it should be assigned to a variable, probably a vector or array of planet pointers. My guess would be that there are more directions for this assignment telling you what to do with this pointer in the calling function.

Quote

I may be going about this the wrong way. Should I be having the loop within main? Calling the function once for each new line, returning the pointer and then the loop can display the planet using the returned pointer?


This seems like a possibility, and since you are returning a "new" pointer you will need to "delete" the memory that has been allocated when you are finished with it. The only thing the function should be doing is creating the "new" instance of the class, reading the file and filling in this "new" class's information. Any further processing should be done through the calling function through that pointer you've returned.


Jim
Was This Post Helpful? 0
  • +
  • -

#5 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 11 November 2014 - 06:43 AM

Ok thankyou for the help. I have played around with it and managed to get this (Which works!)

My other question initially was how to change the input into the class, I've added some brackets with my questions (All caps) in the code block below as its probably easier to see that way.

The array I'm using is set to 10 however I should probably have it scale to the size of the file (how many lines). I tried doing this by creating another while loop that looped around counting the lines and then created the array, but the program just went into an infinite loop. Is it something to do with clearing the memory that you mentioned?

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Planet
{
public: (I WANT THIS TO BE PRIVATE THOUGH)
    int id=0;
    float x_coord=0.0, y_coord=0.0, z_coord=0.0;

public:
    int GetID(){return id;}
    float GetX(){return x_coord;}
    float GetY(){return y_coord;}
    float GetZ(){return z_coord;}
    void SetID(int identity){id=identity;}
    void SetX(float x){x_coord=x;}
    void SetY(float y){y_coord=y;}
    void SetZ(float z){z_coord=z;}
};


void set_planet_properties (Planet& pone);
void report_planet_properties (Planet& pone);


Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    planetlist >> p->id >> p->x_coord >> p->y_coord >> p->z_coord; (WHAT DO I DO HERE IN ORDER TO BE ABLE TO USE THE MEMBER FUNCTIONS? RATHER THAT DIRECTLY EDITING THE VARIABLES? p->SetX() DOES NOT WORK)

    return (p);
}


int main()
{
    int i;
    Planet *PlanetArray[10];

    string line;
    ifstream planetlist ("planets.txt");

    if(planetlist)
    {
        while(!planetlist.eof())
        {
            PlanetArray[i]=generate_planet(planetlist);
            cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;
        }
    }
    else
    {
        cout << "\n\n\n\tFile failed to open! Maybe it does not exist? (planets.txt)\n" << endl;
    }

    return 0;
}


Was This Post Helpful? 0
  • +
  • -

#6 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 11 November 2014 - 06:49 AM

Is there a way to edit your posts? I can't seem to find it.

I forgot to include the 'i++;' on line 53.

Also, I can view the different planets correctly - tested it by sticking
    cout << PlanetArray[3]->GetX() << " " << PlanetArray[4]->GetY() << endl;
into main beneath the loop and its displaying the correct values.
Was This Post Helpful? 0
  • +
  • -

#7 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 11 November 2014 - 07:20 AM

Why doesn't your setter work? They seem to work for me.

Quote

The array I'm using is set to 10 however I should probably have it scale to the size of the file (how many lines). I tried doing this by creating another while loop that looped around counting the lines and then created the array, but the program just went into an infinite loop. Is it something to do with clearing the memory that you mentioned?


For all of your present questions I need to see your code. Without seeing your code I can only guess as to why your having problems. So please post your code where you're trying to use your setters, and where your trying to determine the "size" of the file and then allocate the required memory.

It would also be helpful to see the actual assignment. This project could be easily accomplished without the use of manual memory management with the use of a single dimensional std::vector.




View PostSyzygy, on 11 November 2014 - 07:49 AM, said:

Is there a way to edit your posts? I can't seem to find it.

I forgot to include the 'i++;' on line 53.

Also, I can view the different planets correctly - tested it by sticking
    cout << PlanetArray[3]->GetX() << " " << PlanetArray[4]->GetY() << endl;
into main beneath the loop and its displaying the correct values.


First in order to edit your posts you need to have a certain number of posts under your belt. I believe you may now be able to edit your posts for a short time.

Don't forget to also initialize i before you try to use it.

Jim

This post has been edited by jimblumberg: 11 November 2014 - 07:20 AM

Was This Post Helpful? 0
  • +
  • -

#8 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 11 November 2014 - 08:11 AM

They work in the code I posted, but its when I try to change it to use the encapsulation properly that it breaks.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Planet
{
private:
    int id=0;
    float x_coord=0.0, y_coord=0.0, z_coord=0.0;

public:
    int GetID(){return id;}
    float GetX(){return x_coord;}
    float GetY(){return y_coord;}
    float GetZ(){return z_coord;}
    void SetID(int identity){id=identity;}
    void SetX(float x){x_coord=x;}
    void SetY(float y){y_coord=y;}
    void SetZ(float z){z_coord=z;}
};


void set_planet_properties (Planet& pone);
void report_planet_properties (Planet& pone);


Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    planetlist >> p->SetID() >> p->SetX() >> p->SetY()) >> p->SetZ();
    //This is the error

    return (p);
}


int main()
{
    int i=1;
    //Planet *PlanetArray[10];

    string line;
    ifstream planetlist ("planets.txt");

    if(planetlist)
    {
        while(!planetlist.eof())
        {
            i++;
        }
        Planet *PlanetArray[i];
        i=1;
        while(!planetlist.eof())
        {
            PlanetArray[i]=generate_planet(planetlist);
            cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;
            i++;
        }
    }
    else
    {
        cout << "\n\n\n\tFile failed to open! Maybe it does not exist? (planets.txt)\n" << endl;
    }

    cout << PlanetArray[3]->GetX() << " " << PlanetArray[4]->GetY() << endl;

    return 0;
}



The assignment is in 4 parts;

Quote

Part 1 (complete):

Define and implement a class planet to hold all their details. (x,y,z coordinates are to be
stored with float precision).
Define and implement a function called, report_planet_properties, that takes an argument
identifying a planet instance and reports its properties to the screen.
Define and implement a function, set_planet_properties, that takes an argument
identifying an existing plant instance and prompts the user through messages on the
screen to enter the planet’s id number and coordinates.
Some advice - well actually, more Good Practice. I really hope that you will go through
all of the tasks of this exercise and design and implement the Declarations and Interfaces
of all the objects and functions before you actually start thinking about the detail of their
implementation!


Part 2 (current)

Define and implement a function, generate planet, that takes a stream argument that has
already been connected to a file (i.e. the argument is istream& fin). The function must
create a new instance of planet using new and read its details from the next line in the
file.
Each line of the file is in the format id x y z.
The function must return the newly created planet.

I am planning ahead for part 3/4, hence the array. So they can select two planets by their ids and find the distance between the pair.

Part 3

Define and implement a function, called distance_between_planets that takes two
arguments identifying a pair of planets and returns the distance between them.


Part 4

Write a main program to do the following
1) Open a file called route.txt and connect it to the stream fin using
ifstream fin(“route.txt”);
The first line in the file contains the number of planets. Subsequent lines contain the id x
y z coordinates of the planets. Example for the two pictures shown in the introduction
above, the route files would be,

4
1 1.1 -0.7 0.9
2 9.2 8.0 0.1
3 11.7 -31.0 0.4
4 -0.9 -4.3 2.9

4
3 11.7 -31.0 0.4
2 9.2 8.0 0.1
1 1.1 -0.7 0.9
4 -0.9 -4.3 2.9

2) Define an array called the_planets of 10 planet pointers, i.e. use the line
planet* the_planets[10]; // Are you sure why the syntax is like this?
We will assume for the present that there are never more than 10 deliveries per route.

3) Each element of the array is to point to a particular planet, the details of which come
from the file. Therefore use your generate_planet function within a loop to achieve this,
maybe using the line.
the_planets [i]=generate_planet(fin);


Although... after reading through it again. I think I'm actually doing part 4 with the array? Part 2 is just asking for me to display the planets. Part 3 is asking for just two planets in the file and find the distance between them - no selection involved. Part 4 is asking for the array?

This post has been edited by jimblumberg: 11 November 2014 - 09:33 AM
Reason for edit:: Removed extra code tags.

Was This Post Helpful? 0
  • +
  • -

#9 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 11 November 2014 - 09:01 AM

I still can't edit, but I forget the end of part 4.. sorry!

End of 4:
4) Report the details of all the planets to the screen by using your
report_planet_properties function within a loop. Be careful that the_planets[i] is a
pointer to a planet34.
5) Finally, evaluate the total route length. (We will visit the planets in the order in which
they appear in the file).
Our Base – the_planets[0] – the_planets[1] --- the_planets[n-1] – our base
and print it on the screen. Be careful to deal with the start and end locations!
Testing: On Moodle there is a test file route.txt, the distance should evaluate to 133.43



I have finished part 3 now, the code is this: (4 just seems to be combining everything into one bigger program).

#include <iostream>
#include <fstream>
#include <string>
#include <math.h>

using namespace std;

class Planet
{
public:
    int id=0;
    float x_coord=0.0, y_coord=0.0, z_coord=0.0;

public:
    int GetID(){return id;}
    float GetX(){return x_coord;}
    float GetY(){return y_coord;}
    float GetZ(){return z_coord;}
    void SetID(int identity){id=identity;}
    void SetX(float x){x_coord=x;}
    void SetY(float y){y_coord=y;}
    void SetZ(float z){z_coord=z;}
};


void set_planet_properties (Planet& pone);
void report_planet_properties (Planet& pone);


float distance_between_planets (Planet& planet1, Planet& planet2)
{
    float x1=0.0,x2=0.0,y1=0.0,y2=0.0,z1=0.0,z2=0.0,distance=0.0;
    distance=sqrt(
    ((planet1.GetX()-planet2.GetX())*(planet1.GetX()-planet2.GetX()))+
    ((planet1.GetY()-planet2.GetY())*(planet1.GetY()-planet2.GetY()))+
    ((planet1.GetZ()-planet2.GetZ())*(planet1.GetZ()-planet2.GetZ())));




    return(distance);
}


Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    planetlist >> p->id >> p->x_coord >> p->y_coord >> p->z_coord;

    return (p);
}


int main()
{
    int i=1;
    Planet *PlanetArray[2];
    string line;
    ifstream planetlist ("planets.txt");

    cout << "\n\nDISTANCE BETWEEN TWO PLANETS FROM TEXT FILE\nM Harman - 4123498\n\n";

    if(planetlist)
    {
        while(!planetlist.eof())
        {
            PlanetArray[i]=generate_planet(planetlist);
            cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;
            i++;
        }
    }
    else
    {
        cout << "\n\n\n\tFile failed to open! Maybe it does not exist? (planets.txt)\n\n" << endl;
    }


    cout << "\n\nThe distance between the two planets is: " << distance_between_planets(*PlanetArray[1],*PlanetArray[2]) << " 'units of space distance'\n" << endl;



    return 0;
}


Was This Post Helpful? 0
  • +
  • -

#10 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 11 November 2014 - 10:01 AM

Quote

Although... after reading through it again. I think I'm actually doing part 4 with the array? Part 2 is just asking for me to display the planets. Part 3 is asking for just two planets in the file and find the distance between them - no selection involved. Part 4 is asking for the array?


I hope you have read all the instructions and implemented your code taking the following advice:

Quote

Some advice - well actually, more Good Practice. I really hope that you will go through
all of the tasks of this exercise and design and implement the Declarations and Interfaces
of all the objects and functions before you actually start thinking about the detail of their
implementation!


Now let's look a the code for main().

int main()
{
    int i=1;
    Planet *PlanetArray[2];
    string line;
    ifstream planetlist ("planets.txt");

    cout << "\n\nDISTANCE BETWEEN TWO PLANETS FROM TEXT FILE\nM Harman - 4123498\n\n";

    if(planetlist)
    {
        while(!planetlist.eof())
        {
            PlanetArray[i]=generate_planet(planetlist);
            cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;
            i++;
        }
    }
    else
    {
        cout << "\n\n\n\tFile failed to open! Maybe it does not exist? (planets.txt)\n\n" << endl;
    }

    cout << "\n\nThe distance between the two planets is: " << distance_between_planets(*PlanetArray[1],*PlanetArray[2]) << " 'units of space distance'\n" << endl;

    return 0;
}



The first thing I see wrong here is the first line inside of main(). Remember arrays in C/C++ start at zero not one.

Quote

I am planning ahead for part 3/4, hence the array. So they can select two planets by their ids and find the distance between the pair.

Are you sure? Does this Planet *PlanetArray[2]; match the instructions? Look at Part 4 of your instructions.

Quote

2) Define an array called the_planets of 10 planet pointers, i.e. use the line
planet* the_planets[10]; // Are you sure why the syntax is like this?
We will assume for the present that there are never more than 10 deliveries per route.


Also is that question: Are you sure why the syntax is like this? your question or is it part of the instructions>

Next let's look at this function:

Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    planetlist >> p->id >> p->x_coord >> p->y_coord >> p->z_coord;

    return (p);
}


Your class member functions should be private, so you should be using the setter functions to set the values. Something more like (please note the added error checking):
Planet* generate_planet (ifstream& planetlist)
{
   int id;
   float x_coord, y_coord, z_coord;
   // Create a Planet pointer set to nullptr in case read fails.
   Planet *planet = nullptr;
   
   planetlist >> id >> x_coord >> y_coord >> z_coord;
   if(planetlist)
   { // Only do this if the file read succeeded.
      planet = new Planet;
      planet->SetID(id)
      planet->SetX(x_coord);
      planet->SetY(y_coord);
      planet->SetZ(z_coord);
   }
   // Return the new planet if the read succeeded, a nullptr otherwise.
   return (planet);
}




And don't forget what you "new" you must "delete"!


Also in your last post, this: cout << "\n\nThe distance between the two planets is: " << distance_between_planets(*PlanetArray[1],*PlanetArray[2]) << " 'units of space distance'\n" << endl; should be in the if statement.

Jim

This post has been edited by jimblumberg: 11 November 2014 - 10:02 AM

Was This Post Helpful? 0
  • +
  • -

#11 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 11 November 2014 - 06:32 PM

I did plan it first. I find it makes it easier when you actually come to coding later on.

As for the arrays, I do know they start at 0 but I like to push it all forward one as its just nicer to see that Array[1] corresponds to item 1 etc. It does however leave Array[0] as.. nothing, so might cause some issues maybe? I'm guessing it would be ok if I set Array[0] to 0 first? I don't mind if I have to start using arrays from 0, it was just purely because I liked it the other way.

My array[2] is actually correct! They want a separate project for each task. So task 1 is one project, task 2 is another project etc. Which means that Task 3 is literally only task 3 instructions. So I only need to calculate the distance for two planets, the big array and big list is for task 4.

The syntax question was in the instructions. Although I'm not entirely sure why its like that. Its creating a pointer to an array(of pointers), which we can pass to the functions? Which is much more flexable than just a straight up Array? Correct me if I am wrong!


Regarding the setter functions, that was one of my questions in my first post. I had created the functions but couldn't get them to work with the generate_planets. p->Setx() doesn't work because it is expecting a value. I hadn't thought to set them into temp variables first, simple really but couldn't get my head around it. Thanks!


What bit must I delete? I don't quite understand this. Also could you explain the error checking? I already have a check in main() so do I need another?

Thanks!
Was This Post Helpful? 0
  • +
  • -

#12 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 11 November 2014 - 10:13 PM

Quote

What bit must I delete? I don't quite understand this. Also could you explain the error checking? I already have a check in main() so do I need another?


Yes. Using eof() to control data entry is usually not the best method, you are better off using the "return" value from the read operation. However since this function is returning a pointer you you can't really use the "return" value from the read operation.

The check in main is after you do all the storing of the values to the variables. The eof(0 flag won't be set until after you try to read the file. So the last time through the loop when you try to read the file, it will fail. When the stream fails the variables won't get valid values. Therefore you need to check the stream state after you try the read. If the stream state is good then it is okay to allocate the memory for the class, and store the temporary values into the class. If the stream fails you don't want to allocate the memory and try to set the member variables to the bad values.


Jim
Was This Post Helpful? 0
  • +
  • -

#13 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 15 November 2014 - 11:04 AM

That makes sense actually, thanks.

The program was crashing each time originally - because the file was being read one more time than it needed to be and the array wasn't big enough so it kept crashing out? When I set the proper error check it worked fine.

All the programs appeared to be working perfectly and are now submitted, thanks for the help :)
Was This Post Helpful? 0
  • +
  • -

#14 Syzygy   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 30
  • Joined: 23-January 14

Re: Create class instances from text file stream.

Posted 15 November 2014 - 07:11 PM

Ok.. this was apparently a 'duplicate' so ... will post it here. I assumed because it was about some random crash rather than how to create a class instance from a text file it would be considered a new topic. I'm new here so will take a while to learn how things work, sorry :smile2:/>


-----------------------------------
I did this program for an assignment the other day and it was running fine for days. I opened it up again to look at something and now it is crashing 9 times out of 10. Sometimes it works, but mostly it doesn't.

This is the line that causes the crash:
cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;


but I believe that is because it is trying to display something that doesn't exist / it can't display, hence the crash. The actual problem is somewhere within the generate_planet function as, when the above line is commented out, it does not crash but the final distance is a load of rubbish.

So it seems the data from the file is not getting written to the classes? I'm lost :)/>

The idea is, the program takes two sets of data from a file in the form 'id x y z' and then finds the distance between the two sets of coordinates.

Can't seem to attached the code files so the code is below: (We weren't allowed to use class member functions, so thats why they're separate)
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>

using namespace std;

class Planet
{
private:
    int id=0;
    float x_coord=0.0, y_coord=0.0, z_coord=0.0;

public:
    int GetID(){return id;}
    float GetX(){return x_coord;}
    float GetY(){return y_coord;}
    float GetZ(){return z_coord;}
    void SetID(int identity){id=identity;}
    void SetX(float x){x_coord=x;}
    void SetY(float y){y_coord=y;}
    void SetZ(float z){z_coord=z;}
};

Planet* generate_planet (ifstream& planetlist);
float distance_between_planets (Planet& planet1, Planet& planet2);

int main()
{
    int i=1;
    Planet *PlanetArray[2];
    string line;
    ifstream planetlist ("planets.txt");

    cout << "\n\nDISTANCE BETWEEN TWO PLANETS FROM TEXT FILE\n\n";

    if(planetlist)
    {
        while(!planetlist.eof())
        {
            PlanetArray[i]=generate_planet(planetlist);
            cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " << PlanetArray[i]->GetX() << " , " << PlanetArray[i]->GetY() << " , "            << PlanetArray[i]->GetZ() << " )" << endl;
            i++;
        }
    }
    else
    {
        cout << "\n\n\n\tFile failed to open! Maybe it does not exist? (planets.txt)\n\n" << endl;
    }

    cout << "\nThe distance between the two planets is: " << distance_between_planets(*PlanetArray[1],*PlanetArray[2]) << " 'units of space distance'!\n" << endl;

    return 0;
}

Planet* generate_planet (ifstream& planetlist)
{
    Planet* p = new Planet;

    int tempid=0;
    float tempx=0.0,tempy=0.0,tempz=0.0;

    planetlist >> tempid >> tempx >> tempy >> tempz;

    p->SetID(tempid);
    p->SetX(tempx);
    p->SetY(tempy);
    p->SetZ(tempz);

    return (p);
}

float distance_between_planets (Planet& planet1, Planet& planet2)
{
    float x1=0.0,x2=0.0,y1=0.0,y2=0.0,z1=0.0,z2=0.0,distance=0.0;
    distance=sqrt(
    ((planet1.GetX()-planet2.GetX())*(planet1.GetX()-planet2.GetX()))+
    ((planet1.GetY()-planet2.GetY())*(planet1.GetY()-planet2.GetY()))+
    ((planet1.GetZ()-planet2.GetZ())*(planet1.GetZ()-planet2.GetZ())));

    return(distance);
}



And the text file:
1 5.4 2.1 8.7
2 6 3.132 981



I couldn't get your error check to work for some reason. Even assigning the pointer to Null was causing issues so I'm not sure if that was just something dodgy with the complier at the moment in time or not. When I looked into the code online I couldn't find anything wrong with what you'd suggested (ignoring a missing semi-colon). I'd like to include it if I can get it working though, however the random crashing probably needs to be solved first - unless they're interlinked somehow.

Thanks!
Was This Post Helpful? 0
  • +
  • -

#15 jimblumberg   User is offline

  • member icon

Reputation: 5568
  • View blog
  • Posts: 17,213
  • Joined: 25-December 09

Re: Create class instances from text file stream.

Posted 15 November 2014 - 07:18 PM

My first suggestion is to break up that line so you can tell which of the function calls is failing.

cout << "Planet ID (" << PlanetArray[i]->GetID() << ") has landing site coordinates: ( " ;
cout << PlanetArray[i]->GetX() << " , " ;
cout << PlanetArray[i]->GetY() << " , " ;
cout << PlanetArray[i]->GetZ() << " )" << endl;



Edit: My bet would be that the line previous to this is the one causing the problem.


Jim

This post has been edited by jimblumberg: 15 November 2014 - 07:31 PM

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2