Basing Array Size on Input File

I have a program due for class. We just finished talking about arrays.It says:

"Write a program that reads a file consisting of students' test scores in the range 0-200. It should then determine the number of students have scores in each of the following ranges: 0-24, 25-49, 50-74, 75-99, 100-124, 125-149, 150-174, 175-200. Output the score ranges and the number of students. (Run your program with the following input data: 76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189, 167, 200, 175, 150, 87, 99, 129, 149, 176, 200, 87, 35, 157, 189.)


To be honest, I'm completely clueless. Here is my skeleton so far:

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

int main()
{
int index;
int scores[index];
char filename[51];
ifstream inData;

cout >> "Enter name of file to be read:" << endl;
cin << filename;
inData.open(filename);
cout >> endl; 

cout >> "0-24: \t" >> variable1 >> endl;
cout >> "25-49: \t" >> variable2 >> endl;
cout >> "50-74: \t" >> variable3 >> endl;
cout >> "75-99: \t" >> variable4 >> endl;
cout >> "100-124: \t" >> variable5 >> endl;
cout >> "125-149: \t" >> variable6 >> endl;
cout >> "150-174: \t" >> variable7 >> endl;
cout >> "175-200: \t" >> variable8 >> endl;
return 0;
}


So my question is, how do I make it so that the array "scores" is the same number that the file holds (pretending I didn't already know)?
You should use a std::vector:
http://www.cplusplus.com/reference/vector/vector/
http://en.cppreference.com/w/cpp/container/vector

If you're not allowed to, you have to do it the wrong way instead by using dynamic memory (e.g. the new[] and delete[] operators). I must apologize in advance if your professor requires you to do it the wrong way.
Last edited on
@ThisGuyIsBrad

Your program won't compile. For one, the variable index, is not even defined, and so you cannot create the array of scores[]. Second, it's cout <<, NOT cout >>. Your cin << needs to be cin >> You can define scores with a size of 8, since you need eight checks. You can define it as int scores[8] = {0}, to zeroes it out. You also need one more variable to hold the digit read in. Check its value, and use if statements.
1
2
3
4
5
if (myvar <=24)
 scores[0]++;
if (myvar <=49)
  scores[1]++;
\\etc... 


Hopefully, you know how to read a file..
Last edited on
Okay, so we've not been taught either of those. I'm just going to assume that I can know that the input number is 26. So I now change it to:

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

int main()
{
int scores[25];
char filename[51];
ifstream inData;
int count1,count2,count3,count4,count5,count6,count7,count8;

cout >> "Enter name of file to be read:" << endl;
cin << filename;
inData.open(filename);
cout >> endl; 



cout >> "0-24: \t" >> count1 >> endl;
cout >> "25-49: \t" >> count2 >> endl;
cout >> "50-74: \t" >> count3 >> endl;
cout >> "75-99: \t" >> count4 >> endl;
cout >> "100-124: \t" >> count5 >> endl;
cout >> "125-149: \t" >> count6 >> endl;
cout >> "150-174: \t" >> count7 >> endl;
cout >> "175-200: \t" >> count8 >> endl;
return 0;
}



I'm absolutely clueless. Do you have any clue of how I should go from there?
@ThisGuyIsBrad

I don't think you even read what I answered.

After opening your file, read the number into a variable. For now, let's assume it's int MyVar. The array of scores, needs to be only 8, since, as I mentioned, you're needing only 8 different results. When this finishes, print out scores[0] to scores[7], instead of your count1 to count8.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
while(inData >> MyVar)
{
if( MyVar <= 25)
scores[0]++;
if( MyVar > 25 && MyVar <= 49)
scores[1]++;
if(  MyVar > 49 && MyVar <= 74)
scores[2]++;
if(  MyVar > 74 && MyVar <= 99)
scores[3]++;
if(  MyVar > 99 && MyVar <= 124)
scores[4]++;
if(  MyVar > 124 && MyVar <= 149)
scores[5]++;
if(  MyVar > 149 && MyVar <= 174)
scores[6]++;
if(  MyVar > 174 && MyVar <= 200)
scores[7]++;
num_students++;
}
I completely didn't even see it. I'm sorry. So after stressing a while, I finally got 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
#include <iostream>
#include <fstream>
using namespace std;

int main()
{

    int scores[26];
    int counter = 0;
    int category[8] = {0};
    
    
    cout << "Opening grades.txt ..." << endl;
    ifstream infile("grades.txt");
    infile.open("grades.txt");
    cout << endl;
    
    if (infile.is_open())
    {
        while(infile.good())
        {
            if(scores[counter] >= 0 && scores[counter]<= 24){
                category[0]++;
            }
            else if(scores[counter] >= 25 && scores[counter] <= 49)
                category[1]++;
            else if(scores[counter] >= 50 && scores[counter] <= 74)
                category[2]++;
            else if(scores[counter] >= 75 && scores[counter] <= 99)
               category[3]++;
            else if(scores[counter] >= 100 && scores[counter] <= 124)
                category[4]++;
            else if(scores[counter] >= 125 && scores[counter] <= 149)
                category[5]++;
            else if(scores[counter] >= 150 && scores[counter] <= 174)
                category[6]++;
            else {
                category[7]++;
            }
            counter++;
        }
        
    }
    cout << "0-24: \t" << category[0] << endl;
    cout << "25-49: \t" << category[1] << endl;
    cout << "50-74: \t" << category[2] << endl;
    cout << "75-99: \t" << category[3] << endl;
    cout << "100-124: \t" << category[4] << endl;
    cout << "125-149: \t" << category[5]<< endl;
    cout << "150-174: \t" << category[6] << endl;
    cout << "175-200: \t" << category[7] << endl;
    return 0;
}


For some reason all my ending numbers come out as all 0s. Any idea on how to make it count correctly?
@ThisGuyIsBrad

This .. while(infile.good()) does not read in the numbers to any variable, plus the scores[] array values, never change. Look closer how I check the inData values, in the previous post. Oh, and also, you don't need the scores[] array, since you created a category[] array.
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
#include <iostream>
#include <fstream>
using namespace std;

int main()
{

    int scores;
    int category[8] = {0};
    int counter = 0;
    
    
    
   cout << "Opening grades.txt ..." << endl;
    ifstream infile("grades.txt");
    infile.open("grades.txt");
    cout << endl;
    
    if (infile.is_open())
    {
        while(infile >> scores)
        {
            if(scores >= 0 && scores<= 24)
                category[0]++;
            if(scores >= 25 && scores <= 49)
                category[1]++;
            if(scores >= 50 && scores <= 74)
                category[2]++;
          /* if(scores[counter] >= 75 && scores[counter] <= 99)
               category[3]++;
            if(scores[counter] >= 100 && scores[counter] <= 124)
                category[4]++;
            if(scores[counter] >= 125 && scores[counter] <= 149)
                category[5]++;
            if(scores[counter] >= 150 && scores[counter] <= 174)
                category[6]++;
            if(scores[counter] >= 175 && scores[counter] <= 200)
                category[7]++; */
            
            counter++;
        }
        
    }
    cout << "0-24: \t" << category[0] << endl;
    cout << "25-49: \t" << category[1] << endl;
    cout << "50-74: \t" << category[2] << endl;
    cout << "75-99: \t" << category[3] << endl;
    cout << "100-124: \t" << category[4] << endl;
    cout << "125-149: \t" << category[5]<< endl;
    cout << "150-174: \t" << category[6] << endl;
    cout << "175-200: \t" << category[7] << endl;
    return 0;
}

I don't quite understand how to fix it. how do I use the counter variable to be sure that the program reads the whole list? I'm still getting the same result. I'm not even sure that it's opening my file.
Last edited on
@ThisGuyIsBrad

You don't need counter unless you want to show how many student scores there were. You almost have your program correct. Here it is with just some minor fixes.

The while (infile >> scores) will keep looping until there are no more to be read, then stops. It would be a goo idea to add infile.close();, before the return 0. It may not be absolutely required, but it's a good practice to get into.

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>
using namespace std;

int main()
{

 int scores;
 int category[8] = {0};
 int counter = 0;



 cout << "Opening grades.txt ..." << endl;
 ifstream infile("grades.txt");
 
 cout << endl;

 if (infile)
 {
	while(infile >> scores)
	{
	 if(scores >= 0 && scores<= 24)
		category[0]++;
	 if(scores >= 25 && scores <= 49)
		category[1]++;
	 if(scores >= 50 && scores <= 74)
		category[2]++;
	 if(scores >= 75 && scores<= 99)
		category[3]++;
	 if(scores >= 100 && scores <= 124)
		category[4]++;
	 if(scores >= 125 && scores <= 149)
		category[5]++;
	 if(scores >= 150 && scores<= 174)
		category[6]++;
	 if(scores >= 175 && scores <= 200)
		category[7]++;

	 counter++; // Use only if you want to show now many students there are, total
	}

 }
 cout << "0-24: \t" << category[0] << endl;
 cout << "25-49: \t" << category[1] << endl;
 cout << "50-74: \t" << category[2] << endl;
 cout << "75-99: \t" << category[3] << endl;
 cout << "100-124: \t" << category[4] << endl;
 cout << "125-149: \t" << category[5]<< endl;
 cout << "150-174: \t" << category[6] << endl;
 cout << "175-200: \t" << category[7] << endl;
 cout << endl << "There are a total of " << counter << " student scores.." << endl;
 return 0;
}
Last edited on
I appreciate the help. I think I'm slowly starting to understand. I am having a major problem, though. My program isn't even reading the file. I have the .cpp and the .txt in the same file. What else could I be missing?

EDIT: I have the file opening. I just had to do the full address. Now the problem is that it only reads my first number in the list.
Last edited on
Make sure that the file data has no commas in it, just the numbers. I put each number on a separate line, but it should also do fine with a string of numbers with just a space for separation between each. You were reading just one number, correct, the 76?
I haven't read the thread really, but I have to chime in. Forgive me if what I mention here was already mentioned -- but I didn't see it when I skimmed.

I hate these kinds of if chains, and you should too:

1
2
3
4
	 if(scores >= 0 && scores<= 24)
		category[0]++;
	 if(scores >= 25 && scores <= 49)
		category[1]++;


Why do I hate them?

Mainly... they're redundant. Redundant code is bad code. You can take advantage of the fact that an else statement will only execute if the previous if condition was false.

This is better, less error prone, and less redundant:

1
2
3
4
5
6
7
8
9
if(scores >= 0)
{
    if     (scores < 25)    category[0]++;
    else if(scores < 50)    category[1]++;
    else if(scores < 75)    category[2]++;
    else if(scores < 100)   category[3]++;
    else if(scores < 125)   category[4]++;
    ...
    


By using else if, the else ensures the previous if was false. So by the time we test (scores < 50), we already know it's >= 25 because it would have to be for the previous if to be false. The first if already covers it... we don't have to cover it again.





But even that is bad, as you don't need if's at all. You have an array, and you have a linear mapping of ranges to indexes (ie: each entry in the array corresponds to 25 scores). So all you really have to do is divide by 25 and bounds check:

1
2
3
4
5
int index = scores / 25;
if(index >= 0 && index < 8) // make sure it's in bounds
    category[index]++;

// that's it! 


Plug in some numbers and you'll find that:


index = scores/25  yields the below results:

scores   / 25 = index
----------------
  0- 24 / 25  = 0
 25- 49 / 25  = 1
 50- 74 / 25  = 2
 75-100 / 25  = 3
 etc


Math is your friend.
Last edited on
OH MY GOODNESS THANK YOU! I had the commas still in there. I guess that's what was tripping you up. You're a huge life saver.
@Disch

Yes, I see that the else if makes it look a lot better, but the rest of your post isn't going with the program above. A file is being read, and depending on the score read, one of the category indexes is increased. What is being checked then, is how many of the digits falls between 0 and 25, 26 to 50, etc. I will, though, keep track of what you wrote, as it may come in handy for whatever I may program.
Last edited on
1
2
3
4
5
int index = scores / 25;
if(index >= 0 && index < 8) // make sure it's in bounds
    category[index]++;

// that's it!  
since it goes up to 200 and not 199 you need to add this after
1
2
else if(index == 8)
    ++category[index-1];
or alternatively
1
2
else if(index == 8)
    ++category[7];
or even
1
2
else if(scores == 200)
    ++category[7];


*changed if to else if since there was a previous if.
Last edited on
OVERKILL


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

class RangeTally
{
private:
    struct Range
    {
        int min;
        int max;
        int count;

        Range(int n,int x) : min(n), max(x), count(0) {}
    };
    
    std::vector<Range>      tallies;
    
    bool isValidId(int id)
    {
        if(id < 0)              return false;
        if(id >= getSize())     return false;
        return true;
    }
    
public:
    void clear()
    {
        tallies.clear();
    }
    
    void resetTallies()
    {
        for(auto& i : tallies)
            i.count = 0;
    }
    
    int addRange(int min, int max)
    {
        tallies.emplace_back( min,max );
        return getSize()-1;
    }
    
    void tally(int value)
    {
        for(auto& i : tallies)
        {
            if(value < i.min)   continue;
            if(value > i.max)   continue;
            ++i.count;
        }
    }
    
    int getMin(int id)
    {
        return isValidId(id) ? tallies[id].min : 0;
    }
    
    int getMax(int id)
    {
        return isValidId(id) ? tallies[id].max : 0;
    }
    
    int getTally(int id)
    {
        return isValidId(id) ? tallies[id].count : 0;
    }
    
    int getSize()
    {
        return static_cast<int>(tallies.size());
    }
};


////////////////////////////////////////
////////////////////////////////////////

// define your ranges
RangeTally tally;
for(int i = 0; i < 175; i += 25)
    tally.addRange( i, i+24 );
tally.addRange(175,200);


// tally up the categories
while(infile >> scores)
{
    tally.tally( scores );
    ++counter;
}

// print them out
for(int i = 0; i < tally.getSize(); ++i)
{
    cout << tally.getMin(i) << '-' << tally.getMax(i) << ": \t" << tally.getCount(i) << '\n';
}
cout << "\nThere are a total of " << counter << " student scores.." << endl;
Last edited on
Topic archived. No new replies allowed.