Недавно я пытался объяснить указатели наглядно, как карточки.
Вопрос 001: это рисунок места в памяти компьютера. Это правда, что его адрес
0x23452
? Зачем?Ответ: Да, потому что
0x23452
описывает, где компьютер может найти это место.
Вопрос 002: правда ли, что персонаж
b
хранится в ячейке памяти0x23452
? Зачем?Ответ: Нет, потому что персонаж
a
на самом деле хранится внутри него.
Вопрос 003: правда ли, что указатель хранится в ячейке памяти
0x23452
? Зачем?Ответ: Да, потому что в
0x34501
ней хранится адрес ячейки памяти .
Вопрос 004: правда ли, что указатель хранится в ячейке памяти
0x23452
? Зачем?Ответ: Да, потому что внутри него хранится адрес другой ячейки памяти.
Теперь о той части, которая меня беспокоит. Инженер-программист объяснил мне указатели так:
Указатель - это переменная, значением которой является адрес памяти другой переменной.
Основываясь на четырех карточках, которые я вам всем показал, я бы определил указатели немного по-другому:
Указатель - это ячейка памяти, значением которой является адрес памяти другой ячейки памяти.
Можно ли с уверенностью сказать, что переменная - это то же самое, что и ячейка памяти?
Если нет, то кто прав? В чем разница между переменной и местом в памяти?
источник
a
,0x23453
.nil
и т.д. вещи внутри них являются ценностями. Это может показаться вам очевидным, но мне было бы неудобно давать решительные ответы на эти вопросы, не видя, как эти поля определены. На самом деле нет никакого способа узнать, является лиa
на втором изображении символ, строка (если они различаются) или имя переменной. Если это строка, тоnil
тоже строка? Или "нулевое" значение?Ответы:
Переменная - это логическая конструкция, которая соответствует цели алгоритма, тогда как область памяти - это физическая конструкция, которая описывает работу компьютера. Вообще говоря, для выполнения программы (генерируется компилятором) выполняется сопоставление между логическим представлением переменной и хранилищем компьютера.
(Даже на языке ассемблера мы имеем представление о (логических) переменных, идущих к алгоритму и назначению, и (физической) ячейки памяти, хотя они более тесно связаны в сборке.)
Переменная - это концепция высокого (эр) уровня. Переменная представляет собой либо неизвестное (как в математике, или в программировании), так и заполнитель, который можно заменить значением (как в программировании: параметры).
Область памяти - это концепция низкого (эр) уровня. Место в памяти может использоваться для хранения значения, иногда для хранения значения переменной. Тем не менее, регистр ЦП является еще одним способом хранения значения некоторой переменной (переменных). Регистры ЦП также являются хранилищами низкого (эр) уровня, но они не являются ячейками памяти, так как у них нет адресов, только имена.
В некотором смысле переменная является механизмом абстракции для выражения намерения программы, тогда как ячейка памяти является физическим объектом среды обработки, которая обеспечивает хранение и поиск.
Мы не можем сказать наверняка. То, что там есть значение, которое будет работать как адрес, не означает, что это тот адрес, это может быть целое (десятичное) 144466. Мы не можем делать предположения о толковании ценностей просто исходя из того, как они выглядят численно.
Это действительно странный вопрос. Они ожидают некоторых предположений на основе блоков, однако отметим, что адреса увеличиваются на 1 для каждого блока. В любом современном компьютере это означало бы, что каждая ячейка может содержать байтово-байтовую адресацию, которая уже десятилетия является нормой. Однако байт только 8 бит и может варьироваться от 0 до 255 (для значений без знака); все же они показывают намного большее значение, сохраненное в одном из этих адресов, что очень подозрительно. (Это могло бы работать, если бы это была машина с адресом слова, но это не говорит об этом, и сегодня мало машин, хотя некоторые образовательные машины так и есть.)
Хотя бывают ситуации, когда это мышление верно, вы смешиваете метафоры здесь. Понятие переменной относится к алгоритму и его намерению - нет необходимости предполагать, что все переменные имеют ячейки памяти. Некоторые переменные (особенно массивы) имеют области памяти, потому что области памяти поддерживают адресацию (тогда как регистры ЦП могут быть названы только не проиндексированными).
Для выполнения существует логическое отображение между переменными и операторами и местами памяти процессора и последовательностями команд процессора. Переменная, значение которой никогда не изменяется (например, константа), даже не обязательно требует места в памяти, поскольку значение может быть воспроизведено по желанию (например, как необходимо для последовательностей кода, сгенерированных компилятором).
источник
for
индекса цикла, когда компилятор решает полностью развернуть цикл. Нигде в полученном выходном коде (будь то сборка, машинный код или байт-код) нет места в памяти, в котором хранится счетчик цикла. Но это все еще переменная.source
равной длины,dest
то цикл, закодированный как,for (int i=0; i<8; ++i) dest[i] = source[i];
вполне может скомпилироваться во что-то, эквивалентное повторениюdest++ = source++;
подходящего числа раз. С самим счетчиком цикла нигде нет свидетельств (даже в регистре), и только количество повторений говорит вам о состоянии цикла.Нет. Переменная и место в памяти - это две абстракции на двух разных уровнях абстракции. Переменная и указатели являются понятием более высокого уровня на уровне кода / языка, расположение памяти - понятием более низкого уровня на уровне машины. Как только код был скомпилирован в исполняемый файл, переменных больше нет. Попытка говорить о расположении памяти и переменных таким способом является категорической ошибкой.
Переменная может быть реализована с использованием памяти, но не всегда, поскольку компилятор может оптимизировать вычисления и выполнять все вычисления, относящиеся к переменной, полностью в регистрах, или он может поместить одну переменную в несколько мест памяти, или он может использовать одну память место для нескольких переменных.
Эта серия карточек настолько запутана, что они не просто не правы, но даже не ошибаются.
источник
Once a code had been compiled into an executable, there's no longer any variables.
Это то, с чем я, возможно, не согласен. Правильно, что ваша переменная в том виде, в каком вы ее знаете (то есть под этим именем), больше не существует, но, похоже, ваша фраза предполагает, что скомпилированный исполняемый файл использует только адреса памяти. Это не правильно. Ваш скомпилированный, но не исполняемый исполняемый файл не знает, какие адреса памяти он будет использовать при выполнении. Концепция переменной (т. Е. Повторно используемой ссылки на любой адрес памяти, который будет назначен во время выполнения) все еще существует внутри скомпилированного исполняемого файла.Переменные являются языковыми конструкциями . Они имеют имя, находятся в области видимости, на них могут ссылаться другие части кода и т. Д. Они представляют собой логическую сущность. Компилятор может реализовать эту языковую конструкцию любым удобным для нее способом, если наблюдаемое поведение соответствует стандарту языка. Таким образом, переменная даже не должна храниться где-либо, если компилятор может доказать, что это не нужно.
Места памяти - это аппаратная концепция . Они обозначают место в виртуальной / физической памяти. Каждая ячейка памяти имеет ровно один физический адрес и любое количество виртуальных адресов, которые могут использоваться для манипулирования им. Но в каждой ячейке памяти всегда хранится ровно один байт.
Указатели - это особый вид ценностей . Сказать что-то - указатель - все равно что сказать что-то типа
double
. Он указывает, сколько битов используется для значения и как эти биты интерпретируются, но это не означает, что это значение хранится в переменной, и не означает, что это значение хранится в памяти.Чтобы привести пример в C: Когда у меня есть 2D-массив,
int foo[6][7];
и я обращаюсь к его элементу с помощьюfoo[1][2]
, тогдаfoo
это переменная, которая содержит массив. Когдаfoo
используется в этом контексте, он превращается в указатель на первый элемент массива. Этот указатель не хранится ни в одной переменной и не сохраняется в памяти, его значение генерируется только в регистре ЦП, используется и затем забывается. Аналогично, выражениеfoo[1]
превращается в другой указатель в этом контексте, который, опять же, не находится в переменной, не сохраняется в памяти, но вычисляется в ЦП, используется и забывается. Три понятия: переменная , место в памяти и указатель - это на самом деле три разных понятия.Кстати, я действительно имел в виду «в каждой ячейке памяти всегда хранится ровно один байт». Это было не так в каменном веке вычислений около пятидесяти лет назад, но это верно практически для всего оборудования, которое используется сегодня. Всякий раз, когда вы сохраняете значение в памяти, которое превышает один байт, вы фактически используете несколько последовательных ячеек памяти. Т.е. (при условии порядка байтов с прямым порядком байтов) число 0x01234567 сохраняется в памяти как
(Машины с прямым порядком байтов, такие как архитектура X86, хранят байты в обратном порядке.) Это также верно для указателей: указатель на 64-битной машине хранится в восьми последовательных байтах, каждый со своим собственным адресом памяти. Вы не можете посмотреть на ячейку памяти и сказать: «О, это указатель!» Вы всегда видите только байты, когда смотрите на память .
источник
Позвольте мне сосредоточиться на вашем актуальном вопросе - "кто прав?" при сравнении этих двух утверждений:
Ответ на это нет . Первый говорит о «адресе памяти другой переменной», но переменные не обязательно имеют адреса памяти, как уже объяснили другие ответы. Второй говорит, что «указатель - это область памяти», но указатель - это буквально просто число, которое может храниться в переменной, но, как и раньше, переменная не обязательно имеет адрес в памяти.
Несколько примеров для более точных утверждений:
«Указатель - это число, представляющее адрес памяти ячейки памяти», или
«Переменная-указатель - это переменная, значением которой является адрес памяти ячейки памяти».
«Адрес памяти может содержать указатель, представляющий адрес памяти ячейки памяти».
Обратите внимание, что иногда термин «указатель» используется в качестве ярлыка для «переменной указателя», что нормально, если это не приводит к путанице.
источник
Я, конечно, не сказал бы, что указатель - это область памяти, которая содержит адрес. С одной стороны, я не знаю архитектуры, где
0x23453
можно было бы разместить один байт. :) Даже если вы удалите различие в байтах / словах, у вас все равно будет проблема, что каждая ячейка памяти содержит адрес. Адреса - это просто цифры, а содержимое памяти - просто цифры.Я думаю, что хитрость здесь в том, что «указатель» описывает намерение человека , а не какую-то особенность архитектуры. Это похоже на то, как «символ» или «строка» - это не конкретная вещь, которую вы можете видеть в памяти - все это тоже просто числа, но они функционируют как строки, потому что именно так к ним относятся. «Указатель» просто означает значение, предназначенное для использования в качестве адреса.
Честно говоря, если ваша цель состоит в том, чтобы преподавать определенный язык (Цель C?), Я не уверен, что вытягивание классической магнитной ленты даже настолько полезно. Вы уже говорите ложную ложь, показывая напечатанные значения и значения, слишком большие для байта. Обучайте семантике, а не механике - ключевое понимание указателей заключается в том, что они обеспечивают косвенное обращение , что является чрезвычайно полезным инструментом для понимания.
Я думаю, что хорошее сравнение может быть с URL, который говорит вам, где найти некоторые данные, но не сами данные. Выслушай меня:
Вы редко волнует , что URL на самом деле является ; Подавляющее большинство из них скрыто в связях с именами. Многие люди используют Интернет, не зная точно, как URL приводит к странице; некоторые люди полностью забывают об URL.
Не каждая строка является URL-адресом или предназначена для использования в качестве URL-адреса.
Если вы попытаетесь посетить поддельный URL или страницу, которая раньше существовала, но с тех пор была удалена, вы получите сообщение об ошибке.
URL-адрес может указывать на изображение, текст, музыку или любое количество других отдельных элементов - или на страницу, содержащую различные элементы. Очень часто бывает целая куча страниц с одинаковыми макетами, но разными данными.
Если вы создаете веб-страницу и хотите ссылаться на данные на какой-либо другой веб-странице, вам не нужно копировать и вставлять все это; Вы можете просто сделать ссылку на него.
Любое количество других страниц может ссылаться на тот же URL.
Если у вас есть коллекция похожих страниц, вы можете создать индексную страницу со списком ссылок на все из них, или у вас может быть просто «следующая» ссылка внизу страницы 1, которая приведет вас на страницу 2, и так далее. Преимущества и недостатки обоих подходов сразу очевидны, особенно если учесть, что нужно сделать веб-мастеру для добавления или удаления страниц в разных местах.
Эта аналогия очень ясно показывает, для чего нужны указатели , что очень важно для их понимания - в противном случае они просто кажутся произвольными, сложными и бессмысленными. Понять, как что-то работает , гораздо проще, если вы уже понимаете, что это делает и почему это полезно. Если вы уже усвоили, что указатель - это какой-то черный ящик, который сообщает вам, где находится что-то еще, а затем вы узнаете о тонкостях модели памяти, то представление указателей в качестве адресов является довольно очевидным. Кроме того, преподавание семантики сделает ваших учеников намного лучше для понимания и изобретения других форм косвенного обращения - что хорошо, когда большинство основных языков вообще не имеют указателей!
источник
every memory location contains an address
- Каждая ячейка памяти имеет адрес. Он не содержится нигде, кроме, возможно, в переменной указателя.Я знаю, что вы уже приняли ответ, и на этот вопрос уже есть пять ответов, но есть момент, который они не упоминают, который, я думаю, сбил вас с толку. Учебники CS часто пытаются быть агностиком в отношении выбора языка программирования, что приводит к неявному предположению, что терминология, используемая для описания вещей, универсальна. Это не так.
В Си унарный оператор амперсанда называется оператором адресации. Программисты C без колебаний скажут, что выражение
&x
вычисляется по адресу переменной x. Конечно, они означают «адрес памяти, в котором хранится значение переменной x», но никто не настолько педантичен в случайном разговоре. В языке C слово «указатель» обычно относится к типу данных переменной, для которой в качестве значения используется адрес памяти. Или, что то же самое, тип данных значения. Но некоторые люди использовали бы «указатель» как само значение.В Java все переменные типа объекта или массива ведут себя подобно указателям на C (за исключением арифметики указателей), но Java-программисты называют их ссылками, а не указателями.
C ++ считает ссылки и указатели разными понятиями. Они связаны, но не совсем одно и то же, поэтому программисты на C ++ должны делать различие в разговоре. Амперсанд читается как «адрес» в некоторых контекстах и «ссылка» в других.
Вот как программист C может описать это, используя «указатель» в том же смысле, что и «int». (Например, «указатель содержит адрес памяти, а int содержит целое число в определенном диапазоне.»)
Это странный способ сказать это, потому что это требует очень свободного и неформального определения «есть».
Было бы яснее сказать, что адрес памяти - это место в памяти, где хранится значение переменной. (Конечно, не все переменные хранятся в памяти из-за оптимизации компилятора, но любая переменная, адрес которой взят с,
&x
будет.)источник
Оператор Указатель - это переменная, значение которой является адресом памяти другой переменной , упрощенно. Но к тому моменту, когда читатель поймет, что такое область памяти и чем она отличается от переменной, он уже поймет, что такое указатель, и, следовательно, больше не будет нуждаться в этом неточном объяснении.
Оператор Указатель является ячейкой памяти, значение которой является адресом памяти другой ячейки памяти, неверно. Значение указателя не нужно хранить в ячейке памяти, и это спорно , если указатель должен ссылаться на ячейку памяти, в зависимости от предполагаемого определения «памяти».
Область памяти - это одно из нескольких возможных мест, где могут храниться данные. Эти данные могут быть переменной или частью переменной. Переменные - это способ маркировки данных.
источник
Этот ответ фокусируется на C и C ++; это кажется уместным, поскольку ваш вопрос касается указателей, которые являются более неотъемлемой частью C / C ++, чем других языков. Большая часть этого поста будет применяться к большинству скомпилированных языков без сложного времени выполнения (например, Pascal или Ada, но не как Java или C #).
Хорошие ответы, которые уже даны, подчеркивают, что переменная - это языковая конструкция на более абстрактном уровне, чем физическая память. Я хотел бы подчеркнуть, что эта абстракция имеет определенное обоснование и систему:
Абстракция в основном состоит в использовании имени вместо буквального адреса.
Основная идея заключается в том, что переменная является именованным дескриптором для типизированного объекта; объекты в C / C ++ обычно находятся в памяти. Затем языки добавляют некоторые тонкости, касающиеся управления временем жизни и маршалингом данных для преобразования типов. Концепция переменных является более абстрактной, чем физические адреса, потому что нас не волнует числовое значение адресов или точное расположение функций в памяти. Мы просто называем их, а затем называем их по имени, а компилятор, компоновщик и система времени выполнения заботятся о мельчайших деталях.
И не делайте вид, что C / C ++ не зависят от памяти: в конце концов, существует универсально применимый адресный оператор. Да, правда, вы не можете взять адрес переменной C в классе хранения регистров; но когда вы последний раз использовали один? Это особое исключение из общей концепции, а не массовое отклонение аргумента. Наоборот, общее правило заключается в том, что получение адреса переменной фактически заставляет компилятор действительно создавать объект в памяти, даже если это не будет сделано иначе (например, с константами). Концепция «именованного дескриптора» также является хорошей парадигмой для ссылок C ++: ссылка - это просто другое имя для того же объекта.
Когда я писал встроенный ассемблер для 68k, было приятно видеть, как вы можете использовать имена переменных в качестве смещений для адресов регистров (и вы можете использовать имена переменных, объявленные
register
вместо имен регистров с нуля!). Для компилятора переменная - это постоянное смещение адреса. Повторим: переменные называются дескрипторами, обычно для объектов в памяти.источник
Звучит так, как будто вопрос направлен на популярный язык, образованный путем дополнения стандарта C дополнительной гарантией: «В тех случаях, когда некоторые части стандарта или документация реализации описывают поведение какого-либо действия, а другая часть классифицирует его как неопределенное , первая часть доминирует. », а также определение« переменная », согласующееся с использованием этого термина другими языками.
На этом языке каждая ячейка памяти может рассматриваться как пронумерованный почтовый ящик, который всегда содержит некоторое количество (обычно восемь) битов, каждый из которых может независимо равняться нулю или единице. Места памяти обычно организованы в ряды из двух, четырех или восьми. и некоторые операции обрабатываются в нескольких последовательных ячейках памяти одновременно. В зависимости от машины, некоторые операции, которые работают с группами из двух, четырех или восьми ячеек памяти, могут быть ограничены операциями над местами в одной строке. Кроме того, хотя некоторые машины могут иметь одну комнату с последовательно пронумерованными почтовыми ящиками, другие могут иметь несколько непересекающихся групп пронумерованных почтовых ящиков.
Переменная определяет диапазон областей памяти, которые связаны исключительно с ней, и тип, в котором эти области памяти должны интерпретироваться. Чтение переменной приведет к тому, что биты в ее соответствующих местах хранения будут интерпретироваться способом, соответствующим типу переменной, а запись переменной приведет к тому, что соответствующие биты будут установлены способом, соответствующим ее типу и значению.
Адрес содержит любую информацию, необходимую для идентификации почтового ящика. Это может быть сохранено как простое число или как обозначение какой-либо группы вместе с номером почтового ящика в этой группе.
Применение
&
оператора к переменной даст указатель, который инкапсулирует адрес и его тип. Применение унарного*
или[]
оператора к указателю приведет к тому, что биты почтовых ящиков, начинающиеся с инкапсулированного адреса, будут интерпретированы или установлены способом, соответствующим инкапсулированному типу.источник
Я опаздываю на эту вечеринку, но я не могу удержаться, вставив свои 2 цента.
В эти времена, в чем разница между значениями, хранящимися в этих местах памяти?
Время 1
Время 2
Правильный ответ: ничего. Все они представляют собой одинаковые ценности, представленные в разных интерпретациях их значения.
Откуда я это знаю? Потому что я тот, кто придумал это. Вы действительно еще этого не знаете.
Вы сталкиваетесь с тем, что я называю проблемой вне группы . Как правильно интерпретировать значение этих значений здесь не хранится. Это знание хранится в другом месте. Тем не менее, когда вы представляете эти ценности на бумаге, вы помещаете эту интерпретацию. Это означает, что вы добавили информацию, которой просто нет в этих местах памяти.
Например, значения здесь идентичны, но вы знаете, что это правда, если вы правы, когда вы предполагаете, что кодировка символов ASCII / UTF-8 - это то, как я получил первое, а не произнесение EBCDIC . И вы также должны предположить, что второе - это шестнадцатеричные выражения числовых значений, хранящихся в этих ячейках памяти, которые могут быть указателями на другие адреса, а не ссылками на строки, которые начинаются с «0x». :П
Ничто, хранящееся в этих местах памяти, не говорит о том, что любое из этих предположений является верным Эта информация может быть сохранена. Но это будет храниться в другом месте.
Это проблема презентации . Вы не можете выразить любое число вообще без предварительного согласования того, как его представить. Вы можете опираться на предположения, соглашения и контекст, но если вы глубоко вникаете в это, когда презентация явно не определена, единственный действительно правильный ответ - «недостаточно информации».
источник