Very stuck with eof() related problem

Hi C++ friends,

I'm studying Problem Solving with C++ 8e by Walter Savitch, on Chapter 6 "I/O Streams as an Introduction to Objects and Classes."

One of the problems at the end of the chapter is to take input from two files and output to one other file. Each of the two input files is a list of ordered integers, with no other stipulations such as whether the integers shouldn't be repeated or not. The output file must be the two lists combined resulting in a longer list that's ordered.

I've worked probably more than 9 hours altogether on this problem. One primary strategy I tried and came back to is to control the loops with eof() checks. The other primary strategy I tried was controlling the loops with extraction statements (e.g., "file_in_1 >> value_1"), but the deriving code was getting to be too complicated both for me to follow and for it to be a likely solution at this early stage.

Below is where I'm at presently. It works for all the boundary types of cases I could conceive, except each of the input files requires a '\n' after the last integer. This is what made me try controlling loops with extraction statements instead, where I failed worse.

I don't feel like I should be satisfied. I feel like there must be better logic that would make it work regardless of a new-line character. As far as a beginner would know, this problem represents an important broader class of problems related to file endings that just simply wouldn't have such a relatively non-robust solution.

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
void combine_keep_order(ifstream& file_in_1_var, ifstream& file_in_2_var, ofstream& file_out_var)
{
    int number_1, number_2;

    file_in_1_var >> number_1;
    file_in_2_var >> number_2;
    while(file_in_1_var.eof() != true or file_in_2_var.eof() != true)
    {
        if(number_1 <= number_2)
        {
            if(file_in_1_var.eof() != true)
            {
                file_out_var << number_1 << endl;
                file_in_1_var >> number_1;
            }
            else if(file_in_1_var.eof())
            {
                file_out_var << number_2 << endl;
                file_in_2_var >> number_2;
            }
        }
        if(number_1 > number_2)
        {
            if(file_in_2_var.eof() != true)
            {
                file_out_var << number_2 << endl;
                file_in_2_var >> number_2;
            }
            else if(file_in_2_var.eof())
            {
                file_out_var << number_1 << endl;
                file_in_1_var >> number_1;
            }
        }
    }

    return;
}
http://www.cplusplus.com/reference/algorithm/merge/
Try to mimic that algorithm. Where if (first1==last1) will be if( not in_a.eof() )
and the copy while( in_a>>n ) out << n;

By the way file_in_1_var.eof() != true looks obfuscated. ¿why not just not file_in_1_var.eof() ?


Also
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <iterator>
#include <fstream>
#include <algorithm>

int main(int argc, char **argv){
	std::ifstream a("a.txt"), b("b.txt");
	std::merge(
		std::istream_iterator<int>(a),
		std::istream_iterator<int>(),
		std::istream_iterator<int>(b),
		std::istream_iterator<int>(),
		std::ostream_iterator<int>( std::cout, " " )
	);
	return 0;
}
Thank you Ne. I couldn't mimic the merge algorithm very well though since I can't yet make enough sense of some that syntax. I determined that I could brute check for either an integer or an end-of-file. The form of the function is almost the same except (1) for two while() loops instead of one, (2) where single extraction statements are replaced with compound statements involving get() and putback(), and (3) where Boolean variables about valid content replace end-of-file calls.

The first while loop takes the place of

1
2
file_in_1_var >> number_1;
file_in_2_var >> number_2;

either to determine if the variables have valid content or to handle the cases routinely if either or both lists are empty. For an example of one extraction statement being replaced with a compound extraction statement,

1
2
3
4
5
6
7
8
9
do
{   file_in_1_var.get(symbol);
}   while((symbol == '\n' or symbol == ' ') and not file_in_1_var.eof());
if(not file_in_1_var.eof())
{
    file_in_1_var.putback(symbol);
    file_in_1_var >> number_1;
}
else content_1 = false;

The loop reads white characters until it gets to a non-white character. If it's not the end of the file, the last character read is put back into the stream so that it can then be part of a valid extraction. The truth values of content_1 and content_2 represent number_1 and number_2 respectively, and they take the place of eof() functions in the main controls. A more finished version might've abstracted the brute checks:

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
void combine_keep_order(ifstream& file_in_1_var, ifstream& file_in_2_var, ofstream& file_out_var)
{
    int number_1, number_2;
    char symbol;
    bool content_1, content_2;

    // Handle the cases where either list or both lists are empty
    // and where both lists are non-empty initiate the variables.
    while(true)
    {
        do
        {   file_in_1_var.get(symbol);
        }   while((symbol == '\n' or symbol == ' ') and not file_in_1_var.eof());
        if(not file_in_1_var.eof())
        {
            file_in_1_var.putback(symbol);
            file_in_1_var >> number_1;
            content_1 = true;
        }
        else content_1 = false;

        do
        {   file_in_2_var.get(symbol);
        }   while((symbol == '\n' or symbol == ' ') and not file_in_2_var.eof());
        if(not file_in_2_var.eof())
        {
            file_in_2_var.putback(symbol);
            file_in_2_var >> number_2;
            content_2 = true;
        }
        else content_2 = false;

        if(content_1 == false and content_2 == false)
            break;
        else if(content_1 == false and content_2 == true)
        {
            file_out_var << number_2 << endl;
            while(content_2 == true)
            {
                do
                {   file_in_2_var.get(symbol);
                }   while((symbol == '\n' or symbol == ' ') and not file_in_2_var.eof());
                if(not file_in_2_var.eof())
                {
                    file_in_2_var.putback(symbol);
                    file_in_2_var >> number_2;
                    file_out_var << number_2 << endl;
                }
                else content_2 = false;
            }
            break;
        }
        else if(content_1 == true and content_2 == false)
        {
            file_out_var << number_1 << endl;
            while(content_1 == true)
            {
                do
                {   file_in_1_var.get(symbol);
                }   while((symbol == '\n' or symbol == ' ') and not file_in_1_var.eof());
                if(not file_in_1_var.eof())
                {
                    file_in_1_var.putback(symbol);
                    file_in_1_var >> number_1;
                    file_out_var << number_1 << endl;
                }
                else content_1 = false;
            }
            break;
        }
        break;
    }

    // Combine while either list can extract valid content.
    while(content_1 == true or content_2 == true)
    {
        if(number_1 <= number_2)
        {
            if(content_1 == true)
            {
                file_out_var << number_1 << endl;
                do
                {   file_in_1_var.get(symbol);
                }   while((symbol == '\n' or symbol == ' ') and not file_in_1_var.eof());
                if(not file_in_1_var.eof())
                {
                    file_in_1_var.putback(symbol);
                    file_in_1_var >> number_1;
                }
                else content_1 = false;
            }
            else if(content_1 == false)
            {
                if(content_2 == true)
                {
                    file_out_var << number_2 << endl;
                    do
                    {   file_in_2_var.get(symbol);
                    }   while((symbol == '\n' or symbol == ' ') and not file_in_2_var.eof());
                    if(not file_in_2_var.eof())
                    {
                        file_in_2_var.putback(symbol);
                        file_in_2_var >> number_2;
                    }
                    else content_2 = false;
                }
            }
        }
        if(number_1 > number_2)
        {
            if(content_2 == true)
            {
                file_out_var << number_2 << endl;
                do
                {   file_in_2_var.get(symbol);
                }   while((symbol == '\n' or symbol == ' ') and not file_in_2_var.eof());
                if(not file_in_2_var.eof())
                {
                    file_in_2_var.putback(symbol);
                    file_in_2_var >> number_2;
                }
                else content_2 = false;
            }
            else if(content_2 == false)
            {
                if(content_1 == true)
                {
                    file_out_var << number_1 << endl;
                    do
                    {   file_in_1_var.get(symbol);
                    }   while((symbol == '\n' or symbol == ' ') and not file_in_1_var.eof());
                    if(not file_in_1_var.eof())
                    {
                        file_in_1_var.putback(symbol);
                        file_in_1_var >> number_1;
                    }
                    else content_1 = false;
                }
            }
        }
    }

    return;
}

I myself won't "mark as solved" since I don't have 100% confidence that it wouldn't be broken, although it seems to pass the same kinds of tests as before including those with input files having variously white endings.
¿Just 1 digit numbers? Really, you are doing a mess just to read 1 character.
¿Why don't just copy the content of the files to a container (like a deque or a vector) and then do the merge?

Line 71: ¿why do you have an unconditional break?

Still, the idea is that if you reach the eof in either file, you should break the loop. And just copy the remaining elements of the other file.
If both content_1 and content_2 are true and there's no break, then the loop won't end. But I just realized this first while() loop wasn't necessary, although everything inside it is necessary relative to the previous version (except for the break statements).

This function works with integers of any digit length and as long as they're in order from least to greatest. Before, what was happening was when the last integer of a list was extracted it would arbitrarily either "possess" an end-of-file signal simultaneously with the extraction or it would not, and there was no way to handle it consistently. When the loop ended, either one or the other or both of the last integers in the list either would not have been output to the file or would be written twice to the file, and a programming assumption could not be made about the matter in order to do a final handling or final comparison after the loop ended.

Your suggestion with a container sounds like it would be better. Unfortunately I haven't been taught anything about Deque and Vector in the book yet (although they'll be covered later according to the index). However, being constrained with only what has been taught so far made me feel like I got a much better understanding of reading input from a file.
Topic archived. No new replies allowed.