Раздел: Курсы / Указатели /

Типизированные и нетипизированные указатели

Куда указывают указатели Куда указывают указатели

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

Думаю, вы уже знаете, что указатели могут быть типизированными и нетипизированными.

Типизированный указатель содержит ссылку на область памяти, где хранятся данные определенного типа (byte, real и т.п.).

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

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

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

var P1   : ^integer;  //Типизированный указатель
    P2   : ^single;   //Типизированный указатель 
    P3   : pointer;   //Нетипизированный указатель

то такой код:

P1 := P2;

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

P3 := P2;
P1 := P3;

то есть мы таки записали в указатель Р1 значение указателя Р2. Кстати, можете взять этот приём на вооружение - в некоторых редких случаях это может быть необходимо. Однако в большинстве случаев это является ошибкой (хотя компилятор её не заметит и программа будет создана). Эту ошибку показывает следующий пример:

program myprog;

var iNum : integer;   //Переменная целого типа
    fNum : single;    //Переменная вещественного типа
    P1   : ^integer;  //Типизированный указатель
    P2   : ^single;   //Типизированный указатель
    P3   : pointer;   //Нетипизированный указатель

begin
  iNum := 100;
  fNum := 100;

  WriteLn('iNum = ', iNum);       //Выведет 100
  WriteLn('fNum = ', fNum:0:1);   //Выведет 100.0

  P1 := @iNum;        //Р1 = адрес переменной iNum
  P2 := @fNum;        //Р2 = адрес переменной fNum

  WriteLn('iNum = ', P1^);        //Выведет 100

  //Это не вызовет ошибки, однако так делать опасно,
  //потому что теперь в память по адресу, где должна храниться
  //целочисленная переменная, записаны данные вещественного типа,
  //и искажение данных гарантировано
  P3 := P2;
  P1 := P3;
  
  //Выведет 1120403456 или что-то типа того
  iNum := P1^;
  WriteLn('iNum = ', iNum);
  
  ReadLn;
end.

Типизированные и нетипизированные указатели

Здесь, во-первых, мы разрываем связь между указателем Р1 и переменной iNum. Ну это ладно, это не страшно. Давайте посмотрим, что же мы натворили:

  1. Адрес переменной fNum, который хранился в указателе Р2, мы поместили в нетипизированный указатель Р3. При этом помним, что в переменной fNum у нас хранится вещественное число 100.
  2. Далее в указатель Р1 мы записали значение указателя Р3. То есть таким образом мы в указатель Р1 записали адрес переменной fNum.
  3. И теперь указатель Р1 содержит ссылку на место в памяти, где хранится число 100.
  4. Однако, если мы получим данные, на которые ссылается указатель Р1, и сохраним их в переменную iNum, то это будет не 100, а какое-то непонятное число.

Таким образом мы получили “искажённую картину мира”, то есть наши ожидания не оправдались и мы не смогли преобразовать через указатели вещественное число в целое. А всё потому, что представление целых и вещественных чисел в памяти компьютера совершенно разное. И не зря компилятор ругается, когда мы пытаемся напрямую присвоить значение типизированного указателя одного типа указателю другого типа.

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


Директивы компилятора Директивы компилятора
Как это ни странно, но даже многие опытные программисты не используют директивы компилятора, считая их чем-то ненужным и бесполезным. А между тем, директивы компилятора - это очень классная штука. Если их умело применять в своих программах, то можно существенно сократить время на разработку и уменьшить количество рутинных операций. Подробнее...
Инфо-МАСТЕР ®
Все права защищены ©
e-mail: mail@info-master.su

Яндекс.Метрика