Уже не одно десятилетие ходит распространенное заблуждение о словах Достоевского «Красота спасёт мир». И в «Идиоте», и в «Братьях Карамазовых» у него явно звучит эта идея, но совсем с другим оттенком. Именно «Красотою мир спасётся»! Русский язык позволяет передавать эти тонкости, надо этим пользоваться, а не огрублять тексты до простейшего смысла «Придёт Человек-Красота с супер-способностями, всех победит, спасёт мир, а потом по этому комиксу снимут фильм и даже напишут книгу».
О чём это я? Например о том, что в мире есть огромное количество корявых и неудобных вещей, которые произведены очень просто: взяли красивое, удобное и хорошее, но добавили симметрию (или ещё какую-нибудь задурь, про которую есть заблуждение, что с ней лучше). А симметрия хороша только при условии, что она ничего не портит. За примерами маразма далеко ходить не надо, так как уже есть чудная коллекция - Идиотека Лебедева (там половину можно смело фильтровать за несмешной юмор, но его держат, скорее всего, для успеха у большинства).
Но вернёмся к делу. Недавно я уже приводил текст программы в блоге, поэтому предполагаю, что никого сейчас не напугаю следующей короткой распечаточкой кода на языке Си :)
Любителям задачек рекомендую сосредоточиться (кстати, на предыдущую головоломку почему-то пришло очень мало ответов, поэтому разбор пока не публикую).
Итак, следующая программа должна выводить числа ряда Фибоначчи, пока одно из них не привысит 20 (определяется этот ряд легко: каждое следующее число - это сумма двух предыдущих, а первые два - единицы).
#include "stdio.h"
void main()
{
// Эта программа должна вывести /
// первые 8 чисел Фибоначчи: /
// 1, 1, 2, 3, 5, 8, 13, 21. /
// Определим первое и второе /
// значение ряда - это единицы: /
int first = 1, second = 1;
// Сразу же выведем первое число: /
printf("%d, ", first);
// Цикл "делать следующее, пока /
// второе значение меньше 20". /
while (second < 20) { // проверили/
// Следующее - это сумма /
// первого и второго. Вычислим /
int next = first + second;
// Теперь надо записать второе /
// значение в первое, а следую- /
// щее - во второе, так ведь ???/
first = second;
second = next;
// Выведем на экран первое число/
printf("%d, ", first);
}
// Выведем последнее значение ряда/
printf("%d\n", second);
}
Как видите, специально обученный фанат понятных комментариев сделал своё дело - код программы совершенно ясен. К вопросу о красоте - всё ровненько, аккуратненько, одинаковые стандартизованные комментарии даже немножко раздражают :)
Теперь вопрос знатокам: почему эта программа выводит не ожидаемый ряд «1, 1, 2, 3, 5, 8, 13, 21», а неожиданный «1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20»? Почему это проявляется не у всех?
Как обычно, прошу первые сутки в комментарии не писать решение, а только оставлять статус «понял сразу», «понял погуглив», «не понял, по какому запросу гуглить» и так далее.
Понял только благодаря компилятору :)
ОтветитьУдалитьРеально мир спасется только красотою.
Понял. Интересная задача, чтобы поскрипеть мозгами средь рабочего дня.
ОтветитьУдалитьпонял, сразу т.к. видел подобную задачу недавно.
ОтветитьУдалитьУ меня в gcc все работает.
ОтветитьУдалитьА у кого проблема? У мелкософтовского компилятора что ли? От этих всего можно ожидать.
Avialaynen, в данном конкретном случае дело не в MS: эффект заметен как минимум в OpenWatcom и Lcc. А gcc, кстати, прямо игнорирует требование стандарта (впрочем, я с ним в этом согласен :)
ОтветитьУдалитьПонял сразу
ОтветитьУдалитьИ gcc 3.4.4, и msvc60, и watcom 10.6 все дают соответствующий warning. Надо просто не лениться их читать.
ОтветитьУдалитьДогадался в чём дело минут за пять. Очень хорошая задачка для проведения собеседования :)
ОтветитьУдалитьДа, действительно, на этот варнинг я внимания не обратил. Получается, что я благополучно завалил собеседование :)
ОтветитьУдалитьв mingw gcc предупредило только что main() описана неправильно но откомпилировалось и выдало ту строчку чисел что от нее и требовалось.
ОтветитьУдалить4ый gcc сказал только про int у main()
ОтветитьУдалитьРяд выдал, как положено.
Ошибку по-прежнему не вижу, разве что могу предположить :)
Да, gcc в этом смысле молодец!
ОтветитьУдалитьПонимая, что некоторые элементы стандарта уже неактуальны, он их выключил (оставив возможность включить, если кому-то для совместимости понадобится).
Полагаю, уже можно раскрывать смысл сегодняшней шутки, поэтому пользователям gcc рекомендую собрать этот пример с опцией компилятора «-trigraphs», чтобы увидеть« неправильное »поведение, на которое рассчитано в этой задачке.
В топку такой компилятор, который дает глючную последовательность. Давать такие задачи на собеседовании считаю неправильным, особенно молодежи, которая начинает программировать с C# под .NET 3+. Не все могут понять идиотскую логику морально устаревшего стандарта. :-)
ОтветитьУдалитьПонял благодаря предыдущим комментаторам :)
ОтветитьУдалитьДействительно красивый пример )
понял после вдумчивого вглядывания в код. компилятор не использовал. согласен, что такие задачки на интервью давать не стоит.
ОтветитьУдалитьВ википедии в статье про триграфы, кстати, описан тот самый случай, что и у нас.
ОтветитьУдалитьNewstufflover, я согласен с Вами в том, что это не задачка для собеседования. Но если мы уже отбираем из нескольких равных, а нужен нам человек тщательный и с широким кругозором, да ещё и планируется поручать ему борьбу с тяжёлыми глючными случаями, то подобный вопрос может помочь с выбором :)
ОтветитьУдалитьТриграфы... Классно.. Забавная задачка :)
ОтветитьУдалитьпонял, погуглив про триграфы
ОтветитьУдалитьПoсле копирования кода в MS 6-ю студию выкинул комментарии и долго удивлялся, как может не работать
ОтветитьУдалить(Комментарии на русском превратились в нечитабельные вопросики).
Потом посмотрев повторно на код в блоге рассмотрел триграф ??/
Спасибо за задачку. На сообщение компилятора не сразу обратил внимание. В отладке выглядит прикольно. У меня сначала возникла идея, что компилятор делает какую-то оптимизацию :)
ОтветитьУдалитьНо вот как задачка на собеседование это выглядит не очень. Такие тонкости не обязательно знать. IMHO, гораздо важнее, когда кандидат на С++ понимает основы: конструкторы, деструкторы, порядок инициализации, видит утечки памяти, разбирается в многопоточности. Ну и можно давать задания на алгоритмическое мышление.
Но данная задача, конечно, покажет многое, если кандидат начнет рассуждать вслух :)
Понял запустив студию и скомпилив... Хотя триграфы уже открыл в вики, но еще не смотрел))))
ОтветитьУдалитьПро собеседование - все зависит от предполагаемых задач. Если вопрос стоит о хитрых оптимизациях и т.п. - то да, такие тонкости можно спрашивать. А если нужен "простой" разработчик и "простой" код, то не надо, извините, выеживаться в коде и организовывать проверку четности битовыми операциями на UI стороне (реальный случай был... не сразу же понимаешь, что сказать хотели - сразу мысли "а вдруг здесь что из хитрых багфиксов..." лезут).
ЗЫ. Лучше смотреть, как чел будет эту задачу решать в реале, получив ее как тестовое на собеседовании.
Каюсь, моя догадка была неверна. Решил, что проблема в некорректной работе со ссылками.
ОтветитьУдалитьПро триграфы не знал. Архаизмы.
1. проверил код - поверил что правильный
ОтветитьУдалить2. подумал про триграфы и пошел смотреть коменты ))) вобщем идейно двигался правильно, но в компиляторе не стал проверять, полагаю кривое место в ???/ ))
Вот ведь извращение-то! даже и не подозревал до сих пор про триграфы
ОтветитьУдалитьпонял, посмотрев коменты, потом погуглив, потом внимательно посмотрев в код
ОтветитьУдалить"Специально обученный фанат понятных комментариев" сам нашел себе проблемы.
ОтветитьУдалитьДа, комментарии совершенно понятны. Но вот код стал понятен гораздо меньше.
Лучшим решением головоломки (по крайней мере, наиболее полезным) будет "не-решение": не писать так, стараться выразить свою мысль кодом, а не комментариями к нему.
Ах да: понял сразу.
Так и не понял, пока не прочел коменты. gcc поругался конечно на триграф, я не зная что это, не обратил внимание, но с ключенной опцией триграф скомпилил. Сначала я подумал, что дело в переменной next, думал что она раз объявившись в цикле, больше не объявляется в следующих итерациях. Мда, сам бы не за что не догадался.
ОтветитьУдалитьНе знал что такое триграфы.
ОтветитьУдалитьЧестно говоря, что '/' продолжает комментарий на следующую строку тоже никогда не использовал, поэтому даже при замене триграфа на / тоже не сообразил бы.
Спасибо за информацию, буду осторожен впредь.
Не сразу понял, но красиво можно понять скомпилив гнутым компилером с такими опциями:
ОтветитьУдалитьgcc c.c -trigraphs -E