Операция @
Операция @ позволяет получить номер ячейки (адрес) переменной. В верхнем примере @i будет равно 54564786.
Операция p := @i занесёт данные об адресе переменной i в указатель p.
Значок ^.
Когда значок ^ стоит после названия переменной-указателя (p^), он обозначает, что указатель разыменовывают. Как я писал выше, обращаются не к данным в переменной p, а к данным, на которые указывает переменная p.
То есть p^ и i - одно и то же. Для нас. Но не для компилятора. Что бы компилятор понял, что можно делать с p^, что бы он знал, на что собственно указывает указатель (понятно, что он всегда указывает на какую-то ячейку памяти, но там может находиться начало любой переменной или объекта, а может не находится вообще ничего интересно, либо мусор, либо может быть ‘середина’ переменной, либо вообще кусок кода, а не данные. То есть, что в поинтер положили, на то он и указывает. А уж что конкретно там лежит, на что он указывает - известно только Богу. Если вы - хороший программист, то еще и вам), он должен быть типизированным. То есть он должен быть не pointer, а, например, PInteger. Тогда p^ будет распознано компилятором именно как переменная типа integer.
Если мы предварительно инициализировали указатель p адресом переменной i, написав p := @i, то после этого мы можем к i обращаться как i и как p^.
С ним (с p^) можно делать любые операции, которые возможны с integer’ом. При этом сам указатель p не меняется, меняются данные в переменной, на которую он указывает, то есть в переменной i.
Кроме этого значок ^ может использоваться в описании типа указателей в секции ‘type’, вот несколько строк из модуля system.pas:
type
PAnsiString = ^AnsiString;
end;
Здесь описывается тип PAnsiString. Тип PAnsiString описывается, как указатель на AnsiString. Именно этой строкой компилятору дают понять, что все типизированные указатели типа PAnsiString могут указывать только на переменные типа AnsiString. Это позволяет компилятору проверят верность передачи параметров в процедуры и верность работы с разыменованными указателями.
Операции сложения/вычитания с указателями.
Так как, собственно, указатели - это самые обычные 32-х разрядные числа, ничто не мешает их складывать и вычитать. В компиляторе Делфи, однако, есть ограничение - такие операции возможны только с указателями типа PChar.
Например, с указателем p: pchar можно написать p := p + 10;
Что при этом произойдет. Допустим, указатели изначально указывал на ячейку 54564786. После команды p := p + 10; он будет указывать на ячейку 54564796. Вполне вероятно, что в этой ячейке может содержаться 11-й символ массива символов s. Так же вероятно (в случае, если размер s меньше 11-ти), что в этой ячейке будет либо мусор, либо уже другая переменная, либо эту ячейку вообще нельзя читать и/или писать. Тогда, в лучшем случае можно получить т.н. AV - acess violation, в худшем - этот же AV рано или поздно появится у заказчика, который работает на другом конце Земли. Поэтому в случае применения операций сложения/вычитания с указателями желательно каким-то образом следить за границами массивов.
Inc(p) инкрементирует указатель. То есть добавляет к нему единицу, ‘продвигая’ его на SizeOf(Type) ячеек вверх. Инкремент (Inc) и декремент (Dec) возможен с любыми типизированными указателями.