c++ problem when trying to read from file

Discussion in 'Programmer's Corner' started by frogacult, Jun 11, 2009.

  1. frogacult

    Thread Starter Member

    Apr 30, 2008
    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:
    Code ( (Unknown Language)):
    2. unsigned int getData(ifstream& f, unsigned int* ID,float** GRD)
    3. {
    4.    unsigned int j=0;
    5.    f>>ID[j];
    6.    while ((j<150) && (!f.eof()))
    7.    {
    8.       for (unsigned int i=0; i<6; i++)
    9.          f>>GRD[i][j];
    11.       j++;
    12.       f>>ID[j];              
    13.    }
    14.    return j;
    15. }
    17. int main() {
    18.    unsigned int ID[150],col;
    19.    float GRD[6][150],*k[6];
    20.    ifstream f;
    22.    for (int i=0; i<6;i++)
    23.       k[i] = &B[i][0];
    25.    f.open("myFile.txt");
    26.    if (f.fail())
    27.       cout<<"File not found!";
    28.    else
    29.       col = getData(f,AM,k);
    31. }[/i][/i][/i]

    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!! :)
  2. Mark44

    Well-Known Member

    Nov 26, 2007
    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:
    Code ( (Unknown Language)):
    1. float * k[6];
    Do you realize that k is an array of pointers to float?
  3. frogacult

    Thread Starter Member

    Apr 30, 2008
    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

    Code ( (Unknown Language)):
    1. unsigned int getData(ifstream& f, unsigned int * stId,float **stGrd)
    2. {
    3.    unsigned int j=0;
    4.    f>>stId[j];
    5.    while ((j<150) && (!f.eof()))
    6.    {
    7.       for (unsigned int i=0; i<6; i++)
    8.          f>>stGrd[i][j];
    10.       j++;
    11.       f>>stId[j];              
    12.    }
    13.    return j;
    14. }
    16. int main()
    17. {
    18.    unsigned int stId[150],col;
    19.    float stGrd[6][150],*k[6];
    21. ifstream f;
    23.    for (int i=0; i<6;i++)   /////// I can't understand these two lines
    24.       k[i] = &stGrd[i][0];
    26.    f.open("stud.txt");
    27.    if (f.fail())
    28.       cout<<"File not found";
    29.    else
    30.       col = getData(f,stId,k);
    31. }[/i][/i][/i]
  4. Mark44

    Well-Known Member

    Nov 26, 2007
    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.
    Code ( (Unknown Language)):
    2.    unsigned int stId[150],col;
    3.    float stGrd[6][150],*k[6];
    5.    ifstream f;
    7.    for (int i=0; i<6;i++)   /////// I can't understand these two lines
    8.       k[i] = &stGrd[i][0];
    9. [/i][/i]

    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 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
    Code ( (Unknown Language)):
    2. int val = 0;
    3. val = 5;
    If you write a function to do the same thing, this won't work
    Code ( (Unknown Language)):
    3. main()
    4. {
    5.    int num = 0;
    6.    changeValue(num);
    7. }
    9. void changeValue(int val)
    10. {
    11.     val = 5;
    12. }
    After the call to changeValue, num is still 0, and didn't get reset to 5.

    This will work, though.
    Code ( (Unknown Language)):
    2. main()
    3. {
    4.    int num = 0;
    5.    changeValue(&num);
    6. }
    8. void changeValue(int *val)
    9. {
    10.     *val = 5;
    11. }
    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
    Code ( (Unknown Language)):
    2. 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.

  5. frogacult

    Thread Starter Member

    Apr 30, 2008
    Finally it worked.. I don't know how but i got the right results. The most significant point was these two lines
    Code ( (Unknown Language)):
    2. for (int i=0; i<6;i++)
    3.    k[i] = &stGrd[i][0];
    4. [/i][/i]

    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

    Code ( (Unknown Language)):
    2. #include <iostream.h>
    3. #include <fstream.h>
    4. #include <stdlib.h>
    8. int getData(ifstream& f,unsigned int *A,float **B) {
    9.     unsigned int pos=0;
    11.     f>>A[pos];
    13.     while(!f.eof() && pos<150) {
    15.         for(int i=0;i<6;i++)
    16.             f>>B[pos][i];
    18.         pos++;
    19.         f>>A[pos];
    20.     }
    21.     return pos;
    22. }
    24. int main()
    25. {
    26.     unsigned int stId[150],size=0;
    27.     float stGrd[6][150],*k[6];
    28.     ifstream f;
    30.     f.open("stud.txt");
    32.     for (int i=0; i<6;i++)
    33.       k[i] = &stGrd[i][0];
    35.     if(!f)
    36.       cout<<"File not Found!"<<endl;
    37.     else
    38.       size=getData(f,stId,k);
    40.         for(int i=0;i<size;i++) {
    41.         cout<<stId[i]<<"\t";
    42.         for(int j=0;j<6;j++)
    43.             cout<<stGrd[i][j]<<" ";
    44.         cout<<"\n"<<endl;
    45.     }
    48. }
    50. }
    51. [/i][/i][/i][/i][/i]
  6. bobbyrae

    Active Member

    May 14, 2009
    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.
  7. Mark44

    Well-Known Member

    Nov 26, 2007
    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 --

    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.
  8. frogacult

    Thread Starter Member

    Apr 30, 2008
    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..
  9. Mark44

    Well-Known Member

    Nov 26, 2007
    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.