Help with program that read files!

Hi. I'm a beginner, and I'm having trouble with my CS 124 C++ class assignment. I'm supposed to write a program that will read a file with 10 grades in it, then display the average score. The problem is that no matter what I do, I always get an error message saying the file can't be read. This is my code:

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

void getFileName(char fileName[]);
float readFile(char fileName[]);
void display(float average);

int main()
{
   char fileName[256];

   getFileName(fileName);
   float average = readFile(fileName);
   display(average);

   return 0;
}

void getFileName(char fileName[])
{
   cout << "Please enter the filename: ";
   cin  >> fileName;
}

float readFile(char fileName[])
{
   ifstream fin(fileName);
   float data;
   fin >> data;
   float average = 0;
   if (fin.fail());
   {
      cout << "Error reading file \""
         << fileName
         << "\""
         << endl;
      return average = -1;

   }

   while (fin >> data)
      average += data;

   fin.close();
   return average;

}

void display(float average)
{
   if (!average == -1)
   cout << "Average Grade: "
        << average
        << "%"
        << endl;
}
Is the file in the same directory as the running executable? This is not the same as the source code directory.

Alternatively, enter the entire path to the file: C:/some/path/with/no/spaces/filename
Last edited on
@obao98
You've got those functions to read from input, from file, and make a display.
So far, so good.
I tried to compile it a few times, and it seems that there are a few issues:
-on line 32:
 
if (fin.fail());

This one only tests the if, then does nothing about it.
That semicolon pretty much makes sure the whole block, that you wished was dependent on the condition, will be executed, whether you like it or not.
Instead remove the ';', and you should have:
1
2
3
4
5
6
7
8
if (fin.fail())
{
  cout << "Error reading file \""
       << fileName
       << "\""
       << endl;
  return average = -1;
}

-after the if was solved, there will be no result displayed.
That would be because of line 52:
 
if (!average==-1)

I am just going to assume that you want to say "if the average is not -1, then display it".
But instead, the not operator '!' will have priority.
So the result inside the if would be:
-if average is anything but 0, then it's always false. It checks whether not-not-zero is equal to -1 (if (0==-1))
-if average is 0, then it checks whether a non-zero is equal to -1 (I do not know what it does next, but it's not as apparently intended).
Here's 2 easy alternatives:
1. set the order of the operators so that you can ask "is it not true that average is equal to -1?", which would look like
 
if (!(average==-1))

2. just use the not-equal operator instead, to ask "is average not equal to/anything but -1?"
 
if (average!=-1)


Also, this would work with such files like "Filetest1.txt" and not "File test 1.txt", because you're using cin>> as opposed to cin.get() or getline, in case you're not aware. But if you're just to work with 1-word-filenames, then it should be all right.
Thanks for the reply Repeater and Troaat.

@troaat

The file I'm trying to open is just called grade.txt, so cin >> should be good.

I was able to figure out that semicolon error too.

I now have two problems with the program:

The grade.txt file has 10 grades written on it: 90 86 95 76 92 83 88 87 91 100

First problem, when the program reads the file and returns the average, it's returning 79, instead of 89, which it seems to me that it's not reading the last number, 100.

Second problem, the program is only supposed to read 10 numbers. If the file has more than 10, or less than 10, it needs to report the error "Error reading file <file>". I've tried creating a loop, but I honestly am very lost. This is my first time working with files, and I don't understand it exactly how it works yet.

I tried creating a for loop after opening the file. This is what I did:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
float readFile(char fileName[])
{
   ifstream fin(fileName);
   float data;
   fin >> data;
   float average = 0;
   if (fin.fail())
   {
      cout << "Error reading file \""
         << fileName
         << "\""
         << endl;
      return average = -1;

   }

   for (float count = data; count <= 10; count++)
      average += count;

   fin.close();
   return average / 10;

}


When I try running the program with that for loop in there, I always get Average Grade 0%. I know it is opening sucessfully the file because it's not giving me the error anymore, but apparently it's not reading the data in the file.
Your only trying to read one float from the file. Perhaps you need to read the whole file?

Please post a small sample of your input file.
The file is very simple. It's just a .txt called grade.txt and it contains a row of 10 numbers, one after the other, separated by a space: 90 86 95 76 92 83 88 87 91 100
Okay, then what is the purpose of line 5?

I would suggest something more like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
double readFile(const std::string& fileName)
{
   ifstream fin(fileName);
   if(!fin)
   {
        std::cerr >> "File failed to open properly.\n";
        return -1.0;
   }

   double data;
   double average = 0;

   while(fin >> data)
      average += data;

   return average / 10.0;
}


But note your function name is misleading. You probably should be just reading the file and returning a vector that contains the "data" and do your average in another function.


@jlb

Thanks for the reply. I changed my loop to a while loop like you suggested and it worked. Now I'm able to read the file and get the data in it. I now have one last problem. As I said above, the file can only be read if it has 10 numbers in it (which it does, and I get the average nicely).

However, the assignment needs to display an error message the file has less than 10 numbers, and more than 10 numbers. So a new grade.txt file is created, this time with only 3 numbers, and another text is created with 12 numbers. This is what I have 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
27
28
29
30
31
32
33
34
35
float readFile(char fileName[])
{
   ifstream fin(fileName);

   float average = 0;

   if (fin.fail())
   {
      cout << "Error reading file \""
           << fileName
           << "\""
           << endl;
      return average = -1;

   }

   float data;
   while (fin >> data)
   {
      average += data;
   }

   if (data != 10)
   {
      cout << "ERROR reading file \""
           << fileName
           << "\""
           << endl;
      return average = -1;
   }

   fin.close();
   return average / 10;

}


I capitalized the ERROR in the IF STATEMENTS to make it different from the fin.fail() error. When I run the program, I get the message with the capitalized ERROR, which tells me function is reading the file normally (since its not returning the error), but the error is in my IF statements (because I'm always getting the capitalized ERROR. I will include my whole code below just to make things clearer:

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

void getFileName(char fileName[]);
float readFile(char fileName[]);
void display(float average);

int main()
{
   char fileName[256];

   getFileName(fileName);
   float average = readFile(fileName);
   display(average);

   return 0;
}

void getFileName(char fileName[])
{
   cout << "Please enter the filename: ";
   cin  >> fileName;
}

float readFile(char fileName[])
{
   ifstream fin(fileName);

   float average = 0;

   if (fin.fail())
   {
      cout << "Error reading file \""
           << fileName
           << "\""
           << endl;
      return average = -1;

   }

   float data;
   while (fin >> data)
   {
      average += data;
   }

   if (data != 10)
   {
      cout << "ERROR reading file \""
           << fileName
           << "\""
           << endl;
      return average = -1;
   }

   fin.close();
   return average / 10;

}

void display(float average)
{

   cout.setf(ios::fixed);
   cout.precision(0);

   if (average != -1)
      cout << "Average Grade: "
           << average
           << "%"
           << endl;
}


tl;dr: everything else is working as intended, except the IF STATEMENT.
if (data != 10)

So what is data?

Hint: It's not the number of elements read from your file. If this is what you want then you need to some how count the number of elements read from the file.


Isn't data the number of elements read from the file? I thought that in the loop, data reads one element, sends to average, then reads a second element, sends to average, and so on?

If that's not it, I'm completely lost :/
Isn't data the number of elements read from the file?

Nope. It's the value read from the file.

I thought that in the loop, data reads one element,

True.

sends to average

No, it adds the value read to average (actually sum would be a better variable name at this point).

then reads a second element, sends to average, and so on?

So where in any of your description does anything keep track of the number of elements read?

If that's not it, I'm completely lost :/

Looks that way.


Ok, got it. I just created a new variable and every time a value was read it was incremented.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 float count;
   float data;
   while (fin >> data)
   {
      average += data;
      count++;
   }

   if (count != 10)
   {
      cout << "Error reading file \""
           << fileName
           << "\""
           << endl;
      return average = -1;
   }


Problem solved. Thanks everyone for the help and patience.
Topic archived. No new replies allowed.