-1

I am trying to write a program that reads information from a text file and copies it into an array using structs and unions and cstrings. My textfile looks something like this.

F South Korea
Male Psy Park Jae Sang
31 - 12 - 1977
3 CSCI114 55 CSCI103 44 GangNam 100

S Female Super Junior
5 - 8 - 1978 
2 CSCI114 60 CSCI103 80

F People Republic Of China
Unknown James Bond
11 - 12 - 1976
4 CSCI114 54 CSCI124 66 CSCI007 99 CSCI123 28

My query is, I've written a simple switch case with a for loop that reads in the information based on its criteria. For instance, the first letter before each paragraph denotes whether the student is a Foreigner, F, or Singaporean, S. Based to their nationality, I'm choosing which struct/union to copy their information into. To give you a better idea, this is what my final text output file will look like after I take in the information from the original text file and process it.

https://i.stack.imgur.com/Bv2YS.jpg

Below is my section of code I am having trouble with. It seems whether or not the char variable reads "S" or "F", my switch statement is only reading it in as "F".

        //file to array.


        char dateJunk;
        int numOfCourses;

        int k = 0;
        while (!afile.eof())
        {
            for (int k = 0; k < 3; k++)
            {
            afile >> locale;
                switch (locale)
                {
                    case 'F':
                        afile.getline(x[k].st.foreignStudent.nationality, MAX);
                        afile >> x[k].st.foreignStudent.gender;
                        afile.getline(x[k].st.foreignStudent.name, MAX);
                        afile >> x[k].st.foreignStudent.bd.day;
                        afile >> dateJunk;
                        afile >> x[k].st.foreignStudent.bd.month;
                        afile >> dateJunk;
                        afile >> x[k].st.foreignStudent.bd.year;
                        afile >> x[k].st.foreignStudent.numOfCourses;

                        for (int i = 0; i < x[k].st.foreignStudent.numOfCourses; i++)
                        {
                            afile >> x[i].st.foreignStudent.subjects[k];

                            afile >> x[i].st.foreignStudent.grades[k];
                        }
                        break;

                    case 'S':
                        afile >> x[k].st.localStudent.gender;
                        afile.getline(x[k].st.localStudent.name, MAX);
                        afile >> x[k].st.localStudent.bd.day;
                        afile >> dateJunk;
                        afile >> x[k].st.localStudent.bd.month;
                        afile >> dateJunk;
                        afile >> x[k].st.localStudent.bd.year;
                        afile >> x[k].st.localStudent.numOfCourses;;
                        for (int i = 0; i < x[k].st.localStudent.numOfCourses; i++)
                        {
                            afile >> x[i].st.localStudent.subjects[k];

                            afile >> x[i].st.localStudent.grades[k];
                        }
                }
                }
        }

        //Tests my cstring arrays to see everything is copied in correctly.
        for (int k = 0; k < 3; k++)
        {
        cout << locale << " " << x[k].st.foreignStudent.nationality;
        cout << endl;
        cout << x[k].st.foreignStudent.gender;
        cout << x[k].st.foreignStudent.name;
        cout << endl;
        cout << x[k].st.foreignStudent.bd.day << " - ";
        cout << x[k].st.foreignStudent.bd.month << " - ";
        cout << x[k].st.foreignStudent.bd.year;
        cout << endl;
        cout << x[k].st.foreignStudent.numOfCourses;
        cout << endl;
        for(int i = 0; i < x[k].st.foreignStudent.numOfCourses; i++)
        {
        cout << x[i].st.foreignStudent.subjects[k] << " ";
        cout << x[i].st.foreignStudent.grades[k] << " ";

        }
            cout << endl;
        }

        return 0;
    }

Below is the code in its entirety.

    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <ctime>
    using namespace std;

    const int MAX = 80;

    struct Birthday
    {
        char day[MAX];
        char month[MAX];
        char year[MAX];
    };

    struct Local
    {
        char name[MAX];
        char nationality[MAX];
        char gender[MAX];
        Birthday bd;
        char subjects [MAX][MAX];
        char grades [MAX][MAX];
        int numOfCourses;

    };

    struct Foreigner
    {
        char name[MAX];
        char nationality[MAX];
        char gender[MAX];
        Birthday bd;
        char subjects [MAX][MAX];
        char grades [MAX][MAX];
        int numOfCourses;
    };

    union Student
    {
        Local     localStudent;
        Foreigner foreignStudent;
    };

    enum CountryType {S, F};

    struct UowStudents
    {
        CountryType ct;
        Student st;
    };

    int fileToArray (fstream& afile, char fileName [], UowStudents* x, char& locale);

    int main ()
    {
        srand(time_t(NULL));

        fstream afile;
        UowStudents x [MAX];
        char fileName[MAX];
        char locale;
        cout << "Enter filename: ";
        cin >> fileName;
        int size = fileToArray (afile, fileName, x, locale);


    }

    int fileToArray (fstream& afile, char fileName [], UowStudents* x, char& locale)
    {
        afile.open(fileName, ios::in);

        if (!afile)
        {
            cout << fileName << "could not be opened for read" << endl;
            exit (-1);
        }
        //file to array.


        char dateJunk;
        int numOfCourses;

        int k = 0;
        while (!afile.eof())
        {
            for (int k = 0; k < 3; k++)
            {
            afile >> locale;
                switch (locale)
                {
                    case 'F':
                        afile.getline(x[k].st.foreignStudent.nationality, MAX);
                        afile >> x[k].st.foreignStudent.gender;
                        afile.getline(x[k].st.foreignStudent.name, MAX);
                        afile >> x[k].st.foreignStudent.bd.day;
                        afile >> dateJunk;
                        afile >> x[k].st.foreignStudent.bd.month;
                        afile >> dateJunk;
                        afile >> x[k].st.foreignStudent.bd.year;
                        afile >> x[k].st.foreignStudent.numOfCourses;

                        for (int i = 0; i < x[k].st.foreignStudent.numOfCourses; i++)
                        {
                            afile >> x[i].st.foreignStudent.subjects[k];

                            afile >> x[i].st.foreignStudent.grades[k];
                        }
                        break;

                    case 'S':
                        afile >> x[k].st.localStudent.gender;
                        afile.getline(x[k].st.localStudent.name, MAX);
                        afile >> x[k].st.localStudent.bd.day;
                        afile >> dateJunk;
                        afile >> x[k].st.localStudent.bd.month;
                        afile >> dateJunk;
                        afile >> x[k].st.localStudent.bd.year;
                        afile >> x[k].st.localStudent.numOfCourses;;
                        for (int i = 0; i < x[k].st.localStudent.numOfCourses; i++)
                        {
                            afile >> x[i].st.localStudent.subjects[k];

                            afile >> x[i].st.localStudent.grades[k];
                        }
                }
                }
        }

        //Tests my cstring arrays to see everything is copied in correctly.
        //The print for foreign student cstrings also has information for the
        //one Singaporean student "S" in the middle. Singaporean must go into
        //the local cstrings.
        for (int k = 0; k < 3; k++)
        {
        cout << locale << " " << x[k].st.foreignStudent.nationality;
        cout << endl;
        cout << x[k].st.foreignStudent.gender;
        cout << x[k].st.foreignStudent.name;
        cout << endl;
        cout << x[k].st.foreignStudent.bd.day << " - ";
        cout << x[k].st.foreignStudent.bd.month << " - ";
        cout << x[k].st.foreignStudent.bd.year;
        cout << endl;
        cout << x[k].st.foreignStudent.numOfCourses;
        cout << endl;
        for(int i = 0; i < x[k].st.foreignStudent.numOfCourses; i++)
        {
        cout << x[i].st.foreignStudent.subjects[k] << " ";
        cout << x[i].st.foreignStudent.grades[k] << " ";

        }
            cout << endl;
        }

//as you can see, everything gets copied into localStudent struct as well.
        for (int k = 0; k < 3; k++)
        {

            cout << x[k].st.localStudent.gender;
            cout << x[k].st.localStudent.name;
            cout << endl;
            cout << x[k].st.localStudent.bd.day << " - ";
            cout << x[k].st.localStudent.bd.month << " - ";
            cout << x[k].st.localStudent.bd.year;
            cout << endl;
            cout << x[k].st.localStudent.numOfCourses;
            cout << endl;
            for(int i = 0; i < x[k].st.localStudent.numOfCourses; i++)
            {
                cout << x[i].st.localStudent.subjects[k] << " ";
                cout << x[i].st.localStudent.grades[k] << " ";

            }
            cout << endl;
        }




        return 0;
    }
NSGod
  • 22,699
  • 3
  • 58
  • 66
TL Han
  • 27
  • 1
  • 10
  • [Don't use `while(!eof())`](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – chris Jan 06 '13 at 09:03
  • And do not copy/paste all of your code, but provide the smallest chunk that can be used to reproduce the problem: no-one is going to read more than 10-15 lines of code here. Anyway, run everything under the debugger to see what's wrong. And add some error-handling! I see 100 lines of code without a single error handling thing. – stijn Jan 06 '13 at 09:10
  • 1
    @stijn I thought I provided the chunk with the issue in the first code box no? The 2nd code box is the entire program. – TL Han Jan 06 '13 at 09:15
  • @chris endoffile is the only way I'm getting proper input results with this. Oh, and I've figured out what was wrong with the repeated segments. I had to replace my union with a struct and now its working properly. – TL Han Jan 06 '13 at 09:15
  • 1
    Why are you using C-strings instead of `std::string`? – leemes Jan 06 '13 at 09:16
  • My lecturer specifically told us to apply cstrings for this program @leemes. – TL Han Jan 06 '13 at 09:17
  • Funny, I think I saw someone here not long ago with the same assignment, but perhaps an earlier stage. – chris Jan 06 '13 at 09:18
  • I think that'd be me as well haha. That was last nights issue. – TL Han Jan 06 '13 at 09:20
  • To the anonymous user who thumbed my question down -- why?? – TL Han Jan 06 '13 at 09:49
  • 1
    `My query is, I've written a simple switch case with a for loop that reads in the information based on its criteria.` -> Uhm, that is not a query. – Sebastian Mach Jan 06 '13 at 09:53
  • 2
    @AceHahn: If you scroll over the vote-down button, there is e.g. "This question does not show any research effort". That could be the reason. – Sebastian Mach Jan 06 '13 at 10:00
  • 3
    This feels way too much like we're doing your homework for you, especially now that you've asked two questions about the same assignment. If this is for a class, you need to learn how to analyze and debug your own code. Asking strangers on the Internet to do it for you, while a successful short-term strategy, will get you nowhere in the long run. – Kurt Revis Jan 06 '13 at 10:02
  • @phresnel Yes, in the midst of phrasing my 'query', I seem to have actually forgotten to do the actual querying, big deal. – TL Han Jan 06 '13 at 13:02
  • @KurtRevis, I'm sorry if you or anyone in the forum feel that way towards my posts. I really have no clue sometimes where some things should/could be fixed after looking at the code for hours and hours and changing and messing about with it. You shouldn't assume Im taking what this community is offering for granted, as that is not my intention. I literally spend many hours doing my homework -- researching everything I can dig up for a particular issue I am facing in reference books and on the internet and this is my final and last website I resort to. Give me a break for crying out loud! – TL Han Jan 06 '13 at 13:08
  • @KurtRevis And as for your sage 'the long run' advice, we all take baby steps in the beginning don't we? And if we fall, we get up and if we can't, we yell help for someone to help dont we? A little understanding Kurt, com'on now. – TL Han Jan 06 '13 at 13:18

1 Answers1

0

You are seeing the effects of using a union in C++.

The main characteristic of a union that all members share the same block of memory. And because your member structures Local and Foreigner have exactly the same layout, you can use either to print the contents of the union.

If you change one of the structures (for example, remove nationality from Local), you will see that some of the printouts get garbled (notably, those entries where you print a foreign student as a local one of vice versa). This is because the memory block used for the students get interpreted differently for local and foreign students.
Note: Technically, this results in undefined behaviour, but in this case the results are unlikely to be catastrophic. Officially, you can only read the same member of a union that you last wrote to, or (if the members are structures) the initial members of a structure that are the same as in the structure last written to the union.

Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41