c++ problem when trying to read from file

Thread Starter

frogacult

Joined Apr 30, 2008
27
Hello everyone
I have a txt file which contains 150 lines.Each line has the student-id and then the grades from 6 lessons like below >>>>


1523 5 7 6 7 3 9
1524 7 4 9 10 3 6
....
....
.....


I want to create a method that will read the file and will save this data in 2 arrays. The first array will be ID[150] in which will be stored the id's of each student and the second array will be GRD[6][150] in which will be saved the 6 grades of each student.

I've created a method to do this work but when im tryin to check the arrays i don't get to correct values in the correct places.

my code is this:
Rich (BB code):
unsigned int getData(ifstream& f, unsigned int* ID,float** GRD)
{
   unsigned int j=0;
   f>>ID[j];
   while ((j<150) && (!f.eof()))
   {
      for (unsigned int i=0; i<6; i++)
         f>>GRD[j];

      j++;
      f>>ID[j];              
   }
   return j;
}

int main() {
   unsigned int ID[150],col;
   float GRD[6][150],*k[6];
   ifstream f;

   for (int i=0; i<6;i++)
      k = &B[0];

   f.open("myFile.txt");
   if (f.fail())
      cout<<"File not found!";
   else
      col = getData(f,AM,k);

}


Now if you try to check the content of the arrays you will realize that the id's aren't in possitions ID[0]=1523, ID[1]=1524.......... neither the grades!

can you help me?
Thanks a lot!! :)
 

Mark44

Joined Nov 26, 2007
628
Your code is pretty difficult to understand, since your variable names aren't self-explanatory. That makes it more difficult for a reader, like me, to understand what a variable represents. Some of the worst examples are f, k, and B. It's OK to have single-letter names for loop counters like i and j, but your other variable names ought to be suggestive of what you want to do with them.

Also, it's very bad form to have variable names in all caps; e.g., GRD, AM, and to a lesser extent, ID. Identifiers using all caps are almost always used for constants that are defined in a #define preprocessor directive.

Some of your variables don't seem to be initialized. At least I don't see that happening in the two functions you posted. The ones I notice are AM and B. Are these global variables defined outside of main() and getData()?

Apparently this code compiles and runs. It would be more helpful if you told me what was in each array rather than what isn't in them.

One thing I notice is that you have declared k like so:
Rich (BB code):
float * k[6];
Do you realize that k is an array of pointers to float?
 

Thread Starter

frogacult

Joined Apr 30, 2008
27
you have right, i was wrong when i was pasting my code here.
I have 1 table for the student's id's with name stId[150], and a table for the 6 grades of each student with name stGrad[6][150].
I want to read the file as i told you before and store the id's and the grades in these two arrays.
My teacher gave me this example but it's not working. Also i can't neither understand why is he using the pointer *k.I tried to create the method getData with the arguments of the inpout file stream, and the two arrays but i can't transfer the value from the file to the table through this method

example : getData(ifstream& f, int& stId[],float& stGrd[][])
When i do this method i'm getting errors saying that i can't transfer the values of the file in these tables through this method.If i do it in main() everything is ok.

I post again the code

Rich (BB code):
unsigned int getData(ifstream& f, unsigned int * stId,float **stGrd)
{
   unsigned int j=0;
   f>>stId[j];
   while ((j<150) && (!f.eof()))
   {
      for (unsigned int i=0; i<6; i++)
         f>>stGrd[j];

      j++;
      f>>stId[j];              
   }
   return j;
}

int main()
{
   unsigned int stId[150],col;
   float stGrd[6][150],*k[6];

ifstream f;

   for (int i=0; i<6;i++)   /////// I can't understand these two lines
      k = &stGrd[0];

   f.open("stud.txt");
   if (f.fail())
      cout<<"File not found";
   else
      col = getData(f,stId,k); 
}
 

Mark44

Joined Nov 26, 2007
628
you have right, i was wrong when i was pasting my code here.
I have 1 table for the student's id's with name stId[150], and a table for the 6 grades of each student with name stGrad[6][150].
I want to read the file as i told you before and store the id's and the grades in these two arrays.
My teacher gave me this example but it's not working. Also i can't neither understand why is he using the pointer *k.
stId[] is a one-dimension array, so technically is not a table. It's basically a list of student IDs. stGrad[][] is a two-dimension array, so can be thought of as a table. The way you declared it, stGrad[6][150], it has 6 rows and 150 columns. I would probably have declared it the other way around, like this: stGrad[160][6]. That way each row would contain the grades of one student.

You asked about two lines in your code in your for loop, in main(). I have included a few lines that come before it.
Rich (BB code):
   unsigned int stId[150],col;
   float stGrd[6][150],*k[6];

   ifstream f;

   for (int i=0; i<6;i++)   /////// I can't understand these two lines
      k = &stGrd[0];


As mentioned before, stGrd is a two-dimension array, with 6 rows (across) and 160 columns (up and down). k, which is a really dumb name, is a 6-element array of pointers to float. The for loop that you asked about cycles through the rows of the stGrd array, and puts the addresses of the first entry of each row into k. IOW, the assignment statement puts the address of stGrd[0][0] into k[0], the address of stGrd[1][0] into k[1], and so on, with the last one putting the address of stGrd[5][0] into k[5].

Why does it do this? I have no idea, but you asked for an explanation of what your code was doing, so there it is.
I tried to create the method getData with the arguments of the inpout file stream, and the two arrays but i can't transfer the value from the file to the table through this method

example : getData(ifstream& f, int& stId[],float& stGrd[][])
When i do this method i'm getting errors saying that i can't transfer the values of the file in these tables through this method.If i do it in main() everything is ok.

I post again the code

Rich (BB code):
unsigned int getData(ifstream& f, unsigned int * stId,float **stGrd)
{
   unsigned int j=0;
   f>>stId[j];
   while ((j<150) && (!f.eof()))
   {
      for (unsigned int i=0; i<6; i++)
         f>>stGrd[j];

      j++;
      f>>stId[j];              
   }
   return j;
}

int main()
{
   unsigned int stId[150],col;
   float stGrd[6][150],*k[6];

ifstream f;

   for (int i=0; i<6;i++)   /////// I can't understand these two lines
      k = &stGrd[0];

   f.open("stud.txt");
   if (f.fail())
      cout<<"File not found";
   else
      col = getData(f,stId,k); 
}


I suspect that the problem with your code is that you need another level of indirection in your getData function. In C and C++, a function can't change the value of any of its input arguments, but if you pass a pointer to a value, the function can change what is pointed to, but doesn't change the pointer's value. So while you can do this
Rich (BB code):
int val = 0;
val = 5;
If you write a function to do the same thing, this won't work
Rich (BB code):
main()
{
   int num = 0;
   changeValue(num);
}

void changeValue(int val)
{
    val = 5;
}
After the call to changeValue, num is still 0, and didn't get reset to 5.

This will work, though.
Rich (BB code):
main()
{
   int num = 0;
   changeValue(&num);
}

void changeValue(int *val)
{
    *val = 5;
}
After the call to changeValue, num's value is now 5.

What I'm saying is that your getData function might need to have a header like this
Rich (BB code):
unsigned int getData(ifstream& f, unsigned int ** stId, float ***stGrd)
but this would require some changes to the body of your function.

It would be helpful for me to see the exact errors your compiler is generating, including line numbers. If you post them, I'll take a look.

Mark
 

Thread Starter

frogacult

Joined Apr 30, 2008
27
Finally it worked.. I don't know how but i got the right results. The most significant point was these two lines
Rich (BB code):
for (int i=0; i<6;i++)
   k = &stGrd[0];


Without these lines the program doesn't work at all!! I can't understand their meaning but i think that the pointer k is assigned to give the values of the table stGrd[][] inside the method getData. I paste all my code to run it if you want and maybe explain me how this works. Thanks a lot :D:D

Rich (BB code):
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>



int getData(ifstream& f,unsigned int *A,float **B) {
	unsigned int pos=0;
	
	f>>A[pos];
	
	while(!f.eof() && pos<150) {
		
		for(int i=0;i<6;i++)
			f>>B[pos];
			
		pos++;
		f>>A[pos];
	}
	return pos;
}

int main()
{
	unsigned int stId[150],size=0;
	float stGrd[6][150],*k[6];
	ifstream f;
	
	f.open("stud.txt");

	for (int i=0; i<6;i++)
	  k = &stGrd[0];

	if(!f)
	  cout<<"File not Found!"<<endl;
	else
	  size=getData(f,stId,k);

        for(int i=0;i<size;i++) {
		cout<<stId<<"\t";
		for(int j=0;j<6;j++)
			cout<<stGrd[j]<<" ";
		cout<<"\n"<<endl;
	}

        
}

}
 

bobbyrae

Joined May 14, 2009
42
I can't figure it out either. You appear to declare k as an array of six pointers and set each to the top of each column. But then in GetData, you seem to have the array indices reversed, so I would have guessed that all the data would be mixed up.

Pointers in C are about the most confusing thing in computer programming and when you use one-letter variable names it just makes it into a big mess. I would suggest rewriting this code with longer variable names and no initializations within loops.
 

Mark44

Joined Nov 26, 2007
628
bobbyrae is concurring with what I've said since my first reply - your variable names are nearly impossible to decipher. And to make matters worse, your rewritten getData function now has two parameters named A and B. The names you chose in post 3 were improvements over the names you had in your first post. stId and stGrd at least convey some indication of what they are supposed to hold. But A and B are absolutely worthless. If you intend to continue with your studies of programming, you have to do better - your instructors will knock points off if you use such poor choices for names.

Also, there is not a single comment in your code. One reason for comments is for the benefit of people reading your code. It also benefits you, the coder, if you revisit your code a few months later when what you did is not so clear.

Regarding the part of the code you don't understand --
Finally it worked.. I don't know how but i got the right results. The most significant point was these two lines

Rich (BB code):
for (int i=0; i<6;i++)
   k = &stGrd[0];

It must have been a miracle for that code to put itself right where it was needed. Or maybe it was code a friend wrote that you were able to copy from.

Since this is code that you wrote, it seems reasonable that you should be able to explain it to me, but that doesn't seem to be the case. For an explanation read what I wrote in my previous post.
 

Thread Starter

frogacult

Joined Apr 30, 2008
27
Mark this excercise and the solution was given to me by my professor..It wasn't mine inspiration. I just tried to solve the problem again alone and every time i didn't know how to continue i checked the solution from my teacher..
Finally it worked..
 

Mark44

Joined Nov 26, 2007
628
In that case, I'm sorry I cast aspersions. It still seems odd to me, though, that your professor would give you an exercise as well as the solution to it.

Anyway, if you still don't understand what the for loop is doing, read the first half of my post #4. After reading that, if you still don't understand, let me know.

Mark
 
Top