How to compare two values from two different text files?

Pages: 12
@Handy Andy

Finally making some progress now that I'm seeing examples, but how should I go about using idx to correlate to a position using the if(idx > -1)? What should I put in that? Where should I put that?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void readProgramGPA(ifstream& out, studentType studentInfo[], int studentNum)
{
    out.open("studentlist.txt");
    
    char programCode{};
    int id{}, idx{};
    double GPA{};
    
    while(!out.eof())
    {
        out >> id >> programCode >> GPA;
        
        idx = findStudentByID(id, studentInfo, studentNum);
        
        if(idx > -1)
        {
            idx = idx;
        }
        
        
    }
    

}

int findStudentByID(int id, const studentType studentInfo[], int studentNum)
{
    int idx;
    
    bool found = false;
    
    for(idx = 0; idx < studentNum; idx++)
    
        if(studentInfo[idx].id == id)
        {
            found = true;
            break;
        }
        
        if(found)
        {
            return idx;
        }
        else
        {
            return -1;
        }


    
}
Hello domweng,

A slight improvement, but not quite there yet.

The while loop: while(!out.eof()) does not work the way that you are thinking it does, or maybe the way that you were lead to believe in classs.

Line 11 is trying to read an output file stream.

Line 13 is good, but since you are trying to read an output stream the value of id would be (0)zero, so your function call would return (-1).

Line 15 is good.

Line 17 does nothing. Why are you setting "idx" equal to its -self?

Line 26 is good.

Line 28 should be initialized to (0)zero.

Line 30 is unnecessary.

Why did you take a perfectly good function and muck it? What I showed you is a simple function that gets the job done. If you did not understand it just ask. The function I gave you should not be beyond what you know at this point.

I am referring to the function in: http://www.cplusplus.com/forum/beginner/277686/#msg1198743 near the end of the post.

Andy
1. I didn't even realize you let me know what should be in place on the !out.eof() my apologies, so that should fix my lines 11 and 13.

2. I set idx to itself because I really didn't know what to put into the if(idx > -1) and I'm lost right now just had an idea to reuse the idx after it's checked to be an actual number, but I was really just shooting guesses.

3. On the note of line 30 I didn't "muck" your idea for findStudentById and I understood what you meant by it, I had just already written a function loosely based around what was in my book which accomplishes the same, if a match is found return idx & if not found return -1.

So this is overall what I have at the moment...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

enum programType { CSCI, DBMS, INFM, SDEV };

const int NUM_STUDENTS = 20;

struct studentName
{
    string firstName;
    char middleInitial;
    string lastName;
};

struct studentType
{
    studentName name;
    int id;
    string email;
    char program;
    double gpa;
    
};

void readClassRoster(ifstream& in, studentType studentInfo[], int& studentNum);
void readProgramGPA(ifstream& out, studentType studentInfo[], int studentNum);
int findStudentByID(int studentID, const studentType studentInfo[], int studentNum);

int main()
{
    int students{};
    studentType studentInfo[NUM_STUDENTS];
    
    ifstream in;
    readClassRoster(in, studentInfo, students);
    
    ifstream out;
    readProgramGPA(out, studentInfo, students);
    
    
    return 0;
}

void readClassRoster(ifstream& in, studentType studentInfo[], int& studentNum)
{
    in.open("classroster.txt");
    in >> studentNum;
    
    for(int i = 0; i < studentNum; i++)
    {
        in >> studentInfo[i].name.firstName >> studentInfo[i].name.middleInitial >> studentInfo[i].name.lastName >> studentInfo[i].id >> studentInfo[i].email;
    }
    
}

void readProgramGPA(ifstream& out, studentType studentInfo[], int studentNum)
{
    out.open("studentlist.txt");
    
    char code{};
    int id{}, idx{};
    double GPA{};
    
    while(out >> id >> code >> GPA)
    {
        
        idx = findStudentByID(id, studentInfo, studentNum);
        
        if(idx > -1)
        {
            
        }
        
    }
    

}

int findStudentByID(int id, const studentType studentInfo[], int studentNum)
{
    int idx;
    
    bool found = false;
    
    for(idx = 0; idx < studentNum; idx++)
    
        if(studentInfo[idx].id == id)
        {
            found = true;
            break;
        }
        
        if(found)
        {
            return idx;
        }
        else
        {
            return -1;
        }


    
}

Does that look better??

Now just need to figure out what to put in the if(idx > -1) & and also how to use that to set the correlating values from the "studentlist.txt" to my array values in my studentInfo...

I'm not sure but it should be something that systemically is read like "studentInfo[idx].gpa = GPA[idx]" if I'm not mistaken. It confused me though as the GPA variable made in this function isn't and array and I'm also not allowed to use a double[int] as array subscript.

Which I will most likely need help on
Last edited on
@domweng, you should look at my previous code.

However, from your post above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

enum programType { CSCI, DBMS, INFM, SDEV };

const int NUM_STUDENTS {20};

struct studentName
{
	string firstName;
	char middleInitial {};
	string lastName;
};

struct studentType
{
	studentName name;
	int id {};
	string email;
	char program {};
	double gpa {};
};

void readClassRoster(ifstream& in, studentType studentInfo[], int& studentNum);
void readProgramGPA(ifstream& out, studentType studentInfo[], int studentNum);
int findStudentByID(int studentID, const studentType studentInfo[], int studentNum);

int main()
{
	int students {};
	studentType studentInfo[NUM_STUDENTS] {};

	ifstream in;
	readClassRoster(in, studentInfo, students);

	ifstream out;
	readProgramGPA(out, studentInfo, students);
}

void readClassRoster(ifstream& in, studentType studentInfo[], int& studentNum)
{
	in.open("classroster.txt");
	in >> studentNum;

	for (int i = 0; i < studentNum; ++i)
		in >> studentInfo[i].name.firstName >> studentInfo[i].name.middleInitial >> studentInfo[i].name.lastName >> studentInfo[i].id >> studentInfo[i].email;
}

void readProgramGPA(ifstream& out, studentType studentInfo[], int studentNum)
{
	out.open("studentlist.txt");

	char code {};
	int id {};
	double GPA {};

	while (out >> id >> code >> GPA) {
		int idx {findStudentByID(id, studentInfo, studentNum)};

		if (idx > -1) {
			studentInfo[idx].gpa = GPA;
			studentInfo[idx].program = code;
		}
	}
}

int findStudentByID(int id, const studentType studentInfo[], int studentNum)
{
	int idx {};
	bool found {};

	for (; !found && idx < studentNum; ++idx)
		if (studentInfo[idx].id == id)
			found = true;

	return found ? idx : -1;
}


You should have a function to display the contents of studentInfo so that you can see if things are working OK.
Last edited on
@seeplus: I prefer the logic that you had earlier:
1
2
3
4
5
6
7
8
9
int findStudentByID( unsigned studentID, const StudentType info[], int studentNum )
{
  for ( int idx = 0; idx < studentNum; ++idx ) {
    if ( info[idx].id == studentID ) {
      return idx;
    }
  }
  return -1;
}

The 'found' flag and the ternary operator feel unnecessary.

The entire function would be unnecessary, if one could use Standard Library:
1
2
3
4
int idx {findStudentByID(id, studentInfo, studentNum)};

if (idx > -1) {
    studentInfo[idx].gpa = GPA;

could be:
1
2
3
4
auto it { std::find_if( studentInfo, studentInfo+studentNum, [id](auto s){return s.id == id;} ) };

if ( it != studentInfo+studentNum ) {
    it->gpa = GPA;

Of course that requires knowing the library, iterators, and lambda closures.
I prefer the logic that you had earlier


I agree - but I was only 'fixing' the OP' code's above.

I suspect that findStudentById() is going to used later on in the assignment to display student info when an id is entered so the function is probably needed.
Last edited on
OP had the earlier logic first (copy-pasted?), but modified it (for wrong reasons).
Hello domweng,

In some ways it is better.

1
2
3
4
5
6
7
8
9
struct Student
{
    StudentName name;
    int id{};
    string email;
    programType program{};  // <--- Changed. This is a number that comes from the "enum" or from something else.
    double gpa{};

};

Looking at what the struct contains "Student" or "StudentInfo" is more a appropriate name. Unless it absultly required a better name is easier to work with. Also it really helps when you start a class or struct name with a capital letter, but not required.

For line 6 go back tan reread your instructions.
Program (an enum type named programType containing programs such as CSCI, DBMS, INFM, SDEV).



3. On the note of line 30 I didn't "muck" your idea for findStudentById and I understood what you meant by it, I had just already written a function loosely based around what was in my book which accomplishes the same, if a match is found return idx & if not found return -1.


What was in my book is like saying "just following orders" it is not always the best way. The book is technically correct, but uses more code than is needed. What is in a book may be a way of explaining something not necessarily the best way to implement the idea. Learning something to just get by is fine, but learning something that not only does the job, but does it better or easier is what you need to achieve.



I'm not sure but it should be something that systemically is read like "studentInfo[idx].gpa = GPA[idx]" if I'm not mistaken. It confused me though as the GPA variable made in this function isn't and array and I'm also not allowed to use a double[int] as array subscript.


Seeing as double gpa{}; is not an array using a subscript should have flagged a compiler error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void readProgramGPA(ifstream& out, Student students[], int studentNum)
{
    out.open("studentlist.txt");
    // <--- Need to check if it is open.

    char code{};
    int id{}, idx{};
    double GPA{};

    while (out >> id >> code >> GPA)
    {

        idx = findStudentByID(id, students, studentNum);

        if (idx > -1)
        {
            // if true use "idx" to set the value of GPA.

            // Then I used a switch based on the "programCode" read from the file.
            // In the case statements use the "enum" to set the value of "programCode".

        }

        // If false there is no match, so just read the next record.
    }
}

I will have to start with line 10. Why are you trying to read from an output file stream?

Again go back and read your instructions to see what needs to be done within the if statement. You have all the information you need to complete this part.

Andy
Handy Andy wrote:
I will have to start with line 10. Why are you trying to read from an output file stream?

Wrong question. The out is an std::ifstream.
The question is: Is 'out' a good, descriptive name for input stream?
@keskiverto,

I realize all of that.

After all I have said about using a good variable name I am trying to make the point of what a bad variable name can do.

Andy
Topic archived. No new replies allowed.
Pages: 12