Бритуля - Богиня
Всем привет!
Сегодня мы поговорим об ошибках. Как я упоминал чуть ранее, это очень важная тема и я хочу осветить ее в самом начале пути.
Прежде, чем начать, как я и обещал в предыдущей лекции:
решение домашнего задания с предыдущей лекции
Напоминаю условие:
1. Программа получает с клавиатуры количество парт в классе.
2. Программа получает с клавиатуры количество учеников за одной партой.
3. Дано: за всеми партами сидит одинаковое количество учеников (то есть НЕ может быть ситуации, в которой за одной партой сидит 2 ученика, а за другой - только один)
4. Программа выводит ответ на экран (консоль).
решение
Несколько замечаний:
1. Не выполняется проверка правильности ввода данных с клавиатуры. Это простительно нам, так как мы еще не умеем, НО как только мы научимся - такую халатность допускать нельзя!
2. Посмотрите на способ, которым я объявил переменные. Я объявил 2 int-а, при этом написав слово int один раз, а далее перечислил имена через запятую. Такой способ объявления возможен и я хочу, чтобы вы познакомились с ним.
3. Я присвоил переменным начальные параметры, обнулив их. ВСЕГДА поступайте так и вы избежите многих проблем!
4. Присмотритесь к строке cout: я провел вычисления прямо в этой строке. Это допустимый способ. Программа вначале сделает вычисления, а уже потом выдаст их на экран. Если программист не уверен, какое действие выполнится раньше, он берет в круглые скобки то выражение, которое нужно выполнить в первую очередь. Это гарантирует заданный порядок.
Совет: всегда, когда я буду давать задания, я буду выкладывать свой вариант решения этого задания. ДАЖЕ если задание вам показалось легким, я советую проанализировать мой вариант. Иногда вы найдете там новый трюк, иногда - более элегантное решение... возможно, мое решение будет непонятным или спорным и тогда, задав вопрос в теме, вы получите исчерпывающий ответ, который, возможно, научит чему-нибудь полезному. Смотреть на решение других программистов - залог успеха!
сегодняшняя лекцияПрактически невозможно написать программу, которая, с момента ее написания и до скончания веков не будет иметь ни одной ошибки (если это конечно не "Hello World"). Программист должен уметь находить и чинить ошибки, а так же его программа должна уметь реагировать на нестандартные ситуации. Приведу пример: допустим, из-за неумелых действий или невнимательности пользователя, либо по стечению обстоятельств программа попала в нестандартную ситуацию. Например, программа попросила пользователя ввести число, а он, по невнимательности ввел звездочку....
Если программа написана так, что подобные ситуации не учтены, то ее поведение будет непредсказуемым: она может "зависнуть", "упасть" или выдать неправильный результат. Так как человек не склонен винить себя, он ищет других виновников, то следующий вывод, который он сделает: "паршивая программа, которую писал криворукий дурак". Я скажу больше: я полностью согласен с таким выводом! Каким бы гениальным не был бы алгоритм, если программа падает при первой же ошибке - такая программа не стОит ни гроша.
Нужно взять за железное правило: НЕЛЬЗЯ полагаться на правильность действий пользователя - НИ В КОЕМ СЛУЧАЕ! Именно поэтому, основная масса кода, которую вы будете писать - это код, который проверяет наличие ошибок и предотвращает непредсказуемое поведение программы. По сравнению с объемом написанного кода с этой целью, код, который непосредственно выполняет задачу, поставленную перед программой - обычно, как минимум, вдвое меньше по объему.
Итак, мотивирующая часть беседы окончена, перейдем к практике. Я разделяю ошибки на 3 основных типа: синтаксические ошибки, логические ошибки (баги) и исключительные случаи. Об этих типах мы и поговорим.
Синтаксические ошибки это такой тип ошибок, при которых программа просто не скомпилируется. Компилятор, кроме непосредсвенно перевода текста в бинарный код, занимается еще очень важным делом: он проверяет, что то, что вы написали - соответствует правилам языка. Допустим код:

Это уже знакомый нам код, с предыдущей лекции, который я немного "исправил". Если мы попробуем скомпилировать код в таком виде - компилятор откажет нам. Давайте разберем ошибки в коде. Тут их 3.
1. переменная "input_from_user" используется в коде, но она - не объявлена. Но пока компилятор "не видит" этой проблемы, потому что есть другие проблемы, которые сбили его с толку. Как только мы починим "другие проблемы" - он сразу же увидит эту.
2. в конце строки cout отсутствует точка с запятой.
3. во втором cout между "your input is: " и input_from_user нет разделителя <<
Это прекрасно, скажете вы, потому что я сделал эти ошибки специально и поэтому я знаю, на что обратить внимание. А как быть, если ошибка случайно допущена? Хорошо, что Эклипс умеет подчеркивать проблемные места, а как быть, если мы работаем в редакторе, который не умеет это делать? (есть такие)
Давайте перепишем этот код, как написал его я и попробуем скомпилировать. После этого обратим внимание на консоль: там написаны все найденные ошибки. И это пишет уже не Эклипс, а наш компилятор:

Всмотритесь, в то, что он написал. В последних строках присутствует слово "error" ("ошибка" по-английски). Компилятор не просто нашел ошибки, а даже попытался предположить в чем они. Нашел он пока только две: 2-ю и 3-ю, первая не была найдена по причине, описанной выше.
2-я ошибка: "../src/first_programm.cpp:14:2: error: expected ‘;’ before ‘cin’" - он угадал. Действительно на 14-й строке кода перед оператором cin он не нашел точку с запятой. Объясню логику: он знает, что оператор "cin" - это самостоятельный оператор, который обязан начинаться с новой строки. Для компилятора новая строка начинается сразу после точки с запятой.
То есть, если бы мы написали: cout << "please, give me digit: "; cin >> input_from_user; - в одну строку, то это НЕ БЫЛО бы ошибкой, так как точка с запятой - присутствует! Мы переносим строку только для удобства чтения, можно (но не советуется) писать программы не перенося строки вообще, НО точка с запятой - быть обязана.
Думаю, что теперь сообщение компилятора становится более понятным.
Однако, 3-я ошибка немного не понятна... мы знаем, что не хватает символа "<<", однако, компилятор думает, что не хватает точки с запятой... дело в том, что компилятор "перевел" то, что мы написали примерно так:
cout << endl << "your input is: ";
input_from_user << endl;
то есть для него пока картина ясна: закончился оператор "cout", а после него пошел другой оператор input_from_user, к которому, ВОЗМОЖНО, тоже можно обратиться через "<<" (можно или нет, он пока не проверял). НО! как только мы сделаем то, что говорит нам компилятор и поставим между ними точку с запятой, он полезет проверять законность такого обращения и выдаст другую ошибку, в которой скажет, что к input_from_user нельзя обращаться через оператор "<<"
Теперь, давайте немного познакомимся с возможностями Эклипса. Напротив строк, отмеченных красным появился рисунок жучка. То есть, этим рисунком Эклипс говорит нам: "тут есть ошибка, но кажется я знаю ее решение. Позволь мне починить ее автоматом" и при нажатии на жука он выдаст описание того, как именно он собирается чинить проблему. Иногда он угадывает и чинит правильно, иногда - нет.
Вывод, который можно сделать из всего написанного: при возникновении синтаксической ошибки всмотритесь в код, и не только, в указанную строку, но и на то, что написано на соседних строках и попытайтесь понять, в чем именно ошибка. Умение сразу определять в чем именно ошибка - приходит с опытом и ТОЛЬКО так... тут никаких "универсальных советов", кроме как "включить мозг и протереть глаза" быть не может! Компьютер может быть внимательней человека, но быть умнее человека - ему не дано)))
Совет: поиграйтесь немного с кодом, который у вас уже есть. Попробуйте, что будет, если допустить ту или иную ошибку. Попробуйте возможности Эклипса чинить эти ошибки.... в будущем, эти познания и опыт могут серьезно облегчить жизнь. Синтаксические ошибки не должны отнимать много времени, потому что это время ценно для отлова логических ошибок!
Логические ошибки еще называют багами. Баг (англ. Bug) - это жук. Это название пошло с тех времен, когда компьютеры работали на светодиодах и занимали, по размеру, сотни квадратных метров. Один из таких начал выдавать ужасные ошибки и когда его проверили, то обнаружилось, что на одном из светодиодов сдох жук, закрыв диод своим телом. Это история.
Чтобы ОЧЕНЬ понятно объяснить что такое баг, я приведу пример: программа высчитывает расстояние, которое прошел поезд:

и результат расчетов программы:

Но любой школьник вам скажет: "Позвольте! Скорость поезда 100 км/ч, время езды - 2 часа... выходит, что пройденное расстояние равно 200 км! Откуда 20 тысяч???"
И он прав! Программист, вместо того, чтобы умножить скорость на время, умножил время на вес поезда! Компилятор даже носом не повел! Он не умеет анализировать логику программы, а с точки зрения синтаксиса - она написана идеально.... Вот это и есть - баг.
Способ отлова таких ошибок только один - внимательный анализ кода! Прежде, чем программист выпустит программу "в свет" он обязан ее протестировать во всех ситуациях, которые придут ему на ум и каждый раз, частенько с калькулятором в руках - проверять результаты работы программы. Это работает только так!
На предприятиях есть целый отдел, вся работа которого заключается в том, что они целый день тестируют программы, написанные их программистами и стараются их вывести из строя ЛЮБЫМИ способами. Такой отдел называется QA.
Думаю, что с логическими ошибками тоже все ясно)))
Чуть выше я сказал фразу:
"...Именно поэтому, основная масса кода, которую вы будете писать - это код, который проверяет наличие ошибок и предотвращает непредсказуемое поведение программы. По сравнению с объемом написанного кода с этой целью, код, который непосредственно выполняет задачу, поставленную перед программой - обычно, как минимум, вдвое меньше по объему."
Но читатель может заметить: позвольте, а где здесь можно с помощью написания кода предотвратить появление всех этих ошибок? Дело в том, что сказав эту фразу я имел ввиду ошибки из типа "исключительные случаи".
В С++ существует 2 способа обработки исключительных случаев. НО! Пока мы рассматривать их не будем, потому что у нас пока не достаточно знаний для этой цели. Поэтому, наберемся терпения и я вам обещаю, что мы еще не раз вернемся к теме ошибок.
Сегодня мы поговорим об ошибках. Как я упоминал чуть ранее, это очень важная тема и я хочу осветить ее в самом начале пути.
Прежде, чем начать, как я и обещал в предыдущей лекции:
решение домашнего задания с предыдущей лекции
Напоминаю условие:
1. Программа получает с клавиатуры количество парт в классе.
2. Программа получает с клавиатуры количество учеников за одной партой.
3. Дано: за всеми партами сидит одинаковое количество учеников (то есть НЕ может быть ситуации, в которой за одной партой сидит 2 ученика, а за другой - только один)
4. Программа выводит ответ на экран (консоль).
решение

Несколько замечаний:
1. Не выполняется проверка правильности ввода данных с клавиатуры. Это простительно нам, так как мы еще не умеем, НО как только мы научимся - такую халатность допускать нельзя!
2. Посмотрите на способ, которым я объявил переменные. Я объявил 2 int-а, при этом написав слово int один раз, а далее перечислил имена через запятую. Такой способ объявления возможен и я хочу, чтобы вы познакомились с ним.
3. Я присвоил переменным начальные параметры, обнулив их. ВСЕГДА поступайте так и вы избежите многих проблем!
4. Присмотритесь к строке cout: я провел вычисления прямо в этой строке. Это допустимый способ. Программа вначале сделает вычисления, а уже потом выдаст их на экран. Если программист не уверен, какое действие выполнится раньше, он берет в круглые скобки то выражение, которое нужно выполнить в первую очередь. Это гарантирует заданный порядок.
Совет: всегда, когда я буду давать задания, я буду выкладывать свой вариант решения этого задания. ДАЖЕ если задание вам показалось легким, я советую проанализировать мой вариант. Иногда вы найдете там новый трюк, иногда - более элегантное решение... возможно, мое решение будет непонятным или спорным и тогда, задав вопрос в теме, вы получите исчерпывающий ответ, который, возможно, научит чему-нибудь полезному. Смотреть на решение других программистов - залог успеха!
сегодняшняя лекцияПрактически невозможно написать программу, которая, с момента ее написания и до скончания веков не будет иметь ни одной ошибки (если это конечно не "Hello World"). Программист должен уметь находить и чинить ошибки, а так же его программа должна уметь реагировать на нестандартные ситуации. Приведу пример: допустим, из-за неумелых действий или невнимательности пользователя, либо по стечению обстоятельств программа попала в нестандартную ситуацию. Например, программа попросила пользователя ввести число, а он, по невнимательности ввел звездочку....
Если программа написана так, что подобные ситуации не учтены, то ее поведение будет непредсказуемым: она может "зависнуть", "упасть" или выдать неправильный результат. Так как человек не склонен винить себя, он ищет других виновников, то следующий вывод, который он сделает: "паршивая программа, которую писал криворукий дурак". Я скажу больше: я полностью согласен с таким выводом! Каким бы гениальным не был бы алгоритм, если программа падает при первой же ошибке - такая программа не стОит ни гроша.
Нужно взять за железное правило: НЕЛЬЗЯ полагаться на правильность действий пользователя - НИ В КОЕМ СЛУЧАЕ! Именно поэтому, основная масса кода, которую вы будете писать - это код, который проверяет наличие ошибок и предотвращает непредсказуемое поведение программы. По сравнению с объемом написанного кода с этой целью, код, который непосредственно выполняет задачу, поставленную перед программой - обычно, как минимум, вдвое меньше по объему.
Итак, мотивирующая часть беседы окончена, перейдем к практике. Я разделяю ошибки на 3 основных типа: синтаксические ошибки, логические ошибки (баги) и исключительные случаи. Об этих типах мы и поговорим.
Синтаксические ошибки
Синтаксические ошибки это такой тип ошибок, при которых программа просто не скомпилируется. Компилятор, кроме непосредсвенно перевода текста в бинарный код, занимается еще очень важным делом: он проверяет, что то, что вы написали - соответствует правилам языка. Допустим код:

Это уже знакомый нам код, с предыдущей лекции, который я немного "исправил". Если мы попробуем скомпилировать код в таком виде - компилятор откажет нам. Давайте разберем ошибки в коде. Тут их 3.
1. переменная "input_from_user" используется в коде, но она - не объявлена. Но пока компилятор "не видит" этой проблемы, потому что есть другие проблемы, которые сбили его с толку. Как только мы починим "другие проблемы" - он сразу же увидит эту.
2. в конце строки cout отсутствует точка с запятой.
3. во втором cout между "your input is: " и input_from_user нет разделителя <<
Это прекрасно, скажете вы, потому что я сделал эти ошибки специально и поэтому я знаю, на что обратить внимание. А как быть, если ошибка случайно допущена? Хорошо, что Эклипс умеет подчеркивать проблемные места, а как быть, если мы работаем в редакторе, который не умеет это делать? (есть такие)
Давайте перепишем этот код, как написал его я и попробуем скомпилировать. После этого обратим внимание на консоль: там написаны все найденные ошибки. И это пишет уже не Эклипс, а наш компилятор:

Всмотритесь, в то, что он написал. В последних строках присутствует слово "error" ("ошибка" по-английски). Компилятор не просто нашел ошибки, а даже попытался предположить в чем они. Нашел он пока только две: 2-ю и 3-ю, первая не была найдена по причине, описанной выше.
2-я ошибка: "../src/first_programm.cpp:14:2: error: expected ‘;’ before ‘cin’" - он угадал. Действительно на 14-й строке кода перед оператором cin он не нашел точку с запятой. Объясню логику: он знает, что оператор "cin" - это самостоятельный оператор, который обязан начинаться с новой строки. Для компилятора новая строка начинается сразу после точки с запятой.
То есть, если бы мы написали: cout << "please, give me digit: "; cin >> input_from_user; - в одну строку, то это НЕ БЫЛО бы ошибкой, так как точка с запятой - присутствует! Мы переносим строку только для удобства чтения, можно (но не советуется) писать программы не перенося строки вообще, НО точка с запятой - быть обязана.
Думаю, что теперь сообщение компилятора становится более понятным.
Однако, 3-я ошибка немного не понятна... мы знаем, что не хватает символа "<<", однако, компилятор думает, что не хватает точки с запятой... дело в том, что компилятор "перевел" то, что мы написали примерно так:
cout << endl << "your input is: ";
input_from_user << endl;
то есть для него пока картина ясна: закончился оператор "cout", а после него пошел другой оператор input_from_user, к которому, ВОЗМОЖНО, тоже можно обратиться через "<<" (можно или нет, он пока не проверял). НО! как только мы сделаем то, что говорит нам компилятор и поставим между ними точку с запятой, он полезет проверять законность такого обращения и выдаст другую ошибку, в которой скажет, что к input_from_user нельзя обращаться через оператор "<<"
Теперь, давайте немного познакомимся с возможностями Эклипса. Напротив строк, отмеченных красным появился рисунок жучка. То есть, этим рисунком Эклипс говорит нам: "тут есть ошибка, но кажется я знаю ее решение. Позволь мне починить ее автоматом" и при нажатии на жука он выдаст описание того, как именно он собирается чинить проблему. Иногда он угадывает и чинит правильно, иногда - нет.
Вывод, который можно сделать из всего написанного: при возникновении синтаксической ошибки всмотритесь в код, и не только, в указанную строку, но и на то, что написано на соседних строках и попытайтесь понять, в чем именно ошибка. Умение сразу определять в чем именно ошибка - приходит с опытом и ТОЛЬКО так... тут никаких "универсальных советов", кроме как "включить мозг и протереть глаза" быть не может! Компьютер может быть внимательней человека, но быть умнее человека - ему не дано)))
Совет: поиграйтесь немного с кодом, который у вас уже есть. Попробуйте, что будет, если допустить ту или иную ошибку. Попробуйте возможности Эклипса чинить эти ошибки.... в будущем, эти познания и опыт могут серьезно облегчить жизнь. Синтаксические ошибки не должны отнимать много времени, потому что это время ценно для отлова логических ошибок!
Логические ошибки
Логические ошибки еще называют багами. Баг (англ. Bug) - это жук. Это название пошло с тех времен, когда компьютеры работали на светодиодах и занимали, по размеру, сотни квадратных метров. Один из таких начал выдавать ужасные ошибки и когда его проверили, то обнаружилось, что на одном из светодиодов сдох жук, закрыв диод своим телом. Это история.
Чтобы ОЧЕНЬ понятно объяснить что такое баг, я приведу пример: программа высчитывает расстояние, которое прошел поезд:

и результат расчетов программы:

Но любой школьник вам скажет: "Позвольте! Скорость поезда 100 км/ч, время езды - 2 часа... выходит, что пройденное расстояние равно 200 км! Откуда 20 тысяч???"
И он прав! Программист, вместо того, чтобы умножить скорость на время, умножил время на вес поезда! Компилятор даже носом не повел! Он не умеет анализировать логику программы, а с точки зрения синтаксиса - она написана идеально.... Вот это и есть - баг.
Способ отлова таких ошибок только один - внимательный анализ кода! Прежде, чем программист выпустит программу "в свет" он обязан ее протестировать во всех ситуациях, которые придут ему на ум и каждый раз, частенько с калькулятором в руках - проверять результаты работы программы. Это работает только так!
На предприятиях есть целый отдел, вся работа которого заключается в том, что они целый день тестируют программы, написанные их программистами и стараются их вывести из строя ЛЮБЫМИ способами. Такой отдел называется QA.
Думаю, что с логическими ошибками тоже все ясно)))
Исключительные случаи
Чуть выше я сказал фразу:
"...Именно поэтому, основная масса кода, которую вы будете писать - это код, который проверяет наличие ошибок и предотвращает непредсказуемое поведение программы. По сравнению с объемом написанного кода с этой целью, код, который непосредственно выполняет задачу, поставленную перед программой - обычно, как минимум, вдвое меньше по объему."
Но читатель может заметить: позвольте, а где здесь можно с помощью написания кода предотвратить появление всех этих ошибок? Дело в том, что сказав эту фразу я имел ввиду ошибки из типа "исключительные случаи".
В С++ существует 2 способа обработки исключительных случаев. НО! Пока мы рассматривать их не будем, потому что у нас пока не достаточно знаний для этой цели. Поэтому, наберемся терпения и я вам обещаю, что мы еще не раз вернемся к теме ошибок.
@темы: C++