Каковы барьеры для понимания указателей и что можно сделать, чтобы их преодолеть? [закрыто]

это не невозможно:

var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window);  
setTimeout(function(){ document.getElementById('input_field_id').dispatchEvent(evObj); },100);

Но как-то это работает, только если это функция, вызванная с помощью события click.

Итак, у вас может быть следующая настройка :

html:

<div onclick="openFileChooser()" class="some_fancy_stuff">Click here to open image chooser</div>
<input type="file" id="input_img">

JavaScript:

    function openFileChooser() {
      var evObj = document.createEvent('MouseEvents');
      evObj.initMouseEvent('click', true, true, window);  
      setTimeout(function()
      { 
        document.getElementById('input_img').dispatchEvent(evObj);      
      },100);      
    }
443
задан 6 revs, 4 users 57% 23 May 2010 в 12:28
поделиться

24 ответа

Указатели являются понятием, которое для многих может сбивать с толку сначала, в особенности когда дело доходит до копирования значений указателя вокруг и все еще ссылки на тот же блок памяти.

я нашел, что лучшая аналогия должна рассмотреть указатель как листок бумаги с адресом дома на нем и блоком памяти, на который это ссылается как фактический дом. Все виды операций могут таким образом быть легко объяснены.

я добавил некоторый код Дельфи вниз ниже и некоторые комментарии в соответствующих случаях. Я выбрал Delphi, так как мой другой основной язык программирования, C#, не показывает вещи как утечки памяти таким же образом.

, Если Вы только хотите изучить высокоуровневое понятие указателей, тогда необходимо проигнорировать части, маркировал "Memory layout" в объяснении ниже. Они предназначаются для предоставления примеров того, на что память могла быть похожей после операций, но они - больше низкого уровня по своей природе. Однако, чтобы точно объяснить, как переполнение буфера действительно работает, было важно, чтобы я добавил эти схемы.

Правовая оговорка: Во всех отношениях, это объяснение и разметки памяти в качестве примера значительно упрощены. Существует больше служебное и намного больше деталей, которые необходимо было бы знать, необходимо ли иметь дело с памятью на основе низкого уровня. Однако для намерений объяснения памяти и указателей, это достаточно точно.

<час>

Позволяют нам предположить, что класс THouse, используемый ниже, похож на это:

type
    THouse = class
    private
        FName : array[0..9] of Char;
    public
        constructor Create(name: PChar);
    end;

при инициализации объекта дома имя, данное конструктору, копируется в частное поле FName. Существует причина, она определяется как массив фиксированного размера.

В памяти, будут немного служебные связаны с выделением дома, я проиллюстрирую это ниже подобного это:

---[ttttNNNNNNNNNN]---
     ^   ^
     |   |
     |   +- the FName array
     |
     +- overhead

"tttt" область является служебной, обычно будет больше из этого для различных типов времени выполнения и языков, как 8 или 12 байтов. Обязательно, чтобы независимо от того, что значения были сохранены в этой области, никогда не изменяется ничем кроме средства выделения памяти или базовых системных стандартных программ, или Вы рискуете разрушать программу.

<час>

Выделяют память

, Заставляют предпринимателя создавать Ваш дом и давать Вам адрес дому. В отличие от реального мира, выделение памяти не может быть сказано, где выделить, но найдет подходящее место с достаточным количеством комнаты и сообщит адрес выделенной памяти.

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

THouse.Create('My house');

расположение Памяти:

---[ttttNNNNNNNNNN]---
    1234My house
<час>

Сохраняют переменную с адресом

Запись адрес в Ваш новый дом вниз на листке бумаги. Данная статья будет служить Вашей ссылкой на Ваш дом. Без этого листка бумаги Вы потеряны и не можете найти дом, если Вы уже не находитесь в нем.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...

расположение Памяти:

    h
    v
---[ttttNNNNNNNNNN]---
    1234My house
<час>

значение указателя Копии

Просто пишут адрес на новом листке бумаги. У Вас теперь есть два листка бумаги, которые получат Вас в тот же дом, не два отдельных здания. Любые попытки следовать за адресом из одной бумаги и переставить мебель в том доме заставят его казаться, что другой дом был изменен таким же образом, если Вы не можете явно обнаружить, что это - на самом деле всего один дом.

Примечание Это обычно - понятие, что у меня есть большая часть объяснения задач людям, два указателя не означает два объекта или блоки памяти.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...
    h1
    v
---[ttttNNNNNNNNNN]---
    1234My house
    ^
    h2
<час>

Освобождение памяти

Уничтожают дом. Можно тогда позже снова использовать бумагу для нового адреса если Вы, так пожелайте или очистите ее для упущения адреса в дом, который больше не существует.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    h := nil;

Здесь я сначала создаю дом и овладеваю его адресом. Тогда я делаю что-то в дом (используйте его... код, оставленный как осуществление для читателя), и затем я освобождаю его. Наконец я очищаю адрес от своей переменной.

расположение Памяти:

    h                        <--+
    v                           +- before free
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h (now points nowhere)   <--+
                                +- after free
----------------------          | (note, memory might still
    xx34My house             <--+  contain some data)
<час>

Висячие указатели

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

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    ... // forgot to clear h here
    h.OpenFrontDoor; // will most likely fail

Используя [1 126] после того, как вызов к [1 127] мог бы работа, но это - просто чистая удача. Скорее всего, это перестанет работать, в потребительском месте, посреди критической операции.

    h                        <--+
    v                           +- before free
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h                        <--+
    v                           +- after free
----------------------          |
    xx34My house             <--+

, Как Вы видите, h неподвижные точки к остаткам данных в памяти, но так как это не могло бы быть завершено, с помощью него в качестве прежде, мог бы перестать работать.

<час>

Утечка памяти

Вы теряете листок бумаги и не можете найти дом. Дом все еще стоит где-нибудь, хотя, и когда Вы позже хотите создать новый дом, Вы не можете снова использовать то пятно.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    h := THouse.Create('My house'); // uh-oh, what happened to our first house?
    ...
    h.Free;
    h := nil;

Здесь мы перезаписали содержание h переменная с адресом нового дома, но старый все еще стоит... где-нибудь. После этого кода нет никакого способа достигнуть того дома, и это оставят, стоя. Другими словами, выделенная память останется выделенной до завершений приложения, в которой точке операционная система разъединит ее.

расположение Памяти после первого выделения:

    h
    v
---[ttttNNNNNNNNNN]---
    1234My house

расположение Памяти после второго выделения:

                       h
                       v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
    1234My house       5678My house

А более распространенный способ получить этот метод состоит в том, чтобы только забыть освобождать что-то, вместо того, чтобы перезаписать его как выше. В терминах Дельфи это произойдет со следующим методом:

procedure OpenTheFrontDoorOfANewHouse;
var
    h: THouse;
begin
    h := THouse.Create('My house');
    h.OpenFrontDoor;
    // uh-oh, no .Free here, where does the address go?
end;

После того, как этот метод выполнился, нет никакого места в наших переменных, что адрес в дом существует, но дом все еще там.

расположение Памяти:

    h                        <--+
    v                           +- before losing pointer
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h (now points nowhere)   <--+
                                +- after losing pointer
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

, Как Вы видите, старые данные оставляет неповрежденными в памяти и не снова использует средство выделения памяти. Средство выделения отслеживает, которых областей памяти использовался и не снова использует их, если Вы не освобождаете его.

<час>

Освобождение памяти, но хранение (теперь недопустимый) ссылка

Уничтожает дом, стирает один из листков бумаги, но у Вас также есть другой листок бумаги со старым адресом на нем, когда Вы перейдете к адресу, Вы не найдете дом, но Вы могли бы найти что-то, что напоминает руины одного.

, Возможно, Вы даже найдете дом, но это не дом, Вам первоначально дали адрес, и таким образом любые попытки использовать его, как будто это принадлежит Вам, мог бы перестать работать ужасно.

Иногда Вы могли бы даже найти, что соседний адрес имеет довольно большой агрегат собственных нужд на нем, который занимает три, обращаются (Мэйн-Стрит 1-3), и Ваш адрес переходит к середине дома. Любые попытки рассматривать ту часть большого 3-адресного дома как единственный небольшой дом могли бы также перестать работать ужасно.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...
    h1.Free;
    h1 := nil;
    h2.OpenFrontDoor; // uh-oh, what happened to our house?

Здесь дом был разъединен через ссылку в [1 129], и в то время как h1 был очищен также, h2 все еще имеет старое, устаревшее, адрес. Доступ к дому, который больше не стоит, мог бы или не мог бы работать.

Это - изменение висячего указателя выше. Посмотрите его расположение памяти.

<час>

Переполнение буфера

Вы перемещаете больше материала в дом, чем можно возможно соответствовать, устремляясь в соседний дом или двор. Когда владелец того соседнего дома позже придет домой, он найдет все виды вещей, он рассмотрит свое собственное.

Это - причина, я выбрал массив фиксированного размера. Чтобы готовить почву, предположите, что второй дом, который мы выделяем, будет, по некоторым причинам, помещен перед первым в памяти. Другими словами, второй дом будет иметь более низкий адрес, чем первый. Кроме того, они выделяются друг прямо рядом с другом.

Таким образом, этот код:

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := THouse.Create('My other house somewhere');
                         ^-----------------------^
                          longer than 10 characters
                         0123456789 <-- 10 characters

расположение Памяти после первого выделения:

                        h1
                        v
-----------------------[ttttNNNNNNNNNN]
                        5678My house

расположение Памяти после второго выделения:

    h2                  h1
    v                   v
---[ttttNNNNNNNNNN]----[ttttNNNNNNNNNN]
    1234My other house somewhereouse
                        ^---+--^
                            |
                            +- overwritten

часть, которая будет чаще всего вызывать катастрофический отказ, - при перезаписи важных частей данных, Вы сохранили, это действительно не должно быть случайным образом изменено. Например, это не могла бы быть проблема, что части названия h1-дома были изменены, с точки зрения катастрофического отказа программы, но перезапись издержек объекта, скорее всего, откажет, когда Вы попытаетесь использовать поврежденный объект, как будет, перезаписывая ссылки, который хранится к другим объектам в объекте.

<час>

Связанные списки

, Когда Вы следуете за адресом на листке бумаги, Вы добираетесь до дома, и в том доме существует другой листок бумаги с новым адресом на нем, для следующего дома в цепочке, и так далее.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('Home');
    h2 := THouse.Create('Cabin');
    h1.NextHouse := h2;

Здесь мы создаем ссылку от нашего домашнего дома до нашей каюты. Мы можем следовать за цепочкой, пока дом не имеет никакой NextHouse ссылка, что означает, что это - последнее. Для посещения всех наших зданий мы могли использовать следующий код:

var
    h1, h2: THouse;
    h: THouse;
begin
    h1 := THouse.Create('Home');
    h2 := THouse.Create('Cabin');
    h1.NextHouse := h2;
    ...
    h := h1;
    while h <> nil do
    begin
        h.LockAllDoors;
        h.CloseAllWindows;
        h := h.NextHouse;
    end;

расположение Памяти (добавил NextHouse как ссылку в объекте, отмеченном с четырьмя LLLL's в ниже схемы):

    h1                      h2
    v                       v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
    1234Home       +        5678Cabin      +
                   |        ^              |
                   +--------+              * (no link)
<час>

В основных условиях, что такое адрес памяти?

адрес памяти А находится в основных условиях просто число. При размышлении об о памяти как большом массиве байтов самый первый байт имеет адрес 0, следующий адрес 1 и так далее вверх. Это упрощаемое, но достаточно хорошее.

Так это расположение памяти:

    h1                 h2
    v                  v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
    1234My house       5678My house

иметь эти два адрес (крайнее левое - адресом 0):

  • h1 = 4
  • h2 = 23

, Что означает, что наш связанный список выше мог бы фактический взгляд как это:

    h1 (=4)                 h2 (=28)
    v                       v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
    1234Home      0028      5678Cabin     0000
                   |        ^              |
                   +--------+              * (no link)

Это типичное, чтобы хранить адрес, который "указывает нигде" как нулевое адресное.

<час>

В основных условиях, что такое указателем?

указатель А просто переменной, содержащей адрес памяти. Вы обычно просит, чтобы язык программирования давать Вам свое число, но большинство языков программирования и времени выполнения попытавшиеся скрывать то, что быть число под, просто потому что само число действительно содержит значение Вам. Лучше думать об указателе как черном квадрате, т.е. Вы действительно знает или заботящиеся о том, как это на самом деле реализовываемое, пока это работает.

742
ответ дан 7 revs 23 May 2010 в 12:28
поделиться

Только, чтобы перепутать вещи немного больше, иногда необходимо работать с дескрипторами вместо указателей. Дескрипторы являются указателями на указатели, так, чтобы бэкэнд мог переместить вещи в память для дефрагментации "кучи". Если изменения указателя в середине стандартной программы, результаты непредсказуемы, таким образом, сначала необходимо заблокировать дескриптор, чтобы удостовериться, что ничто не идет никуда.

http://arjay.bc.ca/Modula-2/Text/Ch15/Ch15.8.html#15.8.5 переговоры об этом немного более когерентно, чем я.:-)

0
ответ дан SarekOfVulcan 23 May 2010 в 12:28
поделиться

Я не вижу то, что так сбивает с толку об указателях. Они указывают на местоположение в памяти, которая является им, хранит адрес памяти. В C/C++ можно определить тип, на который указывает указатель. Например:

int* my_int_pointer;

Говорит, что my_int_pointer содержит адрес к местоположению, которое содержит интервал

, проблема с указателями состоит в том, что они указывают на местоположение в памяти, таким образом, легко затихнуть в некоторое местоположение, Вы не должны быть в. Как взгляд доказательства на многочисленные дыры в системе безопасности в приложениях C/C++ от переполнения буфера (увеличивающий указатель мимо выделенной границы).

0
ответ дан grom 23 May 2010 в 12:28
поделиться

Путаница возникает из-за множества уровней абстракции, смешанных вместе в концепции «указатель». Программистов не смущают обычные ссылки в Java / Python, но указатели отличаются тем, что они раскрывают характеристики базовой архитектуры памяти.

Хорошим принципом является четкое разделение слоев абстракции, а указатели этого не делают.

2
ответ дан Joshua Fox 23 May 2010 в 12:28
поделиться

Я не думаю, что сами указатели сбивают с толку. Большинство людей может понять понятие. Теперь, о скольких указатели могут Вы думать или сколькими уровни абстракции - Вы довольный. Не требуются слишком многих для помещения людей по краю. То, что они могут быть изменены случайно ошибками в Вашей программе, может также сделать их очень трудными отладить, когда вещи идут не так, как надо в Вашем коде.

2
ответ дан bruceatk 23 May 2010 в 12:28
поделиться

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

Например, следуя связанному списку: 1) начните со своей бумаги с адресом 2) перейдите по адресу на бумаге 3) откройте почтовый ящик, чтобы найти новый лист бумаги со следующим адресом на нем

В линейном связанном списке в последнем почтовом ящике ничего нет (конец списка). В круговом связанном списке последний почтовый ящик содержит адрес первого почтового ящика.

Обратите внимание, что на шаге 3 происходит разыменование, и вы можете потерпеть крах или ошибиться, если адрес недействителен. Предполагая, что вы можете подойти к почтовому ящику с неверным адресом, представьте, что там есть черная дыра или что-то еще, что выворачивает мир наизнанку:)

4
ответ дан Christopher Scott 23 May 2010 в 12:28
поделиться

пример учебного руководства с хорошим набором схем помогает значительно с пониманием указателей .

Joel Spolsky делает некоторые правильные замечания о понимании указателей в его Партизанское Руководство по статье Interviewing :

По некоторым причинам большинство людей, кажется, рождается без части мозга, который понимает указатели. Это - вещь способности, не вещь навыка †“, это требует сложной формы вдвойне-indirected размышления, что некоторые люди просто не могут сделать.

9
ответ дан 3 revs, 2 users 62% 23 May 2010 в 12:28
поделиться

Сложности указателей выходят за рамки того, что мы можем легко научить. Заставить студентов указывать друг на друга и использовать листы бумаги с домашними адресами - оба являются отличными инструментами обучения. Они делают большую работу по внедрению основных понятий. Действительно, изучение основных понятий жизненно важно для успешного использования указателей. Тем не менее, в производственном коде часто встречаются гораздо более сложные сценарии, чем эти простые демонстрации могут инкапсулировать.

Я был связан с системами, где у нас были структуры, указывающие на другие структуры, указывающие на другие структуры. Некоторые из этих структур также содержали встроенные структуры (а не указатели на дополнительные структуры). Это где указатели становятся действительно запутанными. Если у вас есть несколько уровней косвенности, и вы начинаете заканчивать с таким кодом:

widget->wazzle.fizzle = fazzle.foozle->wazzle;

он может очень быстро запутаться (представьте себе намного больше строк и, возможно, больше уровней). Добавьте массивы указателей и указатели от узла к узлу (деревья, связанные списки), и это еще хуже. Я видел, как некоторые действительно хорошие разработчики терялись, когда они начали работать над такими системами, даже разработчики, которые действительно хорошо понимали основы.

Сложные структуры указателей также не обязательно указывают на плохое кодирование (хотя они могут). Композиция является жизненно важной частью хорошего объектно-ориентированного программирования, а в языках с необработанными указателями она неизбежно приведет к многоуровневой косвенности. Кроме того, системы часто должны использовать сторонние библиотеки со структурами, которые не соответствуют друг другу по стилю или технике. В подобных ситуациях сложность естественным образом возникает (хотя, конечно, мы должны бороться с ней как можно больше).

Я думаю, что лучшее, что могут сделать колледжи, чтобы помочь студентам выучить указатели, - это использовать хорошие демонстрации в сочетании с проектами, которые требуют использования указателей. Один сложный проект сделает больше для понимания указателя, чем тысяча демонстраций. Демонстрации могут дать вам поверхностное понимание, но для глубокого понимания указателей вы должны действительно их использовать.

12
ответ дан Derek Park 23 May 2010 в 12:28
поделиться

Я нашел "Учебное руководство Ted Jensen на Указателях и Массивах в C" превосходным ресурсом для приобретения знаний об указателях. Это разделено на 10 уроков, начавшись с объяснения того, что указатели (и что они для), и заканчивающийся с указателями функции. http://home.netcom.com/~tjensen/ptr/cpoint.htm

Хождение дальше оттуда, Руководство Beej по Сетевому программированию учит, что Unix снабжает сокетом API, от которого можно начать делать действительно забавные вещи. http://beej.us/guide/bgnet/

19
ответ дан Ted Percival 23 May 2010 в 12:28
поделиться

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

Трудность, по крайней мере та, с которой я сталкивался в прошлом и с которой сталкивались другие, заключается в том, что управление указателями в C / C ++ может быть излишне запутанным.

9
ответ дан 2 revs 23 May 2010 в 12:28
поделиться

Причина указатели, кажется, смущают столько людей, состоит в том, что они главным образом идут с минимальными знаниями в архитектуре ЭВМ. Так как у многих, кажется, нет идеи того, как компьютеры (машина) на самом деле реализованы - работающий в C/C++, кажется посторонним.

развертка А должна попросить, чтобы они реализовали простую основанную на байт-коде виртуальную машину (на любом языке, который они выбрали, Python работает отлично для этого) с системой команд, сфокусированной на операциях указателя (загрузка, хранилище, прямая / косвенная адресация). Тогда попросите, чтобы они записали простые программы для той системы команд.

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

48
ответ дан JSN 23 May 2010 в 12:28
поделиться

, Почему являются указатели таким ведущим фактором беспорядка для многих новых, и даже старый, студенты уровня колледжа на языке C/C++?

понятие заполнителя для значения - переменные - отображаются на что-то, что нам преподают в школе - алгебра. Нет существующей параллели, которую можно провести, не понимая, как память физически размечается в компьютере, и никто не думает о такого рода вещи, пока они не имеют дело с низкоуровневыми вещами - на коммуникационном уровне C/C ++/byte.

там какие-либо инструменты или мыслительные процессы, которые помогли Вам понять, как указатели работают в переменной, функции, и вне уровня?

поля Addresses. Я помню, когда я учился программировать ОСНОВНОЙ в микрокомпьютеры, были эти симпатичные книги с играми в них, и иногда необходимо было ввести значения по абсолютному адресу в конкретные адреса. У них было изображение набора полей, инкрементно маркированных 0, 1, 2..., и было объяснено, что только одна мелочь (байт) могла поместиться в эти поля, и были многие из них - некоторые компьютеры имели целых 65535! Они были друг рядом с другом, и у них всех был адрес.

, Каковы некоторые хорошие вещи практики, которые могут быть сделаны, чтобы принести кому-то к уровню, "А-ч ха, я получил его", не получая их сорвал в полном понятии? В основном разверните как сценарии.

Для развертки? Сделайте структуру:

struct {
char a;
char b;
char c;
char d;
} mystruct;
mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;
cout << 'Start: my_pointer = ' << *my_pointer << endl;
my_pointer++;
cout << 'After: my_pointer = ' << *my_pointer << endl;
my_pointer = &mystruct.a;
cout << 'Then: my_pointer = ' << *my_pointer << endl;
my_pointer = my_pointer + 3;
cout << 'End: my_pointer = ' << *my_pointer << endl;

Тот же пример как выше, кроме C:

// Same example as above, except in C:
struct {
    char a;
    char b;
    char c;
    char d;
} mystruct;

mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;

printf("Start: my_pointer = %c\n", *my_pointer);
my_pointer++;
printf("After: my_pointer = %c\n", *my_pointer);
my_pointer = &mystruct.a;
printf("Then: my_pointer = %c\n", *my_pointer);
my_pointer = my_pointer + 3;
printf("End: my_pointer = %c\n", *my_pointer);

Вывод:

Start: my_pointer = s
After: my_pointer = t
Then: my_pointer = r
End: my_pointer = u

, Возможно, который объясняет некоторые основы через пример?

27
ответ дан 7 revs, 4 users 61% 23 May 2010 в 12:28
поделиться

Аналогия, которую я нашел полезными для объяснения указателей, является гиперссылками. Большинство людей может понять, что ссылка на веб-страницу 'указывает' на другую страницу в Интернете, и если можно скопировать & вставьте ту гиперссылку тогда, они оба укажут на ту же исходную веб-страницу. Если Вы пойдете и отредактируете ту исходную страницу, то перейдете по любой из тех ссылок (указатели), то Вы получите ту новую обновленную страницу.

124
ответ дан 2 revs, 2 users 67% 23 May 2010 в 12:28
поделиться

В моем первом классе Comp Sci мы выполнили следующее упражнение. Конечно, это был лекционный зал с примерно 200 студентами ...

Профессор пишет на доске: int john;

Джон встает

Профессор пишет: int *sally = &john;

Салли встает, указывает на Джона

Профессор: int *bill = sally;

Билл встает, указывает на Джона

Профессор: int sam;

Сэм встает

Профессор: bill = &sam;

Билл теперь указывает на Сэма.

Я думаю, вы поняли идею. Я думаю, что мы потратили на это около часа, пока не рассмотрели основы назначения указателей.

150
ответ дан 3 revs, 3 users 78% 23 May 2010 в 12:28
поделиться

Я думаю, что то, что делает указатели хитрыми для изучения, то, что, пока указатели Вы не довольны идеей, которая "в этой ячейке памяти ряд битов, которые представляют интервал, двойное, символ, безотносительно".

, Когда Вы увидели указатель в первый раз, Вы действительно не получаете то, что в той ячейке памяти. "Что Вы имеете в виду, это содержит адрес ?"

я не соглашаюсь с понятием, что "Вы или получаете их, или Вы не делаете".

Они становятся легче понять, когда Вы начинаете находить реальное использование для них (как не передача больших структур в функции).

5
ответ дан Baltimark 23 May 2010 в 12:28
поделиться

Я думаю, что главная причина, что люди испытывают затруднения из-за него, состоит в том, потому что это обычно не преподается интересным и привлекательным способом. Я хотел бы видеть, что лектор получает 10 волонтеров от толпы и дает им 1-метровую линейку каждый, заставляет их стоять вокруг в определенной конфигурации и использовать линейки для указания друг на друга. Тогда покажите адресную арифметику с указателями путем перемещения людей (и где они указывают на свои линейки). Это было бы простое, но эффективное (и прежде всего незабываемый) способ показать понятия, не будучи слишком сорванным в механике.

, Как только Вы добираетесь до C и C++, это, кажется, становится более трудным для некоторых людей. Я не уверен, является ли это вызвано тем, что они наконец помещают теорию, что они правильно не схватывают в практику или потому что управление указателем по сути более трудно на тех языках. Я не могу помнить свой собственный переход, который хорошо, но я знал указатели в Паскале и затем переместил в C и был полностью потерян.

3
ответ дан 2 revs, 2 users 67% 23 May 2010 в 12:28
поделиться

Номер почтового ящика.

Это - информация, которая позволяет Вам получать доступ к чему-то еще.

(И если Вы делаете арифметику на номерах почтового ящика, у Вас может быть проблема, потому что буква входит в неправильное поле. И если кто-то перемещается в другое состояние - без адреса пересылки - тогда у Вас есть висячий указатель. С другой стороны - если почтовое отделение пересылает почту, то у Вас есть указатель на указатель.)

1
ответ дан joel.neely 23 May 2010 в 12:28
поделиться

Неплохой способ понять это с помощью итераторов ... но продолжайте искать, вы увидите, как Александреску начнет жаловаться на них

Многие бывшие разработчики на C ++ (которые никогда не понимали, что итераторы являются современным указателем, прежде чем создавать дамп языка) переходят на C # и все еще верят, что у них есть достойные итераторы.

Хм, проблема в том, что все, что итераторы находятся в Полные шансы на то, чего пытаются достичь платформы времени исполнения (Java / CLR): новое, простое использование «все - как разработчик». Это может быть хорошо, но они сказали это однажды в фиолетовой книге, и они сказали это даже до и до C:

Indirection.

Очень мощная концепция, но никогда, если вы делаете это все время. Итераторы полезно, поскольку они помогают с абстракцией алгоритмов, другой пример. А время компиляции - это место для алгоритма, очень простого. Вы знаете код + данные,

1
ответ дан 22 November 2019 в 23:09
поделиться

Я думаю, что это может быть проблема синтаксиса. Синтаксис C / C ++ для указателей кажется непоследовательным и более сложным, чем нужно.

По иронии судьбы, вещь, которая действительно помогла мне понять указатели, столкнулась с концепцией итератора в стандартной библиотеке шаблонов c ++ ]. Это иронично, потому что я могу только предположить, что итераторы были заданы как обобщение указателя.

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

2
ответ дан 22 November 2019 в 23:09
поделиться

Причина, по которой это так трудно понять, не в том, что это сложная концепция, а в том, что синтаксис противоречив .

   int *mypointer;

Вы впервые узнали, что крайняя левая часть создания переменной определяет тип переменной. Объявление указателя не работает так в C и C ++. Вместо этого они говорят, что переменная указывает на тип слева. В этом случае: * mypointer указывает на целое число.

Я не полностью понял указатели, пока не попробую использовать их в C # (с небезопасным), они работают точно таким же образом, но с логическим и последовательным синтаксисом. Указатель сам по себе является типом. Здесь mypointer является указателем на int.

  int* mypointer;

Даже не заводите меня на указатели функций ...

5
ответ дан 22 November 2019 в 23:09
поделиться

Я мог работать с указателями, когда знал только C ++. Я вроде знал, что делать в некоторых случаях, а что не делать методом проб / ошибок. Но то, что дало мне полное понимание, это язык ассемблера. Если вы выполните серьезную отладку на уровне инструкций с помощью написанной вами программы на языке ассемблера, вы сможете многое понять.

5
ответ дан 22 November 2019 в 23:09
поделиться

Проблема с указателями не в концепции. Это исполнение и язык вовлечены. Дополнительная путаница приводит к тому, что учителя предполагают, что это КОНЦЕПЦИЯ указателей труднее, а не жаргон или запутанный беспорядок C и C ++ делает концепцию. Огромные усилия прилагаются для объяснения концепции (как в принятом ответе на этот вопрос), и она в значительной степени просто напрасна на кого-то вроде меня, потому что я уже все это понимаю. Это просто объясняет неправильную часть проблемы.

Чтобы дать вам представление о том, откуда я, я тот, кто прекрасно понимает указатели, и я могу грамотно использовать их на языке ассемблера. Потому что на языке ассемблера они не называются указателями. Они называются адресами. Когда дело доходит до программирования и использования указателей в C, я допускаю много ошибок и очень запутываюсь. Я до сих пор не разобрался в этом. Позвольте мне привести вам пример.

Когда API говорит:

int doIt(char *buffer )
//*buffer is a pointer to the buffer

, что он хочет?

он может хотеть:

число, представляющее адрес буфера

(Чтобы дать ему это, я могу сказать doIt (mybuffer) или doIt (* myBuffer) ?)

число, представляющее адрес для адреса в буфере

(это ] doIt (& mybuffer) или doIt (mybuffer) или doIt (* mybuffer) ?)

число, представляющее адрес по адресу к адресу в буфере

(может быть, это doIt (& mybuffer) . Или это doIt (&& mybuffer) ? Или даже doIt (&&& mybuffer) )

и так далее , и используемый язык не делает это настолько ясным, потому что он включает в себя слова «указатель» и «ссылка», которые не имеют такого большого значения и ясности для меня, как «x содержит адрес для y» и «эта функция требует обратиться к вам ". Ответ дополнительно зависит от того, с какого черта «mybuffer» должен начинаться, и что он намерен делать с ним. Язык не поддерживает уровни вложенности, которые встречаются на практике. Например, когда мне нужно передать «указатель» на функцию, которая создает новый буфер, и он изменяет указатель так, чтобы он указывал на новое местоположение буфера. Действительно ли он хочет указатель или указатель на указатель, чтобы он знал, куда идти, чтобы изменить содержимое указателя. Большую часть времени я просто должен догадаться, что подразумевается под " Я в замешательстве.

8
ответ дан 22 November 2019 в 23:09
поделиться

Я думаю, что основной барьер для понимания указателей - плохие учителя.

Почти у каждого учат в том, что он находится , что они не более чем адреса памяти , или что они позволяют указывать на произвольных мест .

И, конечно, что им трудно понять, опасно и полумагируют.

Ничто из чего не правда. Указатели на самом деле довольно простые концепции, , пока вы придерживаетесь к тому, что язык C ++ должен сказать о них и не наполняй их атрибутами, что «обычно» оказывается на практике, но тем не менее не гарантируется языком, и поэтому не являются частью фактической концепции указателя.

Я пытался написать объяснение этого несколько месяцев назад в этот блог Post - надеюсь, это поможет кому-то.

(Примечание, прежде чем кто-то надо будет педантичным, да, стандарт C ++ говорит, что указатели представляют собой адреса памяти. Но не говорят, что «указатели являются адресами памяти, и ничего, кроме адресов памяти и Может использоваться или мыслей взаимозаменяемо с адресами памяти ». Различие важно)

8
ответ дан 22 November 2019 в 23:09
поделиться

Причина, по которой мне было трудно понять указатели, в первую очередь, состоит в том, что многие объяснения включают много дерьма о прохождении посредством ссылки. Все это путает проблему. Когда вы используете параметр указателя, вы до сих пор , передаваемые по значению; Но значение происходит, а не адрес, а не, скажем, int.

Кто-то еще уже связан с этим руководством, но я могу выделить момент, когда я начал понимать указатели:

Учебное пособие по указателям и массивам в C: Глава 3 - указатели и строки

int puts(const char *s);

на данный момент, игнорировать const. Параметр, переданный на , ставит () , является указателем , который является значением указателя (поскольку все параметры C передаются по значению), а значение указателя является адрес, к которому он указывает, или, просто адрес. Таким образом, когда мы пишем , ставит (Stra); Как мы видели, мы передаем адрес Stra [0].

В тот момент, когда я прочитал эти слова, облака расстались и луч солнечного света окутали меня с пониманием указателя.

Даже если вы разработчик VB .NET или C # (как я) и никогда не используете небезопасный код, он все еще стоит понять, как работает указатели, или вы не поймете, как работают ссылки на объект. Тогда у вас будет обычное, так и ошибочное представление, которое передает ссылку на объект на метод, копирует объект.

24
ответ дан 22 November 2019 в 23:09
поделиться