Шаг 214.
Язык программирования C#. Начала.
Указатели. Многоуровневая адресация

    На этом шаге мы рассмотрим использование указателей на указатели.

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

    Чтобы понять, как объявляется указатель на указатель, следует учесть, что при объявлении указателя с использованием идентификатора типа, на значение которого может ссылаться указатель, указывается звездочка *. Например, инструкция int* используется при объявлении указателя на переменную типа int. Тогда при объявлении указателя на указатель на значение типа int используется идентификатор int**. Как иллюстрацию к использованию указателей на указатели рассмотрим программу ниже.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr214_1
{
    // Главный класс:
    class Program
    {
        // Главный метод:
        unsafe static void Main()
        {
            // Целочисленные переменные: 
            int A, B;
            // Указатель на целочисленную переменную: 
            int* p;
            // Указатель на указатель на целочисленную 
            // переменную: 
            int** q;
            // Значение указателя на указатель: 
            q = &p;
            // Значение указателя: 
            p = &A;
            // Переменной A присваивается значение 
            // (через указатель на указатель):
            **q = 123;
            // Проверка значения переменной A:
            Console.WriteLine(A);
            // Новое значение указателя:
            *q = &B;
            // Переменной B присваивается значение 
            // (через указатель):
            *p = 321;
            // Проверка значения переменной B:
            Console.WriteLine(B);
        }
    }
}
Архив проекта можно взять здесь.

    Ниже показано, каким будет результат выполнения программы:


Рис.1. Результат выполнения программы

    В программе мы объявляем переменные A и B типа int, указатель p на значение типа int, а командой

  int** q;
объявляется указатель q, который может ссылаться на указатель, который, в свою очередь, может ссылаться на переменную типа int.

    Командой

 q = &p; 
в указатель q записывается адрес переменной р, которая сама является указателе м. Указателю р значение присваивается командой
  p = &A;      . 
Что мы получили? Имеются переменные (указатель ведь - это тоже переменная) A, р и q. Адрес переменной A записан в переменную p, а адрес переменной p записан в переменную q. Выражение *q - это значение, записанное по адресу, который хранится в q. В указателе q хранится адрес указателя р. Поэтому выражение *q является эквивалентом р. Далее, если *q - это то же, что и р, то **q - это то же, что и . А - это значение переменной A, поскольку указатель р ссылается на переменную A. Поэтому при выполнении команды
  **q = 123; 
переменной A присваивается значение 123.

    А вот когда выполняется команда

  *q = &B;      , 
то в указатель р записывается адрес переменной B. После этого выполнение команды
  *р = 321; 
приводит к тому, что переменной B присваивается значение 321.

    На следующем шаге мы рассмотрим массивы указателей.




Предыдущий шаг Содержание Следующий шаг