C++: Необработанное исключение - нарушение прав доступа при записи по адресу

Нужно создать массив студентов, информация о которых приведена в файле. Студент - это класс. Проблема возникает в функции считывания данных из файла. Сам файл выглядит так:

4
Belkin 2006 75 81 92 5 4 4 5
Sokolov 2007 82 90 90 4 4 4 3
Fedorov 2006 60 61 70 5 5 5 5
Smirnov 2005 100 100 100 5 3 2 2

Его конфигурацию я могу менять. Первая строка - количество студентов, далее в каждой строке: фамилия, год рождения, 3 числа - результаты ЕГЭ и 4 числа - оценки за сессию. Для считывания из файла написал такую функцию:

student* read_st()
{
    int col;
    char s[20];
    int y;
    int e[3];
    int se[4];
    FILE* file = fopen("st.txt", "r");
    if (!file)
    {
        printf("error opening");
    }
    fscanf(file, "%d\n", &col);
    student* st = new student[col];
    for (int i = 0; i < col; i++)
    {
        fscanf(file, "%s %d %d %d %d %d %d %d %d\n", s, &y, &e[0], e[1], &e[2], &se[0], &se[1], &se[2], &se[3]);
        st->put_s(s);
        st->put_y(y);
        st->put_e(e);
        st->put_se(se);
    }
    return st;
}

Она сначала определяет количество студентов, а потом записывает нужные значения в соответствующие переменные. Строки fscanf(file, "%d\n", &col); student* st = new student[col]; работают корректно. Проблема возникает на этом этапе

 fscanf(file, "%s %d %d %d %d %d %d %d %d\n", s, &y, &e[0], e[1], &e[2], &se[0], &se[1], &se[2], &se[3]);

с первой же переменной s - вылезает необработанное исключение. Если поставить 20 перед s (%20s), ничего не меняется. При этом если сразу после %s поставить любое число или цифру (%s20, например) - проблема исчезает и появляется новая - корректно считывается фамилия, но дальнейшие переменные не заполняются. На следующем шаге цикла в s записывается следующее значение из той же строки, в данном случае - 2006, на следующем - 75 и т.д. Для параметра s нужно использовать char по условию, я пользуюсь Visual Studio 2022. Подскажите, пожалуйста, как правильно считать все значения из файла

Заработало вот так:

fscanf(file, "%s %d %d %d %d %d %d %d %d\n", s, &y, &e[0], &e[1], &e[2], &se[0], &se[1], &se[2], &se[3]);

Видимо, ошибка была в , e[1], , не было &


Ответы (1 шт):

Автор решения: Damir Hakimof

Где-то так

#include <iostream>
#include <cstdint>
#include <fstream>
#include <vector>
#include <sstream>
#include <string>

struct USE {
  uint8_t first;
  uint8_t second;
  uint8_t third;
};

struct Session {
  uint8_t first, second, third, forth;
};

class Student {
  public:
    Student(const std::string& sn, uint16_t y, USE use, Session se)
      : m_Surname(sn), 
      m_Year(y), 
      m_Use(std::move(use)), 
      m_Session(std::move(se)) {};

    auto getName() const noexcept {
      return m_Surname;
    }

    auto getYear() const noexcept {
      return m_Year;
    }

    auto getUse() const noexcept {
      return m_Use;
    }

    auto getSession() const noexcept {
      return m_Session;
    }

  private:
    std::string m_Surname = "undefined";
    uint16_t m_Year = 0;
    USE m_Use = {0, 0, 0};
    Session m_Session = {0, 0, 0, 0};
};

class VecOfStudents {
  public:
    VecOfStudents(std::ifstream& file, uint8_t col) {
      m_Students.reserve(col);

      std::string line;
      std::string name;
      uint16_t year;
      uint8_t values[7];

      while (std::getline(file, line)) {
        std::istringstream iss(line);

        iss >> name >> year;

        for (uint8_t i = 0; i < 7; ++i) {
          iss >> values[i];
        }

        m_Students.emplace_back(
          name, 
          year, 
          USE {values[0], values[1], values[2]},
          Session {values[3], values[4], values[5], values[6]}
        );
      }
    }

    auto getVec() const noexcept {
      return m_Students;
    }
  private:
    std::vector<Student> m_Students;
};

int main() {
  uint8_t col;
  std::cin >> col;

  std::ifstream file("st.txt");
  if (!file) {
    std::cout << "ERROR\n";
    return EXIT_FAILURE;
  }
  VecOfStudents ss(file, col);
  for (auto& i: ss.getVec()) {
    std::cout << i.getName() << " " << i.getYear() << " "
              << static_cast<int>(i.getUse().first) << " "
              << static_cast<int>(i.getUse().second) << " "
              << static_cast<int>(i.getUse().third) << " "
              << static_cast<int>(i.getSession().first) << " "
              << static_cast<int>(i.getSession().second) << " "
              << static_cast<int>(i.getSession().third) << " "
              << static_cast<int>(i.getSession().forth) << "\n";
  }
}

Где st.txt:

Ivanov 2000 90 85 95 4 5 4 5
Petrov 2001 80 75 85 3 4 3 4
→ Ссылка