В опасностях java-школ Джоэл рассказывает о своем опыте работы в Penn и о трудностях, связанных с ошибками сегментации. Он говорит
[Сегфоуты трудны до тех пор, пока вы] «не сделаете глубокий вдох и действительно попытаетесь заставить свой ум работать на двух разных уровнях абстракции одновременно».
Принимая во внимание список распространенных причин для segfaults, я не понимаю, как мы должны работать на 2 уровнях абстракции.
По какой-то причине Джоэл считает эти понятия основными для способности программистов абстрагироваться. Я не хочу брать на себя слишком много. Итак, что же такого сложного в указателях / рекурсии? Примеры были бы хорошими.
Ответы:
Я впервые заметил, что указатели и рекурсия были трудными в колледже. Я прошел несколько типичных курсов первого курса (один был C и Assembler, другой был в Схеме). Оба курса начинались с сотен студентов, многие из которых имели многолетний опыт программирования на уровне средней школы (обычно BASIC и Pascal, в те дни). Но как только указатели были введены в курс C, и рекурсия была введена в курсе Scheme, огромное количество студентов - возможно, даже большинство - были полностью сбиты с толку. Это были дети, которые написали много кода раньше и у них не было никаких проблем, но когда они ударяли по указателям и рекурсии, они также врезались в стену с точки зрения их когнитивных способностей.
Моя гипотеза состоит в том, что указатели и рекурсия одинаковы в том смысле, что они требуют, чтобы вы держали два уровня абстракции в своей голове одновременно. В многоуровневой абстракции есть что-то, что требует умственных способностей, которые, возможно, у некоторых людей никогда не будут.
Я также был бы совершенно готов согласиться с тем, что можно учить указателей и / или рекурсии кому-либо ... У меня нет никаких доказательств, так или иначе. Я знаю, что опытным путем, способность действительно понять эти две концепции является очень и очень хорошим предиктором общих навыков программирования, и что в обычном курсе обучения CS бакалавриату эти две концепции являются одними из самых больших препятствий.
источник
Рекурсия - это не просто «функция, которая сама себя вызывает». Вы по-настоящему не поймете, почему рекурсия трудна, пока вы не начнете рисовать кадры стека, чтобы выяснить, что пошло не так с вашим анализатором рекурсивного спуска. Часто у вас есть взаимно рекурсивные функции (функция A вызывает функцию B, которая вызывает функцию C, которая может вызывать функцию A). Может быть очень трудно выяснить, что пошло не так, когда вы N стековых фреймов глубоко во взаимно-рекурсивной серии функций.
Что касается указателей, опять же концепция указателей довольно проста: переменная, которая хранит адрес памяти. Но опять же, когда что-то пойдет не так с вашей сложной структурой данных
void**
указателей, которые указывают на разные узлы, вы поймете, почему это может быть сложно, когда вы пытаетесь выяснить, почему один из ваших указателей указывает на адрес мусора.источник
goto
.goto
.int a() { return b(); }
может быть рекурсивным, но это зависит от определенияb
. Так что это не так просто, как кажется ...Java поддерживает указатели (они называются ссылками) и поддерживает рекурсию. Так что на первый взгляд его аргументация кажется бессмысленной.
На самом деле он говорит о способности к отладке. Указатель Java (err, reference) гарантированно указывает на допустимый объект. Указатель переменного тока не И хитрость в программировании на C, при условии, что вы не используете такие инструменты, как valgrind , заключается в том, чтобы выяснить, где именно вы облажали указатель (это редко в точке, найденной в трассировке стека).
источник
Проблема с указателями и рекурсией заключается не в том, что их обязательно сложно понять, а в том, что их плохо учат, особенно в отношении таких языков, как C или C ++ (главным образом потому, что сами языки плохо преподаются). Каждый раз, когда я слышу (или читаю) кто-то говорит «массив - это просто указатель», я умираю немного внутри.
Точно так же каждый раз, когда кто-то использует функцию Фибоначчи для иллюстрации рекурсии, я хочу кричать. Это плохой пример, потому что итеративная версия не сложна в написании и работает по крайней мере так же хорошо или лучше, чем рекурсивная, и она не дает реального представления о том, почему рекурсивное решение было бы полезным или желательным. Быстрая сортировка, обход дерева и т. Д. гораздо лучшие примеры того, почему и как рекурсия.
Гадость с указателями - это артефакт работы на языке программирования, который их раскрывает. Поколения программистов на Fortran создавали списки, деревья, стеки и очереди, не нуждаясь в выделенном типе указателя (или динамическом распределении памяти), и я никогда не слышал, чтобы кто-нибудь обвинял Fortran в том, что он является игрушечным языком.
источник
GOTO target
) , Я думаю, что мы должны были создать наши собственные стеки времени выполнения. Это было достаточно давно, и я не могу вспомнить подробности.Есть несколько трудностей с указателями:
Вот почему программист должен думать более тщательно при использовании указателей (я не знаю о двух уровнях абстракции ). Это пример типичных ошибок, допущенных новичком:
Обратите внимание, что код, подобный приведенному выше, вполне оправдан для языков, в которых нет понятия указателей, а скорее одно из имен (ссылок), объектов и значений, как это делают функциональные языки программирования и языки с сборкой мусора (Java, Python). ,
Трудность с рекурсивными функциями возникает, когда люди без достаточного математического образования (где рекурсивность является обычным явлением и требуются знания) пытаются подойти к ним, думая, что функция будет вести себя по-разному в зависимости от того, сколько раз ее вызывали ранее . Эта проблема усугубляется, потому что рекурсивные функции действительно могут быть созданы таким образом, что вы должны думать так чтобы понять их.
Подумайте о рекурсивных функциях с передаваемыми указателями, как в процедурной реализации красно-черного дерева, в которой структура данных изменяется на месте; это нечто более сложное, чем функциональный аналог .
Это не упомянуто в вопросе, но другой важной проблемой, с которой новички испытывают трудности, является параллелизм .
Как уже упоминали другие, существует дополнительная неконцептуальная проблема с некоторыми конструкциями языка программирования: даже если мы понимаем, простые и честные ошибки с этими конструкциями могут быть чрезвычайно сложными для отладки.
источник
malloc()
Скорее всего , это сделает любая другая функция.)Указатели и рекурсия являются двумя отдельными животными, и существуют разные причины, по которым каждый из них считается «трудным».
В общем, указатели требуют иной ментальной модели, нежели присваивание чистой переменной. Когда у меня есть переменная указателя, это просто: указатель на другой объект, единственные данные, которые он содержит, - это адрес памяти, на который он указывает. Так, например, если у меня есть указатель int32 и я присваиваю ему значение напрямую, я не изменяю значение int, я указываю на новый адрес памяти (с этим можно сделать много полезных трюков) ). Еще более интересно иметь указатель на указатель (это то, что происходит, когда вы передаете переменную Ref в качестве параметра в C # функции, функция может назначить совершенно другой объект для параметра, и это значение все еще будет находиться в области видимости, когда функция выходы.
При первом обучении рекурсия делает небольшой скачок в уме, потому что вы определяете функцию с точки зрения самой себя. Это дикая концепция, когда вы впервые сталкиваетесь с ней, но как только вы понимаете идею, она становится второй натурой.
Но вернемся к предмету под рукой. Аргумент Джоэла не об указателях или рекурсии самих по себе, а скорее о том, что ученики отстраняются от того, как на самом деле работают компьютеры. Это наука в области компьютерных наук. Существует четкая разница между обучением программированию и обучением работе программ. Я не думаю, что это вопрос «я так учился, поэтому каждый должен учиться так», потому что он утверждал, что многие программы CS становятся прославленными профессиональными училищами.
источник
Я даю П. Брайану +1, потому что я чувствую, что он это делает: рекурсия - это настолько фундаментальная концепция, что тому, у кого есть малейшие трудности с этим, лучше подумать о поиске работы в mac donalds, но тогда даже есть рекурсия:
Конечно, отсутствие понимания также связано с нашими школами. Здесь нужно ввести натуральные числа, как это делали Пеано, Дедекинд и Фреге, чтобы потом у нас не было таких трудностей.
источник
goto top
по какой-то причине IME.Я не согласен с Джоэлом в том, что проблема заключается в том, чтобы думать на нескольких уровнях абстракции как таковой, я думаю, что это больше, чем указатели и рекурсия, это два хороших примера проблем, которые требуют изменения в ментальной модели людей, как работают программы.
Я думаю, что указатели являются более простым примером для иллюстрации. Работа с указателями требует умственной модели выполнения программы, которая учитывает то, как программы фактически работают с адресами памяти и данными. Мой опыт показывает, что часто программисты даже не думают об этом, прежде чем узнают об указателях. Даже если они знают это в абстрактном смысле, они не приняли его в свою когнитивную модель работы программы. Когда вводятся указатели, это требует фундаментального изменения в том, как они думают о том, как работает код.
Рекурсия проблематична, потому что есть два концептуальных блока для понимания. Первый - на уровне машины, и, как и указатели, его можно преодолеть, развивая хорошее понимание того, как программы на самом деле хранятся и выполняются. Другая проблема с рекурсией, я думаю, заключается в том, что у людей есть естественная тенденция пытаться деконструировать рекурсивную проблему в нерекурсивную, что запутывает понимание рекурсивной функции как гештальта. Это либо проблема людей с недостаточным математическим образованием, либо ментальная модель, которая не связывает математическую теорию с разработкой программ.
Дело в том, что я не думаю, что указатели и рекурсия - единственные две области, которые являются проблематичными для людей, застрявших в недостаточной ментальной модели. Параллелизм, по-видимому, является еще одной областью, в которой некоторые люди просто застревают и испытывают трудности с адаптацией своей ментальной модели для объяснения, просто часто в интервью легко проверить указатели и рекурсию.
источник
Концепция самоссылочных данных и кода лежит в основе определения указателей и рекурсии соответственно. К сожалению, широкое знакомство с императивными языками программирования привело студентов, изучающих информатику, к убеждению, что они должны понимать реализацию через операционное поведение своих сред выполнения, когда им следует доверить эту загадку функциональному аспекту языка. Суммирование всех чисел до сотни кажется простым делом, начиная с одного и добавляя его к следующему в последовательности и делая его задом наперед с помощью круговых самоссылочных функций, кажется извращенным и даже опасным для многих, не используемых для безопасности. чистые функции.
Концепция самоизменения данных и кода лежит в основе определения объектов (то есть интеллектуальных данных) и макросов соответственно. Я упоминаю об этом, так как их еще сложнее понять, особенно когда от комбинации всех четырех концепций ожидается оперативное понимание времени выполнения - например, макрос, генерирующий набор объектов, который реализует рекурсивный приличный синтаксический анализатор с помощью дерева указателей. , Вместо того, чтобы отслеживать всю операцию состояния программы шаг за шагом через каждый уровень абстракции, императивным программистам нужно научиться верить, что их переменные назначаются только один раз в чистых функциях и что повторные вызовы одной и той же чистой функции с одни и те же аргументы всегда дают один и тот же результат (т. е. ссылочную прозрачность), даже в языке, который также поддерживает нечистые функции, например в Java. Бег по кругу после запуска - бесполезное занятие. Абстракция должна упростить.
источник
Очень похоже на ответ Анона.
Помимо когнитивных трудностей для новичков, как указатели, так и рекурсия очень мощны и могут использоваться загадочно.
Недостатком огромной силы является то, что они дают вам мощную возможность испортить вашу программу тонкими способами.
Сохранение поддельного значения в обычной переменной достаточно плохо, но сохранение чего-то поддельного в указателе может привести к возникновению всевозможных отложенных катастрофических событий.
И что еще хуже, эти эффекты могут измениться, когда вы попытаетесь диагностировать / отладить причину странного поведения программы. Но, если что-то делается не так, как надо, трудно понять, что происходит.
Аналогично с рекурсией. Это может быть очень мощным способом организации хитрых вещей - путем помещения хитрости в скрытую структуру данных (стек).
источник