После открытия пишет "прекращена работа программы"

После открытия пишет "прекращена работа программы"

Нужно ввести количество оценок (по 12-бальной шкале) за какой-то период, после чего найти среднее значение. Затем нужно разбить результат на 4 группы. Например, если среднее значение 4,5, то нужно вывести на экран «2». Компилирует нормально, но после запуска пишет «прекращена работа программы». В чем проблема? Я тут новичок.

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int n;
    int arr[n];
    cout<<"Elementov massiva:";
    cin>>n;
    int sum=0;
    for (int i=0; i<n; i++) {
      cout<<"["<<i+1<<"]:";
      cin>>arr[i];  
    }
    cout<<"Massiv:";
    for (int i=0; i<n; i++) {
      cout<<arr[i]<<" ";
    }
    for (int i=0; i<n; i++) {
      sum+=arr[i];
    }
    int avg=sum/n;
    cout<<"Srednee:"<<avg<<endl;
    if (1<=avg<=3) {
      cout<<"1";
    }
    if (4<=avg<=6) {
      cout<<"2";
    }
    if (7<=avg<=9) {
      cout<<"3";
    }
    if (10<=avg<=12) {
      cout<<"4";
    }
    return 0;
}

Urgantvirus3871, извини, на счёт врёшь — погорячился. Однако, программа содержит одну ошибку не совместимую с жизнью и минимум 4 предупреждения. Я очень удивлён, что хвалёный GCC с дефолтными настройками компиляции даже предупреждений не даёт ((

Ошибка:

    int n;
    int arr[n];    // <--

По стандарту языка при объявлении массива в квадратных скобках должно быть указано константное выражение интегрального типа большее 0. Т.е. во время компиляции размер массива должен быть известен. На основе известного размера массива и типа элементов массива компилятор генерирует команды для выделения места под массив. В данном случае, вопреки стандарту, GCC выделяет какой-то объём памяти под массив с неизвестным ему размером. Если при работе с этим массивом ты выйдешь за его границу, которую ты не знаешь, то почти 100%-но получишь крах программы. Что, видимо, ты и наблюдаешь.

Лечение. Использовать для массива динамическое выделение/освобождение памяти. Или использовать один из контейнеров STL, например vector.

Предупреждения:

    if (1<=avg<=3) {   // <--
      cout<<"1";
    }

Эта конструкция не будет работать ожидаемым тобой образом. Обычно компиляторы на такие вещи выдают предупреждения. В if написанное тобой условие эквивалентно следующему:

if (int(1 <= avg) <= 3) ...

Т.е. сначала выполняется сравнение avg с первым числом. Результат булевского типа неявно приводится к типу int (тип второго операнда второй операции сравнения). Результатом приведения к целому будет 0 для false и 1 для true. Затем выполняется второе сравнение с очевидным результатом.

Лечение.

if (1 <= avg && avg <= 3) ...

Ещё настоятельно рекомендую в настройках проекта в IDE выставить разрешение вывода всех предупреждений. От граблей оно тебя не избавит, но хотя бы к ним будет флажок привязан ))

Cranium, это не баг GCC, а фича. Плюс ко всему, стандарт C99 допускает автоматическое выделение памяти под массив переменной длины.

https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C90 mode and in C++.

Угу... только с помощью этой фичи нога отстреливается по самые гланды. Что ТС и испытал.

Кстати, про отсутствие бага я бы поспорил. Стандарт C99 мне искать лениво, но в доке по GCC во всех примерах в рантайме размер массива таки вычисляется. Здесь же переменная n объявляется без инициализации. Если уж есть такая фича, то компилятор должен был хотя бы предупреждение выдать, что переменная неинициализирована. А так, какого размера массив выделяется?

Вообще-то говоря, все фичи в компиляторах — от Лукавого. Есть Стандарт. Компилятор обязан ему следовать. Если я хочу использовать какую-то фичу конкретного компилятора, то я должен каким-то образом явно это указать (ключом, прагмой и т.п.). Именно так, а не наоборот, как это реализовано в GCC: есть фичи, но что бы по стандарту, необходимо указать соотв. ключ. Кроме того, использование фичей компилятора делает код непереносимым.

В стандартах есть такие понятия, как неопределенное и допустимое поведение.
То, как такие вещи реализуются — дело того, кто это реализует.

В стандарте C++11 (ISO/IEC 14882:2011 п. 8.3.4) про размер в объявлении массива совершенно чётко сказано

If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.

без всяких оговорок на implementation dependent.

То, что в C99 можно объявлять массивы с неконстантным размером, здесь неприменимо. Это другой язык.

При компиляции с флагом -pedantic компилятор выдает предупреждение.

warning: ISO C++ forbids variable length array ‘array’.

В C++ 14, кстати массивы переменной длины будут поддерживаться.
Я думаю, что по умолчанию эту опцию оставили включенной как расширение как раз из-за сохранения совместимости со старым кодом.

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

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.