295 / 124 / 106
Регистрация: 30.10.2015
Сообщений: 690
1

Вывести фамилии неуспевающих учеников

24.04.2016, 09:57. Показов 1517. Ответов 7
Метки нет (Все метки)

Решил для себя порешать задачи из ЕГЭ, столкнулся с проблемой.

Условие.
Кликните здесь для просмотра всего текста

На вход программе подаются сведения о сдаче экзаменов учениками 9-х классов некоторой средней школы. В первой строке сообщается количество учеников N, которое не меньше 10, но не превосходит 100, каждая из следующих N строк имеет следующий формат: <Фамилия> <Имя> <оценки>, где <Фамилия> - строка, состоящая не более чем из 20 символов, <Имя> — строка, состоящая не более чем из 15 символов, <оценки> - через пробел три целых числа, соответствующие оценкам по пятибалльной системе. <Фамилия> и <Имя>, а также <Имя> и <оценки> разделены одним пробелом. Пример входной строки:
Ива*нов Петр 4 2 4

Требуется написать как можно более эффективную программу (укажите используемую версию языка программирования, например, Borland Pascal 7.0), которая будет выводить на экран фамилии и имена неуспевающих учеников (имеющих по результатам экзаменов хотя бы одну двойку), располагая их в порядке уменьшения числа двоек.


Программа.
Кликните здесь для просмотра всего текста

C++
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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
 
 
 
struct Losers
{
  int number ;
  std :: string name ;
  std :: string lastname ;
} ;
 
 
 
int main ( void )
{
  std :: vector <Losers> losNL ( 1 ) ;
 
  int numbers ;
  int evaluationOne ;
  int evaluationTwo ;
  int evaluationThree ;
  std :: string name ;
  std :: string lastname ;
 
  std :: cin >> numbers ;
 
  for ( int i = 0; i < numbers; ++ i ) {
    std :: cin >> name ;
    std :: cin >> lastname ;
    std :: cin >> evaluationOne >> evaluationTwo >> evaluationThree ;
 
    if ( evaluationOne == 2 || evaluationTwo == 2 || evaluationThree == 2 ) {
      if ( evaluationOne == 2 ) {
        ++losNL [ i ].number ;     
      }
 
      if ( evaluationTwo == 2 ) {
        ++losNL [ i ].number ;
      }
  
      if ( evaluationThree == 2 ) {
        ++losNL [ i ].number ;
      }
 
      losNL [ i ].name = name ;
      losNL [ i ].lastname = lastname ;
      losNL.resize ( losNL.size () + 1 ) ;
    } 
  }
 
  std :: sort ( losNL.begin (), losNL.end (), []( const Losers & a, const Losers & b ) {
    return a.number > b.number ;
  }) ;
 
  for ( int i = 0; i < losNL.size () - 1; ++i ) {
    std :: cout << losNL [ i ].name << " "  << losNL [ i ].lastname << std :: endl ; 
  }
 
 
  return 0 ;
}

При вводе таких данных :
n n 2 2 2
e e 4 4 4
n n 2 2 2

Ошибка сегментирования (сделан дамп памяти)

Не пойму в чем проблема.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
24.04.2016, 09:57
Ответы с готовыми решениями:

В массиве хранятся сведения об оценках 25 учеников по химии. Определить порядковые номера неуспевающих по химии учеников
В массиве хранятся сведения об оценках 25 учеников по химии. Определить порядковые номера...

Структуры: вывести фамилии трех лучших учеников данного класса
Анкета школьника включает в себя Ф.И.О., номер школы, номер класса и оценки по пяти предметам....

Вывести фамилии и имена трех худших по среднему баллу учеников
На вход программе подаются сведения о сдаче экзаменов учениками 9-х классов некоторой средней...

Вывести фамилии и имена трех худших по среднему баллу учеников
На вход программе подаются сведения о сдаче экзаменов учениками 9-х классов некоторой средней...

7
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
24.04.2016, 11:16 2
первое важное - при создании объекта Losers твое интовое поле забито мусором, это происходит из-за того, что структура является Plain Old Data типом. сами правила довольно сложные, так что просто добавь например такой конструктор:
C++
1
2
3
4
5
6
7
struct Losers
{
    Losers() : number() {}
    int number;
    std::string name;
    std::string lastname;
};
ну и ошибка здесь в том, что если ни одной двойки нет, то не происходит ресайз вектора. после того как ты вводишь данные хорошиста, без ресайза вектор по-прежнему из двух элементов, далее попытка обратиться к несуществующему.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    for (int i = 0; i < numbers; ++i) {
        std::cin >> name;
        std::cin >> lastname;
        std::cin >> evaluationOne >> evaluationTwo >> evaluationThree;
 
        if (evaluationOne == 2 || evaluationTwo == 2 || evaluationThree == 2) {
            if (evaluationOne == 2) {
                ++losNL[i].number;
            }
 
            if (evaluationTwo == 2) {
                ++losNL[i].number;
            }
 
            if (evaluationThree == 2) {
                ++losNL[i].number;
            }
 
            losNL[i].name = name;
            losNL[i].lastname = lastname;
        }
 
        losNL.resize(losNL.size() + 1); // <-- тут
    }
Добавлено через 13 минут
а вот кстати я дурак и запутался, помогите.
resize же гарантирует value-инициализацию для объектов, так что рекурсивно ко всем полям должна быть применена она же, а value для инта есть zero-инициализация. и пофигу вроде POD или нет. для одиннадцатого и выше я так и не разобрался с этими тривиал и лейаут..
почему там мусор?
1
295 / 124 / 106
Регистрация: 30.10.2015
Сообщений: 690
24.04.2016, 15:12  [ТС] 3
Цитата Сообщение от Babysitter Посмотреть сообщение
ну и ошибка здесь в том, что если ни одной двойки нет, то не происходит ресайз вектора.
Ну так мне и не нужно увеличивать размер, когда нет ни одной двойки. Ведь я записываю только двоечников. Или я не понимаю чего-то?
0
161 / 153 / 92
Регистрация: 18.11.2015
Сообщений: 677
24.04.2016, 16:31 4
Лучший ответ Сообщение было отмечено Nemovok как решение

Решение

У тебя неправильно задание выполнено. Сказано, что имя должно быть не больше 15 символов, фамилия - не больше 20 символов, ты это не проверяешь. Сказано, что оценка должна соответствовать пятибалльной шкале, ты это не проверяешь. Сказано, что нужно написать как можно более эффективную программу, у тебя она будет ломаться каждый раз, когда в оценку введут дробь или какой-то символ, не являющийся цифрой. Короче, скорее всего, 0 баллов дадут на ЕГЭ за эту прогу.

У меня вот так вышло:
C++
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
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#define NOMINMAX
#include <windows.h>
#include <conio.h>
 
const int grades_total = 3;
 
class Student {
private:
    std::string name;
    std::string last_name;
    std::vector<int> grades;
    int dvoyki_amount;
 
public:
    Student() { for (int i(0); i < grades_total; i++) grades.push_back(0); dvoyki_amount = 0; }
 
    void getInput() {
        bool wrongInput = false;
        do {
            wrongInput = false;
 
            if (!(std::cin >> last_name >> name >> grades[0] >> grades[1] >> grades[2])) {
                std::cin.ignore(std::numeric_limits<int>::max(), '\n');
                std::cin.clear();
                wrongInput = true;
            }
            std::cin.ignore(std::numeric_limits<int>::max(), '\n');
 
            if (last_name.size() >= 15 || last_name.empty()) wrongInput = true;
            if (name.size() >= 20 || name.empty()) wrongInput = true;
 
            for (int i(0); i < grades_total; i++) {
                if (grades[i] > 5 || grades[i] < 1) {
                    wrongInput = true;
                    break;
                }
                if (grades[i] == 2) dvoyki_amount++;
            }
 
            if (wrongInput) std::cout << "\nВы ввели некорректные данные! Попробуйте снова!\n\n";
 
        } while (wrongInput);
    }
 
    void showData() {
        std::cout << last_name << " " << name << " ";
 
        for (int i(0); i < grades_total; i++)
            std::cout << grades[i] << " ";
 
        std::cout << "\n";
    }
 
    int getDvoyki() { return dvoyki_amount; }
};
 
bool myCompare(Student s1, Student s2) {
    return (s1.getDvoyki() > s2.getDvoyki());
}
 
int main() {
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    int num_of_students;
    while (!(std::cin >> num_of_students) || (std::cin.peek() != '\n') || num_of_students < 10 || num_of_students > 100) {
        std::cout << "Неверные данные! Попробуйте снова!\n";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<int>::max(), '\n');
    }
    std::cin.ignore(std::numeric_limits<int>::max(), '\n');
 
    std::vector<Student> students(num_of_students);
 
    for (int i(0); i < num_of_students; i++)
        students[i].getInput();
 
    std::sort(begin(students), end(students), myCompare);
 
    std::cout << "\n\n\nОтвет:\n\n";
    for (int i(0); i < num_of_students; i++) {
        if (students[i].getDvoyki() > 0)
            students[i].showData();
    }
 
    _getch();
}
Она, вроде, везде работает без ошибок. Проверь. Сначала кол-во сдающих экзамен вводишь, потом инфу о сдающих. Можешь добавить какие-нибудь красотульки для ввода, но я чисто по заданию сделал)

Кстати, там про единичку (оценку) ничего не сказано, так что единичка не означает в моей проге, что это двоечник XD
1
295 / 124 / 106
Регистрация: 30.10.2015
Сообщений: 690
24.04.2016, 16:49  [ТС] 5
Цитата Сообщение от meJevin Посмотреть сообщение
У тебя неправильно задание выполнено.
Я же не сказал, что уже доделал задание И интересно, сколько времени уйдет на выполнение этой задачи на листочке и сколько там ошибок будет
0
161 / 153 / 92
Регистрация: 18.11.2015
Сообщений: 677
24.04.2016, 16:56 6
Nemovok, я не знаю, тот код я написал "за один заход". Пришлось, правда, переделать немножко проверку на ошибки, а остальное все работало прекрасно. То есть 2 раза компилировал. Тем более, на написание ЕГЭ много времени дают, можно несколько раз (если не несколько десятков раз) проверить свою программу на ошибки.

Кстати, а там не дают компьютер, чтобы на нем написать программу? Ну, с открытым блокнотиком хотя бы. Именно на листочке нужно писать все?
0
295 / 124 / 106
Регистрация: 30.10.2015
Сообщений: 690
24.04.2016, 16:59  [ТС] 7
Там ручка и листочек И больше ничего.
0
245 / 139 / 53
Регистрация: 23.11.2015
Сообщений: 394
25.04.2016, 11:07 8
Nemovok, я не пытаюсь решать твою задачу, просто показываю, где очевидная ошибка. я рассчитываю, что логику работы ты сам уже поправишь.
итерации:
i = 0 в векторе один элемент(нулевой), ты вводишь двойки и в losNL[0] их инкрементишь, молодец. _ресайз_
i = 1 в векторе два элемента(нулевой/первый), ты вводишь четверки, с ними ничего не делаешь, ресайза нет
i = 2 в векторе все также два элемента(нулевой/первый), ты вводишь двойки, и пытаешься достучаться до losNL[2], а его не существует.

Добавлено через 17 часов 44 минуты
Цитата Сообщение от Babysitter Посмотреть сообщение
resize же гарантирует value-инициализацию для объектов, так что рекурсивно ко всем полям должна быть применена она же, а value для инта есть zero-инициализация. и пофигу вроде POD или нет. для одиннадцатого и выше я так и не разобрался с этими тривиал и лейаут..
попробовал сам разобраться - немного покапитаню. такая структура
C++
1
2
3
4
5
6
struct Losers
{
  int number ;
  std :: string name ;
  std :: string lastname ;
};
кончено не является никакой POD, так как у нее есть поля типа не-POD (std::string).
как я и говорил, гарантировано должна происходить value-инициализация, мы попадаем сюда
Кликните здесь для просмотра всего текста
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object
is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is
called.

и да, он не trivial потому что у его полей(std::string) нетривиальные конструкторы
Кликните здесь для просмотра всего текста
A default constructor is trivial if it is not user-provided and if:
— its class has no virtual functions (10.3) and no virtual base classes (10.1), and
— no non-static data member of its class has a brace-or-equal-initializer, and
— all the direct base classes of its class have trivial default constructors, and
for all the non-static data members of its class that are of class type (or array thereof), each such class
has a trivial default constructor.


то есть вместо zero-инициализации, мы получаем вызов неявного дефолтного конструктора, который в свою очередь выполняет default-инициализацию для каждого поля.

кратко:
Кликните здесь для просмотра всего текста
(Losers) vector element value initialization -> implicitly-declared default constructor
(int) number default initialization -> no initialization is performed for scalar type
(string) name and lastname default initialization -> the default constructor for string is called
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.04.2016, 11:07
Помогаю со студенческими работами здесь

Определить количество неуспевающих учеников
В массиве хранятся сведения об оценках 25 учеников по химии.определить количество неуспевающих...

Вывести на экран фамилии и имена трех худших по среднему баллу учеников
задача На вход программе подаются сведения о сдаче экзаменов учениками 9-х классов некоторой...

Дан вес и рост учеников. Выведите на экран фамилии учеников, которые ниже 160см и весом меньше 60кг
Подскажите как можно решить данную задачу: Дан вес и рост учеников. Выведите на экран фамилии...

Файл содержит фамилии и 4 оценки. Удалить из списка неуспевающих
Файл содержит фамилии и 4 оценки у каждого. Удалить из списка неуспевающих


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru