0

I'm trying to read how many lines there are in the file to get the number of records and compare that to the header record number indicated by the file. The readInput function works when returning true, but when removing lines in the file to make the function return false, it crashes the program.

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

struct Info
{
    string name;
    string idNum;
    int testNum;
    int* tests;
    int average;
    char grade;
};

int headRec(ifstream&);
Info* allocate(int);
bool readInput(Info* , ifstream& , int);
void displayData(Info* , int);
void deallocate(Info* , int);

int main()
{
    int record;
    string filename;
    Info* data;

    cout << "Please enter the input file name -->  ";
    cin >> filename;

    ifstream inputFile(filename.c_str());

    while (!inputFile)
    {
        cout << filename << " cannot be found. Input another file name" << endl;
        cout << "Please enter the input file name -->  ";
        cin >> filename;
        inputFile.clear();
        inputFile.open(filename.c_str());
    }

    record = headRec(inputFile);

    if (record == 0)
    {
        cout << "Error. Program Ending";
        exit(0);
    }

    data = allocate(record);

    if (data == nullptr)
    {
        cout << "Memory Allocation Error. Program Ending";
        exit(0);
    }

    if (readInput(data, inputFile, record) == false)
    {
        cout << "Program Ending";
    }

    displayData(data, record);

    deallocate(data, record);

    cout << "\nPress Enter to end -->  ";
    cin.ignore();
    cin.ignore();

    return 0;
}

int headRec(ifstream& inputFile)
{
    int record = 0;

    inputFile >> record;

    if (record < 5)
    {
        return record = 0;
    }

    return record;

}

Info* allocate(int record)
{
    Info* data = new Info[record];
    return data;
}

bool readInput(Info* data, ifstream& inputFile, int record)
{
    int total = 0, end = 0;
    char c;

    for (int i = 0; i < record; i++)
    {
        inputFile >> data[i].name;
        inputFile >> data[i].idNum;
        inputFile >> data[i].testNum;
        data[i].tests = new int[data[i].testNum];

        for (int j = 0; j < data[i].testNum; j++)
        {
            inputFile >> data[i].tests[j];
            total += data[i].tests[j];
        }

        inputFile.get(c);
        data[i].average = total / data[i].testNum;
        total = 0;

        if (data[i].average < 60)
            data[i].grade = 'F';
        else if (data[i].average <= 70)
            data[i].grade = 'D';
        else if (data[i].average <= 80)
            data[i].grade = 'C';
        else if (data[i].average <= 90)
            data[i].grade = 'B';
        else
            data[i].grade = 'A';
        if (c == '\n')
            end++;
    }

    cout << end;
    cout << record;

    if (end == record)
        return true;
    else
        return false;
}

void displayData(Info* data, int record)
{
    for (int i = 0; i < record; i++)
    {
        cout << "\nName:  " << data[i].name;
        cout << "\tID Number:  " << data[i].idNum << endl;
        cout << "Test Scores:  ";
        for (int j = 0; j < data[i].testNum; j++)
        {
            cout << data[i].tests[j] << " ";
        }

        cout << endl;

        cout << "Average:  " << data[i].average;
        cout << "\tGrade:  " << data[i].grade << endl;
    }
}

void deallocate(Info* data, int record)
{
    for (int i = 0; i < record; i++)
        delete[] data[i].tests;

    delete[] data;
}

This is what the file contains:

10

Mark      2345A78  6  78 67 98 34 78 69
Emily     3246B59  5  89 56 74 59 98
Yao       8942A85  7  98 75 69 89 85 78 95
Claudette 6587C69  5  56 45 63 75 60
Niklos    5874B58  6  69 68 52 69 75 74
Channah   4587B32  7  98 95 100 96 89 96 94
Parissa   8524C84  5  98 96 85 91 90
Rodrick   9856C65  5  56 75 84 65 75
Chance    5648A67  6  100 89 96 89 82 86
Melissa   8786C78  5  80 63 75 77 72
Niels     4854A78  6  48 56 85 65 42 75
Jongware
  • 21,058
  • 8
  • 43
  • 86
  • Please format your code. –  Dec 09 '13 at 22:14
  • Sorry about that! Fixed formatting. – user3084653 Dec 09 '13 at 22:19
  • 1
    Not an answer to your problem, but `exit(0)` on error is not good practice. You should have a different value, >0, for each error, `exit(0)` is supposed to mean NO ERROR. – KeithSmith Dec 09 '13 at 22:27
  • @KeithSmith No, that code is correct. Open sets `ios_base::failbit` on failure, which will reflect in the boolean evaluation of `!inputfile`. It has nothing to do with being on the stack or heap. – 0x499602D2 Dec 09 '13 at 22:33
  • @0x499602D2. My mistake. Will remove comment. – KeithSmith Dec 09 '13 at 22:35
  • The program will end before that function is read in that case Keith. – user3084653 Dec 09 '13 at 22:36
  • @user3084653 Just not my day. Sorry. – KeithSmith Dec 09 '13 at 22:38
  • When reading the file, you read it using the value in the header (`record`). If you remove some lines, you will attempt to read but the file is already in the EOF. What is the expected behavior for ifstream when that happens? BTW, internally you could loop until the end of file and check the number of records it reads. – wendelbsilva Dec 09 '13 at 22:40
  • An error I would assume...how would I remedy that? It's truly escaping my thoughts. – user3084653 Dec 09 '13 at 22:42
  • Can I do that and still read the data into the structure? If so how? >.< Thank you guys so much for your time. – user3084653 Dec 09 '13 at 22:43
  • Inside the loop, the first time you read, if its the EOF it will return false (according to [this](http://stackoverflow.com/questions/4533063/how-does-does-ifstream-eof-work).). So I think you could check that to leave the loop. – wendelbsilva Dec 09 '13 at 22:44
  • Hmm...I think I got it! I added inputFile.good() in the first line of the outer for loop. Thank you so much everyone! – user3084653 Dec 09 '13 at 23:03

1 Answers1

0

You never check for 'eof' in your read loop in readInput(). This means you have garbage values (perhaps 0) for these lines after you hit eof:

    inputFile >> data[i].name;
    inputFile >> data[i].idNum;
    inputFile >> data[i].testNum;

Then what do you suppose is going to happen here, if data[i].testNum is zero?

    data[i].average = total / data[i].testNum;

You might consider checking inputFile.good() before each read from the stream, and handle it appropriately when it returns false.

Markku K.
  • 3,592
  • 17
  • 19