Как вывести данные из текстового файла?(Программа студенческого табеля) - PullRequest
1 голос
/ 19 сентября 2019

В настоящее время я пишу программу, которая состоит из вывода идентификатора студента, имени, курса, кредита и оценки.Все данные находятся в этом текстовом файле:

"StudentRecords.txt"

12546 Amy   CS1 4 81 
13455 Bill  CS1 4 76
14328 Jim   CS1 4 64
14388 Henry CS3 3 80
15667 Peter CS3 3 45
12546 Amy   CS2 4 90 
13455 Bill  CS2 4 85
14328 Jim   CS2 4 71

12546 Amy   CS3 3 90 
13455 Bill  CS3 3 75
14328 Jim   CS3 3 69

Следующая таблица использовалась для расчета GPA (только для справки):

Range Grade:
90 -- 100 > 4.0
80 -- 89 > 3.0
70 -- 79 > 2.0
60 -- 69 > 1.0
0 -- 59 > 0.0

Проблема, с которой я столкнулся сейчас, - это мой вывод.Я пытаюсь сделать так, чтобы это соответствовало моему ожидаемому результату, но я не могу понять это.

Вероятно, это связано с отсутствующими операторами else if () во втором цикле for.Если кто-нибудь может дать мне несколько советов / советов о том, как заставить мой ввод работать и отображать ожидаемый результат, я был бы признателен за это!

Мой текущий код:

#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

struct Student
{
    int ID = -1;
    string Name = "";
    string Course = "";
    int Credit = -1;
    int Score = -1;
};

const int SIZE = 99;

int main()
{
    ifstream inputFile;
    string fileName = "StudentRecords.txt";
    Student studArr[SIZE];

    inputFile.open(fileName.c_str(), ios::in);

    int n = 0;

        if (inputFile.is_open())
        {
            while(!inputFile.eof())
            {
                Student st;
                inputFile >> st.ID;
                inputFile >> st.Name;
                inputFile >> st.Course;
                inputFile >> st.Credit;
                inputFile >> st.Score;
                studArr[n] = st;
                n++;
            }

            inputFile.close();
        }
        else
        {
            cout << "File cannot be opened.";
            return 1;
        }

        // sorts the array by ID and Course
        for (int i = 0; i < n; i++)
        {
            for(int j = i + 1; j < n; j++)
            {
                if(studArr[i].ID > studArr[j].ID)
                {
                    Student temp = studArr[i];
                    studArr[i] = studArr[j];
                    studArr[j] = temp;
                }
                else if(studArr[i].Course > studArr[j].Course)
                {
                    Student temp = studArr[i];
                    studArr[i] = studArr[j];
                    studArr[j] = temp;
                }
            }
        }

        int check = 0;
        float dividend = 0;
        float divisor = 0;
        for(int i = 0; i < n; i++)
        {
            if(studArr[i].ID != studArr[check].ID)
            {
                cout << "======================\nGPA " 
                     << round((dividend / divisor)) << endl << endl;
            }
            else if(i == 0)
            {
                cout << studArr[i].ID << " " << studArr[i].Name 
                     << endl << endl;
                dividend = 0;
                divisor = 0;
            }

            float gradepoints;
            if(studArr[i].Score < 60)
            {
                gradepoints = 0.0;
            }
            else if(studArr[i].Score < 70)
            {
                gradepoints = 1.0;
            }
            else if(studArr[i].Score < 80)
            {
                gradepoints = 2.0;
            }
            else if(studArr[i].Score < 90)
            {
                gradepoints = 3.0;
            }
            else if(studArr[i].Score < 100)
            {
                gradepoints = 4.0;
            }

            dividend += gradepoints * studArr[i].Credit;
            divisor += studArr[i].Credit;
            cout << studArr[i].Course << " " 
                 << studArr[i].Score << " " 
                 << gradepoints << ".0" << endl << endl;
        }
        cout << "======================\nGPA " 
             << round((dividend / divisor)) << endl << endl;
        cout << endl << endl;

        return 0;
}

Мой текущий вывод:

12546 Amy

CS1 81 3.0

CS2 90 4.0

CS3 90 4.0

======================
GPA 4

CS1 76 2.0

======================
GPA 3

CS2 85 3.0

======================
GPA 3

CS3 75 2.0

======================
GPA 3

CS1 64 1.0

======================
GPA 3

CS2 71 2.0

======================
GPA 3

CS3 69 1.0

======================
GPA 2

CS3 80 3.0

======================
GPA 3

CS3 45 0.0

======================
GPA 2

Ожидаемый результат:

12546 Amy

CS1 4 81 3.0

CS2 4 90 4.0

CS3 3 90 4.0

======================

GPA 3.64

======================
13455 Bill

CS1 4 76 2.0

CS2 4 85 3.0

CS3 3 75 2.0

======================

GPA 2.36

======================
14328 Jim

CS1 4 64 1.0

CS2 4 71 2.0

CS3 3 69 1.0

======================

GPA 1.36

======================

14388 Henry

CS3 3 80 3.0

======================

GPA 3

======================
15667 Peter

CS3 3 45 0.0

======================

GPA 0

1 Ответ

0 голосов
/ 21 сентября 2019

Есть ряд областей, в которых вещи усложняются для вас самих, но самая большая проблема связана с вашей попыткой ввода.Ваш ввод гарантированно потерпит неудачу, когда вы берете ввод с помощью:

        while(!inputFile.eof())
        {
            Student st;
            inputFile >> st.ID;
            inputFile >> st.Name;
            inputFile >> st.Course;
            inputFile >> st.Credit;
            inputFile >> st.Score;
            studArr[n] = st;
            n++;
        }

См .: Почему! .Eof () внутри условия цикла всегда неверно. .По сути, после того, как вы прочитали последнее значение VALID inputFile >> st.Score;, eofbit НЕ установлено, поэтому вы повторяете цикл снова, где inputFile >> st.ID; не удается, оставляя все значения в st неопределенными, вы не проверяете результат каждого ввода и, следовательно,Вы назначаете studArr[n] = st; повреждение вашей studArr.

Один из способов избежать попадания в эту ловушку - это написать перегрузку >> для обработки ввода для вашей структуры.В этом случае это довольно легко сделать:

struct Student {
    int ID = -1;
    std::string Name = "";
    std::string Course = "";
    int Credit = -1;
    int Score = -1;
    /* overloading the >> and << to read and write your struct helps */
    friend std::istream& operator >> (std::istream& is, Student& s) {
        is >> s.ID >> s.Name >> s.Course >> s.Credit >> s.Score;
        return is;
    }
    ...
};

Теперь чтение и проверка всех вводимых данных становится простым:

#define MAXS 99     /* if you need a constant, #define one (or more) */
...
int main (int argc, char **argv) {

    Student studArr[MAXS], tmp;
    size_t n = 0;
    std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");

    while (n < MAXS && f >> tmp)
        studArr[n++] = tmp;
    ...

Если, как и было рекомендовано, вы использовали контейнеры STL, такие каккак std::vector для хранилища вашего учащегося вместо базового типа массива, проверка будет дополнительно упрощена до while (f >> tmp) (вы также будете использовать другой метод, например .push_back(tmp) вместо прямого назначения)

сортировка входных данных, в то время как вы можете сортировать массив, в этом нет необходимости.Простой метод состоит в том, чтобы циклически перебирать данные вашего ученика и собирать уникальное значение ID в другом массиве (или векторе и т. Д.). Тогда вам нужно только зациклить уникальные идентификаторы в качестве внешнего цикла и перебрать элементы ученика.массив в качестве внутреннего цикла и обработки каждого студента, где идентификатор соответствует текущему значению внешнего цикла.Переписать логику сопоставления вашего GPA и функцию для циклического перебора массива вашего студента, выполняя то, что было описано, можно сделать следующим образом:

/* simple map GPA function that returns grade points given score */
int mapgpa (int score)
{
    if (score < 60)
        return 0;
    else if (score < 70)
        return 1;
    else if (score < 80)
        return 2;
    else if (score < 90)
        return 3;
    else if (score >= 90)
        return 4;

    return 0;
}

И логику для нахождения GPA для каждого студента:

/* a function to handle outputting the student grades
 * in your desired format.
 */
void dogrades (Student *s, size_t n)
{
    int uniqueID[MAXS] = {0};               /* array to hold unique IDs */
    size_t seen = 0;                        /* number of unique IDs seen */

    for (size_t i = 0; i < n; i++) {        /* loop collecting unique IDs */
        for (size_t j = 0; j < seen; j++)
            if (uniqueID[j] == s[i].ID)
                goto next;
        uniqueID[seen++] = s[i].ID;
        next:;
    }

    for (size_t j = 0; j < seen; j++) {     /* loop ever unique IDs */
        int heading = 0,        /* simple flag indicating name printed */
            sumcredits = 0,     /* variable to hold sum of credits */
            sumpoints = 0;      /* variable to hold sum of gradepoints */
        for (size_t i = 0; i < n; i++) {    /* loop over each stuct element */
            int gradepts = 0;               /* var to map score->gradepoits */
            if (s[i].ID == uniqueID[j]) {   /* if struct element == ID */
                if (!heading) {             /* if no heading output, do it */
                    std::cout << s[i].ID << " " << s[i].Name << "\n\n";
                    heading = 1;            /* set flag indicating done */
                }
                gradepts = mapgpa(s[i].Score);  /* get gradepts from score */
                /* output current course and gradepoints */
                std::cout << s[i].Course << " "
                        << s[i].Credit << " "
                        << s[i].Score << " "
                        << gradepts << ".0\n\n";
                sumcredits += s[i].Credit;              /* sum credits */
                sumpoints += s[i].Credit * gradepts;    /* sum gradepoints */
            }
        }
        std::cout.precision(3);     /* set precsion and output GPA */
        std::cout << "======================\n\n"
                << "GPA " << (double)sumpoints/sumcredits << "\n\n"
                << "======================\n\n";
    }
}

С вашей логикой, обработанной в функции dogrades, ваша main() уменьшается до:

int main (int argc, char **argv) {

    Student studArr[MAXS], tmp;
    size_t n = 0;
    std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");

    while (n < MAXS && f >> tmp)
        studArr[n++] = tmp;

    dogrades (studArr, n);
}

В целом, в примере, который вы можете скомпилировать, который принимает имя файла данных для чтения какпервый аргумент (или читает по умолчанию "dat/StudentRecords.txt"), вы можете сделать следующее:

#include <iostream>
#include <iomanip>
#include <fstream>

#define MAXS 99     /* if you need a constant, #define one (or more) */

struct Student {
    int ID = -1;
    std::string Name = "";
    std::string Course = "";
    int Credit = -1;
    int Score = -1;
    /* overloading the >> and << to read and write your struct helps */
    friend std::istream& operator >> (std::istream& is, Student& s) {
        is >> s.ID >> s.Name >> s.Course >> s.Credit >> s.Score;
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Student& s) {
        os << std::setw(5) << s.ID << "  "
            << std::setw(8) << std::left << s.Name << "  "
            << std::setw(5) << s.Course << "  "
                            << s.Credit << "  "
            << std::setw(3) << s.Score << '\n';
        return os;
    }
};

/* simple map GPA function that returns grade points given score */
int mapgpa (int score)
{
    if (score < 60)
        return 0;
    else if (score < 70)
        return 1;
    else if (score < 80)
        return 2;
    else if (score < 90)
        return 3;
    else if (score >= 90)
        return 4;

    return 0;
}

/* a function to handle outputting the student grades
 * in your desired format.
 */
void dogrades (Student *s, size_t n)
{
    int uniqueID[MAXS] = {0};               /* array to hold unique IDs */
    size_t seen = 0;                        /* number of unique IDs seen */

    for (size_t i = 0; i < n; i++) {        /* loop collecting unique IDs */
        for (size_t j = 0; j < seen; j++)
            if (uniqueID[j] == s[i].ID)
                goto next;
        uniqueID[seen++] = s[i].ID;
        next:;
    }

    for (size_t j = 0; j < seen; j++) {     /* loop ever unique IDs */
        int heading = 0,        /* simple flag indicating name printed */
            sumcredits = 0,     /* variable to hold sum of credits */
            sumpoints = 0;      /* variable to hold sum of gradepoints */
        for (size_t i = 0; i < n; i++) {    /* loop over each stuct element */
            int gradepts = 0;               /* var to map score->gradepoits */
            if (s[i].ID == uniqueID[j]) {   /* if struct element == ID */
                if (!heading) {             /* if no heading output, do it */
                    std::cout << s[i].ID << " " << s[i].Name << "\n\n";
                    heading = 1;            /* set flag indicating done */
                }
                gradepts = mapgpa(s[i].Score);  /* get gradepts from score */
                /* output current course and gradepoints */
                std::cout << s[i].Course << " "
                        << s[i].Credit << " "
                        << s[i].Score << " "
                        << gradepts << ".0\n\n";
                sumcredits += s[i].Credit;              /* sum credits */
                sumpoints += s[i].Credit * gradepts;    /* sum gradepoints */
            }
        }
        std::cout.precision(3);     /* set precsion and output GPA */
        std::cout << "======================\n\n"
                << "GPA " << (double)sumpoints/sumcredits << "\n\n"
                << "======================\n\n";
    }
}

int main (int argc, char **argv) {

    Student studArr[MAXS], tmp;
    size_t n = 0;
    std::ifstream f(argc > 1 ? argv[1] : "dat/StudentRecords.txt");

    while (n < MAXS && f >> tmp)
        studArr[n++] = tmp;

    dogrades (studArr, n);
}

( note: перенаправление оператора << также было добавлено вупростите вывод необработанной информации о структуре, если вам потребуется)

Пример использования / Вывод

$ ./bin/studentrecords
12546 Amy

CS1 4 81 3.0

CS2 4 90 4.0

CS3 3 90 4.0

======================

GPA 3.64

======================

13455 Bill

CS1 4 76 2.0

CS2 4 85 3.0

CS3 3 75 2.0

======================

GPA 2.36

======================

14328 Jim

CS1 4 64 1.0

CS2 4 71 2.0

CS3 3 69 1.0

======================

GPA 1.36

======================

14388 Henry

CS3 3 80 3.0

======================

GPA 3

======================

15667 Peter

CS3 3 45 0.0

======================

GPA 0

======================

Просмотрите все и дайте мне знать, если у вас есть вопросы (и серьезно подумайте об использовании контейнеров STL, таких как std::vector и std::map)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...