Из числа вопросов, опубликованных здесь, становится ясно, что у людей возникают некоторые довольно фундаментальные проблемы, когда они обращают внимание на указатели и арифметику указателей.
Мне любопытно узнать почему. Они никогда не вызывали у меня серьезных проблем (хотя я впервые узнал о них еще в неолите). Чтобы лучше ответить на эти вопросы, я хотел бы знать, что людям трудно.
Итак, если вы боретесь с указателями, или вы недавно, но внезапно «получили», какие аспекты указателей вызвали у вас проблемы?
Ответы:
Я подозреваю, что люди слишком углубляются в свои ответы. Понимание планирования, фактических операций ЦП или управления памятью на уровне сборки на самом деле не требуется.
Когда я преподавал, я обнаружил, что следующие пробелы в понимании студентов являются наиболее распространенным источником проблем:
Большинство моих учеников смогли понять упрощенное рисование фрагмента памяти, как правило, раздела локальных переменных стека в текущей области видимости. Вообще помогло дать явные вымышленные адреса различным местам.
Подводя итог, я говорю, что если вы хотите понимать указатели, вы должны понимать переменные и то, что они на самом деле представляют собой в современных архитектурах.
источник
Когда я впервые начал работать с ними, самой большой проблемой у меня был синтаксис.
все одинаковые.
но:
Зачем? потому что часть указателя в объявлении принадлежит переменной, а не типу.
И затем разыменование вещи использует очень похожую запись:
За исключением случаев, когда вам действительно нужно получить указатель ... тогда вы используете амперсанд!
Ура за последовательность!
Тогда, очевидно, просто чтобы быть придурками и доказать, насколько они умны, многие разработчики библиотек используют указатели на указатели на указатели, и если они ожидают массив этих вещей, то почему бы просто не передать указатель на это тоже ,
чтобы вызвать это, мне нужен адрес массива указателей на указатели на указатели целых:
Через шесть месяцев, когда мне придется поддерживать этот код, я потрачу больше времени, пытаясь выяснить, что все это значит, чем переписывать с нуля. (да, возможно, этот синтаксис ошибочен - прошло много времени с тех пор, как я что-то делал на C.
источник
Правильное понимание указателей требует знания архитектуры базовой машины.
Многие программисты сегодня не знают, как работает их машина, так же как большинство людей, которые знают, как водить машину, ничего не знают о двигателе.
источник
Имея дело с указателями, люди, которые запутались, обычно находятся в одном из двух лагерей. Я был (я?) В обоих.
array[]
толпаЭто толпа, которая прямо не знает, как преобразовать нотацию указателя в нотацию массива (или даже не знает, что они даже связаны). Вот четыре способа доступа к элементам массива:
Идея заключается в том, что доступ к массивам с помощью указателей кажется довольно простым и понятным, но тонну очень сложных и умных вещей можно сделать таким образом. Некоторые из них могут оставить опытных программистов на C / C ++ в замешательстве, не говоря уже о неопытных новичках.
reference to a pointer
Иpointer to a pointer
толпаЭто отличная статья, которая объясняет разницу и которую я буду цитировать и красть из кода :)
В качестве небольшого примера может быть очень трудно понять, что именно хотел сделать автор, если вы столкнулись с чем-то вроде этого:
Или, в меньшей степени, что-то вроде этого:
Итак, в конце концов, что мы действительно решаем со всем этим бредом? Ничего.
Эта сложность и кажущаяся (смелое кажущаяся) взаимозаменяемость со ссылками, которая часто является еще одной оговоркой указателей и ошибкой новичков, затрудняет понимание указателей. Важно также понимать, ради ЗАВЕРШЕНИЯ, в том , что указатели на ссылки , являются незаконными в C и C ++ спутать причины , которые перенесут вас в
lvalue
-rvalue
семантику.Как отмечалось в предыдущем ответе, во многих случаях у вас просто бывают эти горячие программисты, которые думают, что они умны в использовании,
******awesome_var->lol_im_so_clever()
и большинство из нас, вероятно, порой виноваты в написании таких злодеяний, но это просто не хороший код, и он, безусловно, не поддается обслуживанию. ,Ну, этот ответ оказался длиннее, чем я надеялся ...
источник
Я виню качество справочных материалов и людей, занимающихся преподаванием, лично; большинство понятий в Си (но особенно указатели) просто плохо преподаются . Я продолжаю угрожать написать свою собственную книгу C (под названием «Последнее, что нужно миру - это еще одна книга о языке программирования C» ), но у меня нет ни времени, ни терпения, чтобы это сделать. Поэтому я тусуюсь здесь и кидаю случайные цитаты из Стандарта в людей.
Также существует тот факт, что когда C был изначально спроектирован, предполагалось, что вы понимаете архитектуру машины на достаточно детальном уровне только потому, что не было никакого способа избежать этого в вашей повседневной работе (память была настолько тесной, а процессоры - такими медленными Вы должны были понять, как то, что вы написали, повлияло на производительность).
источник
Есть замечательная статья, подтверждающая, что на сайте Джоэла Спольски сложно найти указатели - Опасности JavaSchools .
[Отказ от ответственности - я не ненавистник Java как таковой .]
источник
Большинство вещей труднее понять, если вы не основаны на знаниях, которые «под ним». Когда я преподавал CS, стало намного проще, когда я начал учить своих студентов программированию очень простой «машины», имитирующего десятичный компьютер с десятичными кодами операций, чья память состояла из десятичных регистров и десятичных адресов. Они будут вставлять очень короткие программы, например, чтобы добавить ряд чисел, чтобы получить общее количество. Затем они пошагово наблюдали за происходящим. Они могли бы удерживать клавишу «Ввод» и смотреть, как она работает «быстро».
Я уверен, что почти все на SO удивляются, почему это так полезно. Мы забываем, что это было, не зная, как программировать. Игра с таким игрушечным компьютером создает концепции, без которых вы не можете программировать, такие как идея, что вычисления - это пошаговый процесс, использование небольшого количества базовых примитивов для создания программ и концепция памяти. переменные как места, где хранятся числа, в которых адрес или имя переменной отличается от числа, которое она содержит. Существует различие между временем, когда вы входите в программу, и временем, когда она «запускается». Я уподобляюсь тому, чтобы научиться программировать как пересечение ряда «скачков», таких как очень простые программы, затем циклы и подпрограммы, затем массивы, затем последовательный ввод-вывод, затем указатели и структура данных.
Наконец, при переходе к C указатели сбивают с толку, хотя K & R очень хорошо их объяснил. Способ, которым я узнал их в Си, состоял в том, чтобы знать, как читать их - справа налево. Например, когда я вижу
int *p
в своей голове, я говорю «p
указывает наint
». C был придуман как шаг вперед по сравнению с ассемблером, и это то, что мне нравится в нем - оно близко к этой «земле». Указатели, как и все остальное, труднее понять, если у вас нет этого основания.источник
Я не получил указатели, пока не прочитал описание в K & R. До этого момента указатели не имели смысла. Я прочитал целую кучу вещей, в которых люди говорили: «Не учите указатели, они сбивают с толку и повредят вашу голову, и у вас возникнут аневризмы», поэтому я долго избегал этого и создал этот ненужный вид сложной концепции. ,
В противном случае, в основном то, что я думал, почему на земле вам нужна переменная, через которую вы должны пройти через обручи, чтобы получить значение, и если вы хотите присвоить ей что-то, вы должны были сделать странные вещи, чтобы получить значения для перехода в них. Я думал, что весь смысл переменной заключается в том, чтобы хранить значение, поэтому вопрос о том, почему кто-то хотел усложнить ситуацию, был мне не по карману. «Так что с указателем вы должны использовать
*
оператор, чтобы получить его значение ??? Что это за глупая переменная?» , Я думал. Бессмысленно, каламбур не предназначен.Это было сложно, потому что я не понимал, что указатель - это адрес чего-то. Если вы объясните, что это адрес, что-то, что содержит адрес для чего-то другого, и что вы можете манипулировать этим адресом, чтобы делать полезные вещи, я думаю, это может устранить путаницу.
Класс, который требовал использования указателей для доступа / изменения портов на ПК, использования арифметики указателей для обращения к разным ячейкам памяти и просмотра более сложного C-кода, который модифицировал их аргументы, лишил меня идеи о том, что указатели были, ну, в общем, бессмысленными.
источник
Вот пример указатель / массив, который дал мне паузу. Предположим, у вас есть два массива:
И ваша цель - скопировать содержимое uint8_t из источника с помощью memcpy (). Угадайте, что из следующего достигнет этой цели:
Ответ (Спойлер Alert!) ВСЕ из них. «destination», «& destination» и «& destination [0]» имеют одинаковое значение. «& destination» - это тип, отличный от двух других, но он все еще имеет то же значение. То же самое касается перестановок «источника».
Кроме того, я лично предпочитаю первый вариант.
источник
sizeof(source)
, потому что еслиsource
указатель,sizeof
он не будет тем, что вы хотите. Я иногда (не всегда) пишуsizeof(source[0]) * number_of_elements_of_source
просто, чтобы держаться подальше от этой ошибки.Я должен начать с того, что C и C ++ были первыми языками программирования, которые я выучил. Я начал с C, потом много занимался C ++ в школе, а затем вернулся к C, чтобы свободно владеть им.
Первое, что смутило меня в отношении указателей при изучении C, было простое:
Эта путаница была главным образом связана с использованием ссылки на переменную для аргументов OUT до того, как указатели были должным образом представлены мне. Я помню, что пропустил написание первых нескольких примеров на C для чайников, потому что они были слишком просты, чтобы никогда не заставить работать первую программу, которую я написал (скорее всего, из-за этого).
Что смущало, так это то, что на
&ch
самом деле означало, а также почемуstr
это не нужно.После того, как я познакомился с этим, я вспомнил, что был озадачен динамическим распределением. В какой-то момент я понял, что указатели на данные не очень полезны без динамического выделения некоторого типа, поэтому я написал что-то вроде:
попытаться динамически выделить некоторое пространство. Это не сработало. Я не был уверен, что это сработает, но я не знал, как еще это может сработать.
Позже я узнал о
malloc
иnew
, но они действительно казались мне генераторами волшебной памяти. Я ничего не знал о том, как они могут работать.Некоторое время спустя меня снова учили рекурсии (раньше я изучал ее самостоятельно, но сейчас был в классе) и спросил, как она работает под капотом - где хранятся отдельные переменные. Мой профессор сказал «в стеке», и многое мне стало ясно. Я слышал этот термин раньше и уже реализовывал программные стеки. Я слышал, что другие упоминали о «стеке» задолго до этого, но забыл об этом.
Примерно в это же время я также понял, что использование многомерных массивов в C может привести к путанице. Я знал, как они работают, но их было так легко запутать, что я решил попытаться обойти их, когда смогу. Я думаю, что проблема здесь была в основном синтаксической (особенно передача или возврат их из функций).
Так как я писал C ++ для школы в течение следующего года или двух, я получил большой опыт использования указателей для структур данных. Здесь у меня возник новый набор неприятностей - путаница указателей. У меня было бы несколько уровней указателей (вещи как
node ***ptr;
) сбивают меня с толку. Я бы разыменовал указатель неверное число раз и в итоге прибегнул к определению, сколько*
мне нужно методом проб и ошибок.В какой-то момент я узнал, как работает куча программы (вроде, но достаточно хорошо, что она больше не держала меня ночью). Я помню, что читал, что если вы посмотрите на несколько байтов перед указателем, который
malloc
возвращается в определенной системе, вы увидите, сколько данных было фактически выделено. Я понял, что кодmalloc
может запросить больше памяти у ОС, и эта память не была частью моих исполняемых файлов. Наличие достойной рабочей идеи о том, какmalloc
работает, действительно полезно.Вскоре после этого я взял урок ассемблера, который не научил меня так много, как, вероятно, думает большинство программистов. Это заставило меня задуматься о том, на какую сборку может быть переведен мой код. Я всегда пытался написать эффективный код, но теперь у меня была лучшая идея, как это сделать.
Я также взял пару классов, где я должен был написать какой-то шутку . При написании lisp я не был так обеспокоен эффективностью, как в C. Я очень мало представлял, во что этот код может быть переведен, если скомпилирован, но я знал, что похоже на использование множества локальных именованных символов (переменных), созданных все намного проще. В какой-то момент я написал немного кода поворота дерева AVL с небольшим количеством шуток, и мне было очень трудно писать на C ++ из-за проблем с указателями. Я понял, что мое отвращение к тому, что я считал избыточными локальными переменными, помешало мне написать и несколько других программ на C ++.
Я также взял класс компиляторов. Находясь в этом классе, я переключился на расширенный материал и узнал о статических одиночных присваиваниях (SSA) и мертвых переменных, что не так уж важно, за исключением того, что он научил меня, что любой приличный компилятор справится с переменными, которые больше не используется. Я уже знал, что больше переменных (включая указатели) с правильными типами и хорошими именами помогло бы мне держать вещи прямо в моей голове, но теперь я также знал, что избегать их по соображениям эффективности было даже более глупо, чем мои менее склонные к микрооптимизации профессора говорили меня.
Так что для меня очень помогло знание структуры памяти программы. Размышления о том, что означает мой код, как символически, так и на оборудовании, помогают мне. Использование локальных указателей, имеющих правильный тип, очень помогает. Я часто пишу код, который выглядит так:
так что если я испорчу тип указателя, то по ошибке компилятора станет ясно, в чем проблема. Если бы я сделал:
и любой неверный тип указателя будет ошибкой компилятора. Я испытал бы соблазн прибегнуть к пробным и ошибочным изменениям в моем разочаровании и, вероятно, усугубить ситуацию.
источник
Оглядываясь назад, было четыре вещи, которые действительно помогли мне наконец понять указатели. До этого я мог их использовать, но не до конца их понимал. То есть я знал, что если я буду следовать формам, я получу желаемые результаты, но я не до конца понял «почему» форм. Я понимаю, что это не совсем то, что вы просили, но я думаю, что это полезное следствие.
Написание подпрограммы, которая взяла указатель на целое число и изменила целое число. Это дало мне необходимые формы для построения любых ментальных моделей работы указателей.
Одномерное динамическое распределение памяти. Выяснение 1-D распределения памяти заставило меня понять концепцию указателя.
Двумерное динамическое распределение памяти. Вычисление 2-D выделения памяти подкрепило эту концепцию, но также научило меня, что сам указатель требует хранения и должен быть принят во внимание.
Различия между переменными стека, глобальными переменными и кучей памяти. Выяснение этих различий научило меня типам памяти, на которые указывают / ссылаются указатели.
Каждый из этих предметов требовал представления о том, что происходит на более низком уровне - построение ментальной модели, которая удовлетворяла бы каждому случаю, который я мог себе представить. Это потребовало времени и усилий, но оно того стоило. Я убежден, что для понимания указателей вы должны построить эту ментальную модель того, как они работают и как они реализуются.
Теперь вернемся к исходному вопросу. Исходя из предыдущего списка, было несколько вещей, которые мне было трудно понять изначально.
источник
У меня был «момент указателя», работавший над некоторыми телефонными программами на C. Мне пришлось написать эмулятор обмена AXE10, используя анализатор протокола, который понимал только классический C. Все зависело от знания указателей. Я попытался написать свой код без них (эй, я был «предварительным указателем», немного ослабил меня) и потерпел неудачу.
Ключ к их пониманию, для меня, был оператор & (адрес). Когда я понял, что это
&i
означает «адрес i», то понимание, что*i
«содержание адреса, на который указывает i», появилось немного позже. Всякий раз, когда я писал или читал свой код, я всегда повторял, что означало «&» и что означало «*», и в конце концов я стал использовать их интуитивно.К своему стыду, я был вынужден перейти на VB, а затем на Java, так что мои знания указателей не такие острые, как это было раньше, но я рад, что я «пост-указатель». Не проси меня использовать библиотеку, которая требует от меня понимания * * p, хотя.
источник
&i
это адрес и*i
содержание, то чтоi
?Основная проблема с указателями, по крайней мере для меня, заключается в том, что я не начинал с C. Я начал с Java. Понятие указателей было по-настоящему чуждым до тех пор, пока в колледже не было пары уроков, где я должен был знать C. Итак, я научил себя основам языка C и тому, как использовать указатели в их самом базовом смысле. Даже тогда, каждый раз, когда я читаю код на C, мне приходится искать синтаксис указателя.
Так что в моем очень ограниченном опыте (1 год в реальном мире + 4 в колледже) указатели смущают меня, потому что мне никогда не приходилось использовать его в чем-то другом, кроме школьных занятий. И я могу сочувствовать студентам, начинающим CS с JAVA вместо C или C ++. Как вы сказали, вы изучали указатели в эпоху неолита и, вероятно, используете его с тех пор. Для нас, новичков, понятие выделения памяти и выполнения арифметики указателей действительно чуждо, потому что все эти языки абстрагировали его.
PS После прочтения эссе Спольского его описание «JavaSchools» было совсем не похоже на то, что я изучал в колледже в Корнелле (05–09). Я взял структуры и функциональное программирование (sml), операционные системы (C), алгоритмы (ручку и бумагу) и целый ряд других классов, которые не преподавались в Java. Однако все вступительные классы и факультативы были выполнены в Java, потому что не стоит изобретать велосипед, когда вы пытаетесь сделать что-то более высокое, чем реализация хеш-таблицы с указателями.
источник
void foo(Clazz obj) { obj = new Clazz(); }
не работает, когдаvoid bar(Clazz obj) { obj.quux = new Quux(); }
мутирует аргумент ...Здесь нет ответа: используйте cdecl (или c ++ decl), чтобы понять это:
источник
Они добавляют дополнительное измерение к коду без существенного изменения синтаксиса. Думать об этом:
Там только одна вещь , чтобы изменения:
a
. Вы можете написать,a = 6
и результаты очевидны для большинства людей. Но теперь рассмотрим:Есть две вещи
a
, которые актуальны в разное время: фактическое значениеa
, указатель и значение «за» указателем. Вы можете изменитьa
:... и
some_int
все еще где-то с тем же значением. Но вы также можете изменить то, на что оно указывает:Между ними существует концептуальный разрыв
a = 6
, который имеет только локальные побочные эффекты и*a = 6
может повлиять на множество других вещей в других местах. Моя точка зрения здесь заключается не в том, что концепция косвенности является хитрой по своей сути, а в том, что вы можете делать как непосредственную, локальную вещь, такa
и косвенную вещь*a
... это может быть тем, что смущает людей.источник
Я программировал на c ++ около 2 лет, а затем перешел на Java (5 лет) и никогда не оглядывался назад. Однако, когда мне недавно пришлось использовать некоторые нативные вещи, я обнаружил (с удивлением), что ничего не забыл о указателях и даже нахожу их простыми в использовании. Это резкий контраст с тем, что я испытал 7 лет назад, когда я впервые попытался понять концепцию. Итак, я думаю, что понимание и симпатия - это вопрос зрелости программирования? :)
ИЛИ
Указатели - это как езда на велосипеде, как только вы поймете, как с ними работать, вы не забудете об этом.
В целом, трудно понять или нет, вся идея указателя является ОЧЕНЬ образовательной, и я считаю, что это должен понимать каждый программист, независимо от того, программирует он на языке с указателями или нет.
источник
Указатели сложны из-за косвенности.
источник
Указатели (наряду с некоторыми другими аспектами низкоуровневой работы) требуют от пользователя убрать магию.
Большинство программистов высокого уровня любят магию.
источник
Указатели - это способ справиться с разницей между дескриптором объекта и самим объектом. (хорошо, не обязательно объекты, но вы знаете, что я имею в виду, а также где мой разум)
В какой-то момент вам, вероятно, придется иметь дело с разницей между ними. В современном языке высокого уровня это становится различием между копированием по значению и копированием по ссылке. В любом случае, это концепция, которую часто трудно понять программистам.
Однако, как уже указывалось, синтаксис для решения этой проблемы в C является уродливым, непоследовательным и запутанным. В конце концов, если вы действительно попытаетесь понять это, указатель будет иметь смысл. Но когда вы начинаете иметь дело с указателями на указатели и т. Д. До тошноты, это становится действительно запутанным как для меня, так и для других людей.
Еще одна важная вещь, которую нужно помнить о указателях, это то, что они опасны.C является языком мастера программирования. Предполагается, что вы знаете, какого черта вы делаете, и тем самым дает вам возможность действительно все испортить. Хотя некоторые типы программ все еще должны быть написаны на C, большинство программ этого не делают, и если у вас есть язык, который обеспечивает лучшую абстракцию для различия между объектом и его дескриптором, то я предлагаю вам использовать его.
Действительно, во многих современных приложениях C ++ часто бывает так, что любая необходимая арифметика указателей инкапсулируется и абстрагируется. Мы не хотим, чтобы разработчики делали арифметику указателей повсеместно. Нам нужен централизованный, хорошо протестированный API, который выполняет арифметику указателей на самом низком уровне. Внесение изменений в этот код должно выполняться с большой осторожностью и всесторонним тестированием.
источник
Я думаю, что одна из причин, по которой указатели C трудны, состоит в том, что они объединяют несколько концепций, которые на самом деле не эквивалентны; тем не менее, поскольку все они реализованы с использованием указателей, людям может быть трудно распутать концепции.
В C указатели используются для других вещей:
В C вы определяете связанный список целых чисел, как это:
Указатель существует только потому, что это единственный способ определить рекурсивную структуру данных в C, когда концепция действительно не имеет ничего общего с такими низкоуровневыми деталями, как адреса памяти. Рассмотрим следующий эквивалент в Haskell, который не требует использования указателей:
Довольно просто - список либо пуст, либо сформирован из значения и остальной части списка.
Вот как вы можете применить функцию
foo
к каждому символу строки в C:Несмотря на использование указателя в качестве итератора, этот пример имеет очень мало общего с предыдущим. Создание итератора, который вы можете увеличивать, отличается от определения рекурсивной структуры данных. Ни одна из этих концепций не связана с идеей адреса памяти.
Вот фактическая сигнатура функции, найденная в glib :
Вау! Это довольно много
void*
. И все это только для объявления функции, которая перебирает список, который может содержать любые вещи, применяя функцию к каждому члену. Сравните это с тем, какmap
объявлено в Haskell:Это гораздо проще:
map
это функция, которая берет функцию, которая преобразует aa
в ab
, и применяет ее к спискуa
's, чтобы получить списокb
' s '. Как и в функции Cg_list_foreach
,map
не нужно ничего знать в своем определении о типах, к которым она будет применяться.Подводить итоги:
Я думаю, что указатели на C были бы намного менее запутанными, если бы люди сначала узнали о рекурсивных структурах данных, итераторах, полиморфизме и т. Д. Как об отдельных концепциях, а затем узнали, как указатели можно использовать для реализации этих идей в C , вместо того, чтобы смешивать все эти понятия объединяются в единый предмет «указатели».
источник
c != NULL
в вашем примере "Hello world" ... вы имеете в виду*c != '\0'
.Я думаю, что это требует прочной основы, вероятно, на уровне машины, с введением некоторого машинного кода, сборки и того, как представлять элементы и структуру данных в оперативной памяти. Это займет немного времени, немного домашней работы или практики решения проблем, а также немного размышлений.
Но если человек поначалу знает языки высокого уровня (в этом нет ничего плохого - плотник использует топор. Человек, которому нужно разделить атом, использует что-то другое. Нам нужны люди, которые являются плотниками, и у нас есть люди, которые изучают атомы) и этому человеку, который знает язык высокого уровня, дается 2-минутное введение в указатели, а затем трудно ожидать, что он поймет арифметику указателей, указатели на указатели, массив указателей на строки переменного размера, массив массивов символов и т. д. Твердый фундамент низкого уровня может очень помочь.
источник
Проблема, с которой я всегда сталкивался (прежде всего, самоучка), - это «когда» использовать указатель. Я могу обернуть голову вокруг синтаксиса для создания указателя, но мне нужно знать, при каких обстоятельствах указатель должен использоваться.
Я единственный с таким мышлением? ;-)
источник
Когда-то давно ... У нас было 8 битных микропроцессоров, и каждый писал на ассемблере. Большинство процессоров включало некоторый тип косвенной адресации, используемый для таблиц переходов и ядер. Когда появились языки более высокого уровня, мы добавили тонкий слой абстракции и назвали их указателями. С годами мы все больше отдаляемся от аппаратного обеспечения. Это не обязательно плохо. Они называются языками более высокого уровня по причине. Чем больше я могу сосредоточиться на том, что я хочу сделать, а не на деталях того, как это делается, тем лучше.
источник
Кажется, у многих студентов есть проблема с понятием косвенности, особенно когда они впервые встречают понятие косвенности. Я помню, когда я был студентом, из +100 студентов моего курса только горстка людей действительно понимала указатели.
Концепция косвенного обращения - это не то, что мы часто используем в реальной жизни, и, следовательно, это сложная концепция для первоначального понимания.
источник
Недавно у меня только что был момент щелчка указателя, и я был удивлен, что нашел его запутанным. Больше того, что все так много говорили об этом, что я предположил, что происходит какая-то темная магия.
То, как я это понял, было так. Представьте, что всем определенным переменным предоставляется пространство памяти во время компиляции (в стеке). Если вам нужна программа, которая может обрабатывать большие файлы данных, такие как аудио или изображения, вам не нужен фиксированный объем памяти для этих потенциальных структур. Таким образом, вы ждете времени выполнения, чтобы назначить определенный объем памяти для хранения этих данных (в куче).
Если у вас есть данные в памяти, вы не хотите копировать эти данные по всей вашей шине памяти каждый раз, когда хотите выполнить на ней операцию. Скажем, вы хотите применить фильтр к вашим данным изображения. У вас есть указатель, который начинается в начале данных, которые вы присвоили изображению, и функция перебирает эти данные, меняя их на месте. Если вы не знаете, что мы делаем, вы, вероятно, в конечном итоге создадите дубликаты данных, поскольку вы выполняли эту операцию.
По крайней мере, так я сейчас вижу!
источник
Выступая как новичок C ++ здесь:
Система указателей заняла у меня некоторое время, чтобы переварить не обязательно из-за концепции, но из-за синтаксиса C ++ относительно Java. Несколько вещей, которые я нашел запутанными:
(1) Объявление переменной:
против
против
и, видимо,
является объявлением функции, а не объявлением переменной. В других языках есть только один способ объявить переменную.
(2) Амперсанд используется несколькими различными способами. Если это
тогда & a является адресом памяти.
OTOH, если это
тогда & a является параметром, переданным по ссылке.
Хотя это может показаться тривиальным, это может сбить с толку новых пользователей - я пришел с Java, а язык Java с более единообразным использованием операторов
(3) отношение массив-указатель
Немного разочаровывает понимание того, что указатель
может быть указателем на int
или
может быть массивом для int
И затем, чтобы сделать вещи более запутанными, указатели и массив не взаимозаменяемы во всех случаях, и указатели не могут быть переданы в качестве параметров массива.
Это подводит итог некоторых основных разочарований, которые у меня были с C / C ++ и его указателями, которые, по мнению IMO, сильно усугубляются тем фактом, что C / C ++ имеет все эти специфичные для языка причуды.
источник
Я лично не понимал указатель даже после окончания учебы и после моей первой работы. Единственное, что я знал, это то, что вам это нужно для связанного списка, двоичных деревьев и для передачи массивов в функции. Такая была ситуация даже на моей первой работе. Только когда я начал давать интервью, я понял, что концепция указателя глубока и имеет огромное применение и потенциал. Затем я начал читать K & R и писать собственную тестовую программу. Вся моя цель была ориентирована на работу.
В это время я обнаружил, что указатели действительно не плохие и не сложные, если их научить хорошим способом. К сожалению, когда я изучаю C на выпускном, наш учитель не знал о указателе, и даже в заданиях использовалось меньше указателей. На выпускном уровне использование указателя действительно только для создания бинарных деревьев и связанного списка. Мысль о том, что вам не нужно правильное понимание указателей, чтобы работать с ними, убивает идею их изучения.
источник
Указатели ... ха ... все, что касается указателя в моей голове, это то, что он дает адрес памяти, в котором находятся фактические значения независимо от его ссылки ... так что никакой магии в этом нет. как работают указатели .. давай, ребята ... даже в Java все ссылки ...
источник
Основная проблема, люди не понимают, зачем им указатели. Потому что они не имеют четкого представления о стеке и куче. Хорошо начать с 16-битного ассемблера для x86 с крошечным режимом памяти. Это помогло многим людям понять стек, кучу и «адрес». И байт :) Современные программисты иногда не могут сказать вам, сколько байтов вам нужно для адресации 32-битного пространства. Как они могут получить представление о указателях?
Второй момент - это обозначение: вы объявляете указатель как *, вы получаете адрес как &, и некоторым это непросто понять.
И последнее, что я увидел, была проблема с хранилищем: они понимают кучу и стек, но не могут понять, что такое «статический».
источник