Connecting Tech Pros Worldwide Help | Site Map

problems with pointers

olf olf is offline
Newbie
 
Join Date: Jan 2007
Posts: 5
#1: Jan 25 '07
Hello all,
I have very recently trying to make a small program in c++ and I am having problems with pointers.

I want to read a line from a file, send that line to a function that parses and stores the lines content.
So I have my

getline (myfile,line,'\n');
fillData(line);

functions, where fillData obviously is the parser/storing function and line is a simple string.

fillData is declared as: void fillData(string line);

All fillData does at the moment is: string first = strtok(line, ' ');.
But even these simple things give me errors. And I am assuming it is because I have to use pointers and references to acctually make it work but I just cant seem to figure it out.
So Im hoping that I can get some help here.

Thanks in advance.
/Olle
Banfa's Avatar
AdministratorVoR
 
Join Date: Feb 2006
Location: South West UK
Posts: 6,165
#2: Jan 25 '07

re: problems with pointers


It would be helpful if you could post a more complete version of your code as well as saying what platform (computer/OS) and compiler you are using.
olf olf is offline
Newbie
 
Join Date: Jan 2007
Posts: 5
#3: Jan 25 '07

re: problems with pointers


Of course, sorry for leaving less information than needed.
Im sitting on WinXp and using Visual c++ 6.0.
The complete code looks like the following at the moment:

Expand|Select|Wrap|Line Numbers
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <fstream>
  4. #include <string>
  5. #include <list>
  6. #include <map>
  7.  
  8. using namespace std;
  9.  
  10. class Io{
  11.     public:    
  12.         void readFile();
  13.     private:
  14.         void fillData(string * line);
  15. };
  16.  
  17. void Io::fillData(string * line){
  18.     char * first = strtok(line.c_str(), ' ');
  19. }
  20.  
  21. void Io::readFile() {
  22.     string line;
  23.     ifstream myfile;
  24.     myfile.open ("data.txt");
  25.  
  26.     if (myfile.is_open()){
  27.         while (! myfile.eof() ){
  28.             getline (myfile,line,'\n');
  29.             fillData(line);
  30.             cout << line << endl;
  31.         }
  32.         myfile.close();
  33.     }
  34.     else cout << "Unable to open file"; 
  35. }
  36.  
  37. int main(int argc, char* argv[]){
  38.     Io io;
  39.     io.readFile();
  40.     return 0;
  41. }
  42.  
I hope this clears things up a bit, and thanks for taking the time to reply.

/Olle
Banfa's Avatar
AdministratorVoR
 
Join Date: Feb 2006
Location: South West UK
Posts: 6,165
#4: Jan 25 '07

re: problems with pointers


Sofar all your problems are related to the method fillData

Expand|Select|Wrap|Line Numbers
  1. void Io::fillData(string * line){
  2.     char * first = strtok(line.c_str(), ' ');
  3. }
  4.  
  5. void Io::readFile() {
  6.     string line;
  7. ...
  8.     fillData(line);
  9. ...
  10. }
  11.  
fillData takes a string * as its parameter, in read file you call it with a string, this causes an error the line that calls fillData should be

fillData(&line);

The you can a similar mistake in fillData using

line.c_str()

where you should have

line->c_str()

(BTW I thing fillData would be better if it took a reference to a string as a parameter string &, in this case neither of these other changes are required.)

Even if you fix those 2 problems you still have one more problem. strtok (unlike many other string library functions) has a char * parameter because it actually alters the string that it points to. string::c_str() returns const char * because it is not will to release control of its buffers.

You can not pass the return of string::c_str() directly to strtok because of this const qualifier difference.

What you will need to do is copy the data out of the string first into a modifiable character array. To make sure the array is big enough you will need to dynamically allocate it on the fly.

logically fillData needs to do this

Expand|Select|Wrap|Line Numbers
  1. fillData(string *line){
  2.     Allocate char array buffer large enough to hold string in line
  3.     Copy from line to the char array
  4.     Use strtok to tokenise the char array and store the data
  5.     Free the allocated char array
  6. }
  7.  
RedSon's Avatar
Site Moderator
 
Join Date: Jan 2007
Location: America
Posts: 3,387
#5: Jan 25 '07

re: problems with pointers


Quote:

Originally Posted by Banfa

Expand|Select|Wrap|Line Numbers
  1. fillData(string *line){
  2.     Allocate char array buffer large enough to hold string in line
  3.     Copy from line to the char array
  4.     Use strtok to tokenise the char array and store the data
  5.     Free the allocated char array
  6. }
  7.  

But wait Banfa, that code doesnt compile!!!! Help!
olf olf is offline
Newbie
 
Join Date: Jan 2007
Posts: 5
#6: Jan 26 '07

re: problems with pointers


Thank you very much for the help, I got that part to work now.

/Olle
olf olf is offline
Newbie
 
Join Date: Jan 2007
Posts: 5
#7: Jan 26 '07

re: problems with pointers


A few more problems have arised and I hope that it is ok if I ask more questions.
I have now read and tokenized the strings. What I want to do know is to create numerous structures that hold the information that I have read.
The thing that I am working on involves trains in a train network. So I want to store information about the trains in one type of struct and information about the tracks in another type.
So basically I want two separate lists of structures.
Am I right in assuming that I will have to pass along these lists throughout the functions? Ie create them in main, pass them to readFile and then pass them to fillData where each train/node is assigned values.

The whole program now looks like
Expand|Select|Wrap|Line Numbers
  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <fstream>
  4. #include <sstream>
  5. #include <string>
  6. #include <list>
  7. #include <map>
  8.  
  9. using namespace std;
  10.  
  11. //The segment information, one or more located inside each node
  12. struct segInf{
  13.     string name;
  14.     int oneDist;
  15.     int length;
  16.     int maxSpeed;
  17. };
  18.  
  19. //junction information, connections between nodes may contain junctions
  20. struct junction{
  21.     string name;
  22.     int maxSpeed;
  23. };
  24.  
  25. //the nodes that make up the graph
  26. struct Node{
  27.     list <segInf> segList;
  28.     map < string , list < junction > > zerolist;
  29.     map < string , list < junction > > onelist;
  30. };
  31.  
  32. struct Train{
  33.     string name;
  34.     string currnode;
  35.     string ednstation;
  36.     int maxspeed;
  37. };
  38.  
  39. class Io{
  40.     public:    
  41.         void readFile(Train* trainlist[], Node* nodelist[]);
  42.     private:
  43.         void fillData(string& line);
  44. };
  45.  
  46. void Io::createTrain(string name, string currnode, string endstn, int maxspeed){
  47.     Train train;
  48.     train.name = name;
  49.     train.currnode = currnode;
  50.     train.ednstation = endstn;
  51.     train.maxspeed = maxspeed;
  52. }
  53.  
  54. void Io::fillData(string& line){
  55.     char temp[30];
  56.     memset( temp, '\0', 30 );
  57.     line.copy(temp, 30);
  58.     string first = strtok(temp, " ");
  59.     //find out what type of line we read - train or node
  60.     if(first.compare("train") == 0){
  61.         cout << "train" << endl;
  62.         string name = strtok(NULL, " ");
  63.         string currnode = strtok(NULL, " ");
  64.         string endstn = strtok(NULL, " ");
  65.         string max = strtok(NULL, " ");
  66.         std::istringstream i(max);
  67.         int maxspeed;
  68.         i >> maxspeed;
  69.         //assign values to a train struct
  70.     }
  71.     else if(first.compare("node") == 0){
  72.         cout << "node" << endl;
  73.     }
  74. }
  75.  
  76. void Io::readFile(Train* trainlist[], Node* nodelist[]) {
  77.     string line;
  78.     ifstream myfile;
  79.     myfile.open("data.txt");
  80.  
  81.     if (myfile.is_open()){
  82.         while (! myfile.eof() ){
  83.             getline (myfile,line,'\n');
  84.             fillData(line);
  85.         }
  86.         myfile.close();
  87.     }
  88.     else cout << "Unable to open file";
  89. }
  90.  
  91. int main(int argc, char* argv[]){
  92.     Train trainlist[];
  93.     Node nodelist[];
  94.     Io io;
  95.     io.readFile(trainlist, nodelist);        
  96.     return 0;
  97. }
  98.  
There are several things that are both wrong and that bothers me. Lets start with the temp-array in fillData, it feels horribly wrong to declare it with a static size. I think I should be able to read the length of line and declare it with that size but I just cant get that to work.
The same problem arises with the trainlist and the nodelist in main.
The other problem is how I pass the two lists in main correctly through to the other functions. Since I want to use the data later on I thought I would take them as references in readFile and fillData, but that turns out to be impossible as "arrays of references are illegal".

Turned out to be a very long post, I hope its not as confusing for you guys as it is for me and I hope that you might be able to help me, at least with some parts of it.
If you could do as Banfa did and provide explanations it would also be great as I get the feeling that these things are very basic and are bound to turn up again. So I want to try and learn how things work and not just get a quick solution.

Thanks for taking the time to read and reply.

/Olle
Banfa's Avatar
AdministratorVoR
 
Join Date: Feb 2006
Location: South West UK
Posts: 6,165
#8: Jan 26 '07

re: problems with pointers


Quote:

Originally Posted by RedSon

But wait Banfa, that code doesnt compile!!!! Help!

You had better be joking...

<looks round for pointy stick>
Banfa's Avatar
AdministratorVoR
 
Join Date: Feb 2006
Location: South West UK
Posts: 6,165
#9: Jan 26 '07

re: problems with pointers


Quote:

Originally Posted by olf

A few more problems have arised and I hope that it is ok if I ask more questions.

Absolutly not, we have a strict quota of 1 question per poster per week...


oh hang on that's not right, we don't have any quota at all :p

OK sarcasm aside please ask as many questions as you like generally we will attempt to answer them all.

Quote:

Originally Posted by olf

I have now read and tokenized the strings. What I want to do know is to create numerous structures that hold the information that I have read.
The thing that I am working on involves trains in a train network. So I want to store information about the trains in one type of struct and information about the tracks in another type.
So basically I want two separate lists of structures.
Am I right in assuming that I will have to pass along these lists throughout the functions? Ie create them in main, pass them to readFile and then pass them to fillData where each train/node is assigned values.

Well sort of, however at this point I am not sure you have a good class hierarchy and you need to get that right first.

You have an IO class, this reads the file and creates trains. This is not good, trains are nothing to do with file IO, additionally you have your train and node lists in main. You have trains, nodes (not clear to me exactly what this represents), junctions and segments (track segments?). What you don't have is a Network class.

In my mind the network would be the top level, every train, junction, node and segement must belong to a rail network and this should be represented. The network would then contain the lists of trains etc and in main you would have a single declaration of a single network instance.

The network would contin the functions to load the data from a file but because it also contains the lists of trains etc there would then be no need to pass these around so you could write straight to them.

I would re-write functions like void Io::createTrain(...) as a constructor of the train struct (I might make a class to).

What you are aiming for is each class/structure accessing its own data and a reduction of class/structure data access externally to the clss/structure.

Remember the only difference between a class and a struct is that a class members have a default access of private and a struct memebers have a default access of public.

The IO class is not helpful because it does not excapsulate anything real.



Quote:

Originally Posted by olf

There are several things that are both wrong and that bothers me. Lets start with the temp-array in fillData, it feels horribly wrong to declare it with a static size. I think I should be able to read the length of line and declare it with that size but I just cant get that to work.

It feels horrible because it is horrible, and it is also asking for trouble. Dynamically allocating the data is not hard
Expand|Select|Wrap|Line Numbers
  1. void Io::fillData(string& line){
  2.     char *temp = new char[line.length()+1];// +1 for terminator
  3.  
  4.     if (temp != NULL) // Just check the memory allocation worked
  5.     {
  6.         // Copy line totemp and then terminate the string
  7.         line.copy(temp, line.length());
  8.         temp[line.length()] = '\0';
  9.  
  10.         // <snipped tokenising code>
  11.  
  12.         delete[] temp;
  13.     }
  14.     else
  15.     {
  16.         // Memory allocation failure handling code
  17.     }
  18. }
  19.  
Quote:

Originally Posted by olf

The same problem arises with the trainlist and the nodelist in main.

Look up the C++ standard containers vector, deque, list, map, set. These handle dynamically sized lists for you and are well worth learning because once you know them you will use them all the time. I would have thought either list or map would suit this application.

Quote:

Originally Posted by olf

The other problem is how I pass the two lists in main correctly through to the other functions. Since I want to use the data later on I thought I would take them as references in readFile and fillData, but that turns out to be impossible as "arrays of references are illegal".

As I explained above a "Network" class contining the train etc lists will solve this as its member functions will have access to its member data so there will be no need to pass the data around.
olf olf is offline
Newbie
 
Join Date: Jan 2007
Posts: 5
#10: Jan 26 '07

re: problems with pointers


Once again, thanks for the help, explanations and opinions.
Its very appreciated and now I have something to read and do.
I will very likely get back with more questions during or after the weekend.

Thanks alot!

/Olle
Reply