27 июл. 2009 г.

Красотою мир спасётся

Уже не одно десятилетие ходит распространенное заблуждение о словах Достоевского «Красота спасёт мир». И в «Идиоте», и в «Братьях Карамазовых» у него явно звучит эта идея, но совсем с другим оттенком. Именно «Красотою мир спасётся»! Русский язык позволяет передавать эти тонкости, надо этим пользоваться, а не огрублять тексты до простейшего смысла «Придёт Человек-Красота с супер-способностями, всех победит, спасёт мир, а потом по этому комиксу снимут фильм и даже напишут книгу».

О чём это я? Например о том, что в мире есть огромное количество корявых и неудобных вещей, которые произведены очень просто: взяли красивое, удобное и хорошее, но добавили симметрию (или ещё какую-нибудь задурь, про которую есть заблуждение, что с ней лучше). А симметрия хороша только при условии, что она ничего не портит. За примерами маразма далеко ходить не надо, так как уже есть чудная коллекция - Идиотека Лебедева (там половину можно смело фильтровать за несмешной юмор, но его держат, скорее всего, для успеха у большинства).

Но вернёмся к делу. Недавно я уже приводил текст программы в блоге, поэтому предполагаю, что никого сейчас не напугаю следующей короткой распечаточкой кода на языке Си :)

Любителям задачек рекомендую сосредоточиться (кстати, на предыдущую головоломку почему-то пришло очень мало ответов, поэтому разбор пока не публикую).

Итак, следующая программа должна выводить числа ряда Фибоначчи, пока одно из них не привысит 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»? Почему это проявляется не у всех?

Как обычно, прошу первые сутки в комментарии не писать решение, а только оставлять статус «понял сразу», «понял погуглив», «не понял, по какому запросу гуглить» и так далее.

30 комментариев:

  1. Понял только благодаря компилятору :)
    Реально мир спасется только красотою.

    ОтветитьУдалить
  2. Понял. Интересная задача, чтобы поскрипеть мозгами средь рабочего дня.

    ОтветитьУдалить
  3. понял, сразу т.к. видел подобную задачу недавно.

    ОтветитьУдалить
  4. У меня в gcc все работает.
    А у кого проблема? У мелкософтовского компилятора что ли? От этих всего можно ожидать.

    ОтветитьУдалить
  5. Avialaynen, в данном конкретном случае дело не в MS: эффект заметен как минимум в OpenWatcom и Lcc. А gcc, кстати, прямо игнорирует требование стандарта (впрочем, я с ним в этом согласен :)

    ОтветитьУдалить
  6. И gcc 3.4.4, и msvc60, и watcom 10.6 все дают соответствующий warning. Надо просто не лениться их читать.

    ОтветитьУдалить
  7. Анонимный27.07.2009, 15:13

    Догадался в чём дело минут за пять. Очень хорошая задачка для проведения собеседования :)

    ОтветитьУдалить
  8. Да, действительно, на этот варнинг я внимания не обратил. Получается, что я благополучно завалил собеседование :)

    ОтветитьУдалить
  9. в mingw gcc предупредило только что main() описана неправильно но откомпилировалось и выдало ту строчку чисел что от нее и требовалось.

    ОтветитьУдалить
  10. 4ый gcc сказал только про int у main()
    Ряд выдал, как положено.

    Ошибку по-прежнему не вижу, разве что могу предположить :)

    ОтветитьУдалить
  11. Да, gcc в этом смысле молодец!
    Понимая, что некоторые элементы стандарта уже неактуальны, он их выключил (оставив возможность включить, если кому-то для совместимости понадобится).
    Полагаю, уже можно раскрывать смысл сегодняшней шутки, поэтому пользователям gcc рекомендую собрать этот пример с опцией компилятора «-trigraphs», чтобы увидеть« неправильное »поведение, на которое рассчитано в этой задачке.

    ОтветитьУдалить
  12. В топку такой компилятор, который дает глючную последовательность. Давать такие задачи на собеседовании считаю неправильным, особенно молодежи, которая начинает программировать с C# под .NET 3+. Не все могут понять идиотскую логику морально устаревшего стандарта. :-)

    ОтветитьУдалить
  13. Понял благодаря предыдущим комментаторам :)

    Действительно красивый пример )

    ОтветитьУдалить
  14. понял после вдумчивого вглядывания в код. компилятор не использовал. согласен, что такие задачки на интервью давать не стоит.

    ОтветитьУдалить
  15. В википедии в статье про триграфы, кстати, описан тот самый случай, что и у нас.

    ОтветитьУдалить
  16. Newstufflover, я согласен с Вами в том, что это не задачка для собеседования. Но если мы уже отбираем из нескольких равных, а нужен нам человек тщательный и с широким кругозором, да ещё и планируется поручать ему борьбу с тяжёлыми глючными случаями, то подобный вопрос может помочь с выбором :)

    ОтветитьУдалить
  17. Триграфы... Классно.. Забавная задачка :)

    ОтветитьУдалить
  18. понял, погуглив про триграфы

    ОтветитьУдалить
  19. Пoсле копирования кода в MS 6-ю студию выкинул комментарии и долго удивлялся, как может не работать
    (Комментарии на русском превратились в нечитабельные вопросики).

    Потом посмотрев повторно на код в блоге рассмотрел триграф ??/

    ОтветитьУдалить
  20. Спасибо за задачку. На сообщение компилятора не сразу обратил внимание. В отладке выглядит прикольно. У меня сначала возникла идея, что компилятор делает какую-то оптимизацию :)

    Но вот как задачка на собеседование это выглядит не очень. Такие тонкости не обязательно знать. IMHO, гораздо важнее, когда кандидат на С++ понимает основы: конструкторы, деструкторы, порядок инициализации, видит утечки памяти, разбирается в многопоточности. Ну и можно давать задания на алгоритмическое мышление.

    Но данная задача, конечно, покажет многое, если кандидат начнет рассуждать вслух :)

    ОтветитьУдалить
  21. Понял запустив студию и скомпилив... Хотя триграфы уже открыл в вики, но еще не смотрел))))

    Про собеседование - все зависит от предполагаемых задач. Если вопрос стоит о хитрых оптимизациях и т.п. - то да, такие тонкости можно спрашивать. А если нужен "простой" разработчик и "простой" код, то не надо, извините, выеживаться в коде и организовывать проверку четности битовыми операциями на UI стороне (реальный случай был... не сразу же понимаешь, что сказать хотели - сразу мысли "а вдруг здесь что из хитрых багфиксов..." лезут).

    ЗЫ. Лучше смотреть, как чел будет эту задачу решать в реале, получив ее как тестовое на собеседовании.

    ОтветитьУдалить
  22. Каюсь, моя догадка была неверна. Решил, что проблема в некорректной работе со ссылками.

    Про триграфы не знал. Архаизмы.

    ОтветитьУдалить
  23. 1. проверил код - поверил что правильный
    2. подумал про триграфы и пошел смотреть коменты ))) вобщем идейно двигался правильно, но в компиляторе не стал проверять, полагаю кривое место в ???/ ))

    ОтветитьУдалить
  24. Вот ведь извращение-то! даже и не подозревал до сих пор про триграфы

    ОтветитьУдалить
  25. Анонимный30.08.2009, 18:51

    понял, посмотрев коменты, потом погуглив, потом внимательно посмотрев в код

    ОтветитьУдалить
  26. Анонимный02.09.2009, 7:50

    "Специально обученный фанат понятных комментариев" сам нашел себе проблемы.

    Да, комментарии совершенно понятны. Но вот код стал понятен гораздо меньше.

    Лучшим решением головоломки (по крайней мере, наиболее полезным) будет "не-решение": не писать так, стараться выразить свою мысль кодом, а не комментариями к нему.

    Ах да: понял сразу.

    ОтветитьУдалить
  27. Так и не понял, пока не прочел коменты. gcc поругался конечно на триграф, я не зная что это, не обратил внимание, но с ключенной опцией триграф скомпилил. Сначала я подумал, что дело в переменной next, думал что она раз объявившись в цикле, больше не объявляется в следующих итерациях. Мда, сам бы не за что не догадался.

    ОтветитьУдалить
  28. Не знал что такое триграфы.
    Честно говоря, что '/' продолжает комментарий на следующую строку тоже никогда не использовал, поэтому даже при замене триграфа на / тоже не сообразил бы.
    Спасибо за информацию, буду осторожен впредь.

    ОтветитьУдалить
  29. Анонимный09.03.2010, 17:23

    Не сразу понял, но красиво можно понять скомпилив гнутым компилером с такими опциями:

    gcc c.c -trigraphs -E

    ОтветитьУдалить

Понравилась заметка? Подпишитесь на RSS-feed или email-рассылку.

Хотите поделиться ссылкой с другими? Добавьте в закладки:



Есть вопросы или предложения? Пишите письма на адрес mytribune АТ yandex.ru.

С уважением,
      Илья Весенний