For loop isn't working properly

Im trying to write a nested for loop that gets the data from an input file. The for loop will check the student and the 3 courses they are taking the 5 test from each course. The outer loop will be on students, the middle loop will be on courses and the inner loop will be on four tests. Im not sure what Im doing wrong. Im not getting the name from the input file which is the first line.Im stuck and I don't know how to write the for loop.

Input file
Nancy Peterson
22
510 Tumble Dr., San Gabriel, TX 57981
3
(666) 759 - 2249
492-35-5984
CS1428
80.9
90.2
98.5
89.8
97.7
CS2308
50.9
55.2
60.5
65.8
45.7
CS2308
60.9
55.2
60.5
65.8
60.7
Cole john
19
951 Moore St., San Marcos, Tx 77688
(555) 759 - 2249
555-35-5984
CS1428
80.9
90.2
98.5
89.8
97.7
CS2308
50.9
55.2
60.5
65.8
45.7
CS2308
60.9
55.2
60.5
65.8
60.7
John Doe
19
951 Moore St., San Marcos, Tx 77688
(555) 759 - 2249
555-35-5984
CS1428
80.9
90.2
98.5
89.8
97.7
CS2308
50.9
55.2
60.5
65.8
45.7
CS2308
60.9
55.2
60.5
65.8
60.7

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
  #include <iostream>
#include <fstream>
#include <string>
#include<iomanip>
using namespace std;

int main()
{
    string name, social, address, telephone, course;
    int n, courses,number_of_students, i, age, years, number;
    double test1, test2, test3, test4, test5;
    
    const int NUMBER_OF_COURSES = 3;
    const int NUMBER_OF_SCORES = 5;
    
    //number of students
    cout << "How many students?";
    cin >> n;
    
    while (n < 0)
    {
        cout << "No students" << endl;
        cin >> n;
    }
  
    ifstream fin;
    fin.open("project3_A04889172_Input.txt");
        
    // Ask for some info
    for (int i = 0; i < n; ++i) {
        getline(fin,name);
        fin >> age;
        getline(fin,address);
        fin >> years;
        fin >> number;
        for (int j = 0; j < NUMBER_OF_COURSES; ++j) {
            fin >> course;
            for (int k = 0; k < NUMBER_OF_SCORES; ++k) {
                fin >> test1;
                fin >> test2;
                fin >> test3;
                fin >> test4;
                fin >> test5;
                
            }
        }
    }
    ofstream fout;
    fout.open("project3_A04889172_Output.txt");
    
    fout << name; 
    fout << age;
    
    


    return 0;
    
        }

the problem is your mixing of getline() and >>
>> will leave a '\n' in the input, then when using getline() you'll get an empty string
to fix it you may use fin.ignore(); after a >>, or use std::ws if you don't care about leading whitespace
http://www.cplusplus.com/reference/istream/ws/
getline(fin >> std::ws, name);


also, with the for-loop you may continue reading after you reach the end of file
the readings would fail, and the strings will end empty, that's why you couldn't see `name' in the output file.
Last edited on
Hello dbarclay100,

Along with what ne555 has said yoy need to look at the input file and what you are inputting.

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
// Ask for some info
for (int i = 0; i < n; ++i)
{
	//  Nancy Peterson
	//  22
	//  510 Tumble Dr., San Gabriel, TX 57981
	//  3
	//  (666) 759 - 2249
	//  492 - 35 - 5984
	//  CS1428
	//  80.9
	//  90.2
	//  98.5
	//  89.8
	//  97.7

	getline(fin, name);

	fin >> age;
	fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.

	getline(fin, address);

	fin >> years;
	fin >> number;

	for (int j = 0; j < NUMBER_OF_COURSES; ++j)
	{
		fin >> course;
		for (int k = 0; k < NUMBER_OF_SCORES; ++k)
		{
			fin >> test1;
			fin >> test2;
			fin >> test3;
			fin >> test4;
			fin >> test5;
		}
	}
}

Looking at the first record of the input file there are 5 lines to deal with, but you are only dealing with the first five. Missing the sixth line willl through all other read of the file off.

Storing the telephone number in "number" is not a good idea. When I tested the program it just said zero. Because of the () spaces and "-" using the extraction operator >> will not work. You have defined "telephone" as a std::string and that is what you should use. The other problem even if it was just numbers it would be larger than an "int" could store.

Then you have totally missed using the variable "social" and reading this from the file.

Instead of putting the test scores in separate variables vector or an array would work better. Or what you have works.

When you open a file for input you should follow with a check to make sure it is open and usable. Otherwise you will not be able to read anything. Although this can be shortened I like using this:
1
2
3
4
5
6
7
8
9
10
std::string inFileName{ "" };  // <--- Put file name here.

std::ifstream inFile(inFileName);

if (!inFile)
{
	std::cout << "\n File " << inFileName << " did not open" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread".
	return 1;  //exit(1);  // If not in "main".
}

Line 8 is optional. I use it to pause before the console window closes. Gives me time to read the message.

You could do something similar for the output file, but with an output file is fhe file does not exist it will create it. Although possible it is less likely for there to be a problem with an output file.

After you make an entry for "n", please come up with a better name, should you enter the while loop an error message would be a good idea before you prompt for a new number. Not knowing that something is wrong some people would continue to enter the same wrong number.

Your outer for loop may work for now, but later you should consider changing it to a while loop that will allow you to read any size file.

For now you are overwriting all your variables as you read each record. Consider creating a struct to hold the information and a vector or array to hold each record for later processing.

Hope that helps,

Andy
@handy Andy
@ne55

The loop is still not running and Im unable to type in a number for n students. I can only use a nested for loop for this.

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
#include <iostream>
#include <fstream>
#include <string>
#include<iomanip>
using namespace std;

int main()
{
    string name, social, address, telephone, course;
    int n, age, years;
    double test1, test2, test3, test4, test5;
    
    const int NUMBER_OF_COURSES = 3;
    const int NUMBER_OF_SCORES = 5;
    
    //number of students
    cout << "How many students?";
    cin >> n;
    cout << "You entered" << n << endl;
    
    //Open Input and Output file
    ifstream fin;
    fin.open("Input.txt");
    if (!fin) {
        cout << "could not open file" << endl;
        return -1;
    }

    ofstream fout;
    fout.open("Output.txt");
    if (!fout) {
        cout << "could not open file" << endl;
        return -1;
    }
    
    // Ask for some info
    for (int i = 0; i < n; ++i) {
        getline(fin,name);
        fin >> age;
        fin.ignore();
        getline(fin,address);
        fin >> years;
        fin >> telephone;
        fin >> social;
        for (int j = 0; j < NUMBER_OF_COURSES; ++j) {
            fin >> course;
            for (int k = 0; k < NUMBER_OF_SCORES; ++k) {
                
            }
        }
    }
    return 0;
    
        }
Last edited on
Hello dbarclay100,

I think the first thing you need to understand is how the extraction operator, >>, works. First what you type on the keyboard if put into the input buffer before it is put into a variable. The line of code fin >> telephone; will extract from the input buffer up to and including the first white space or new line whichever comes first and discards either the white space or new line leaving whatever is left in the input buffer for the next read.

So what is happening is that fin >> telephone; is only extracting "(555)" into "telephone" because of the white space and leaving the rest for fin >> social;to extract until it finds a white space.

By the time you get to fin >> course; "- 1234" is left in the input buffer and since "course" is a string it will accept the "-" leaving the last four digits of the phone number for the first test score to extract.

"telephone" and "social" need to be read with a "getline" and fin >> years; needs to be followed with fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // <--- Requires header file <limits>. To make sure the input buffer is empty. Your use of fin.ignore(); uses the default of one character and the new line character which may not be enough to clear the buffer because it will stop after one character and never look for the new line.

Even if you do not understand it right now do understand that it is the best way to clear the input buffer. The part std::numeric_limits<std::streamsize>::max() is just getting a large number, the maximum size of the input buffer, for any given operating system and the compiler that creates the program as different computers do have a different size for this number based on what is in the header file used for a given computer's operating system.

To start with I would work in the uncommented part until you get that working.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for (int i = 0; i < n; ++i)
{
	getline(fin, name);
	fin >> age;
	fin.ignore();
	getline(fin, address);
	fin >> years;
        fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
	fin >> telephone;  // <--- change to "getline".
	fin >> social;  // <--- change to "getline".
	//for (int j = 0; j < NUMBER_OF_COURSES; ++j)
	//{
	//	fin >> course;
	//	for (int k = 0; k < NUMBER_OF_SCORES; ++k)
	//	{

	//	}
	//}
	std::cout << std::endl;  //<--- Used as a break point in the IDE for testing.
}


When you get to the last two for loops you have a new problem. Reading "courses" in the outer for loop will leave "courses" with the last course name read because each time through the outer for loop you will over write "courses" with the next read.

On the inner for loop if you want to use five dfferent variables to hold the test scores you can not use a for loop. If you use a 2D array to hold the test scores it will work. Also you should consider using a 1D array to hold the course names.

While you get the first part working think about how to deal with the course names and grades and give a little thought what to do with the information once it is read and before you go to the next record.

Hope that helps,

Andy
Hello dbarclay100,

While working with your program I discovered that the input file is not correct.

In your first record you have address followed be a number for "years". In the second and third record this number is missing. With out it the whole read is off on the second and third record.

Hope that helps,

Andy
@Handy Andy

Im not sure why the names and numbers aren't printing out correctly.

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
 #include <iostream>

#include <fstream>

#include <string>

#include<iomanip>

using namespace std;



int main()

{

    string name, social, address, telephone, course;

    int n, age, years;

    double test;

    const int NUMBER_OF_COURSES = 3;

    const int NUMBER_OF_SCORES = 5;

    int min_students = 1,

        max_students = 100;

    //number of students

    cout << "Enter how many students do you want to see:" << endl;

    cin >> n;

    // Validate the input while loop

    while (n < min_students || n > max_students )

    {

        cout << "You should have at least "<< min_students << " student"
        << " and more than " << max_students << " students" << endl;

        //get number of students again

        cout << "Enter how many students do you want to see:";

        cin >> n;

    }

    //Open Input and Output file

    ifstream fin;

    fin.open("project3_A04889172_Input.txt");

    if (!fin) {

        cout << "could not open file" << endl;

        return -1;

    }

    ofstream fout;

    fout.open("project3_A04889172_Output.txt");

    if (!fout) {

        cout << "could not open file" << endl;

        return -1;

    }

    // Ask for some info

    for (int i = 0; i < n; ++i) {

        getline(fin,name);

        fin >> age;

        fin.ignore();

        getline(fin,address);

        fin >> years;

        fin.ignore();

        getline(fin,telephone);

        getline(fin,social);

        fout << name << endl;
        fout << age << endl;
        fout << address << endl;
        fout << years << endl;
        fout << telephone << endl;
        fout << social << endl;

        for (int j = 0; j < NUMBER_OF_COURSES; ++j) {

            fin.ignore();

            getline(fin,course);
            

            fout << course << endl;



            for (int k = 0; k < NUMBER_OF_SCORES; k++) {

                fin >> test;

                 fout << test << endl;

            }

        }

    }




    return 0;



Last edited on
Hello dbarclay100,

In testing the new code I found the line 109 works better at line 125.

Right now your fin.ignore(); is ignoring one character and it works in this program, but it may not work in the next program.

The best choice is fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // <--- Requires header file <limits>. or at least fin.ignore(1000); or 10,000.

I am not sure why moving the ignore statement makes a difference, but it did.

Just a note: It may have been form the copy and paste, but you missed the closing } of "main". And blank lines are nice, but to many blank lines do not help.

Hope that helps,

Andy

Edit:
Last edited on
Topic archived. No new replies allowed.