Основы программирования

Сложные описания


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

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

    int *(x[10]);

    означает "массив из 10 элементов типа указатель на int";

  • при отсутствии скобок приоритеты конструкций описания распределены следующим образом:

    • - операция * определения указателя имеет самый низкий приоритет. Например, описание

      int *x[10];

      означает "массив из 10 элементов типа указатель на int". Здесь к имени переменной x сначала применяется операция определения массива [] (квадратные скобки), поскольку она имеет более высокий приоритет, чем звездочка. Затем к полученному массиву применяется операция определения указателя. В результате получается "массив указателей", а не указатель на массив! Если нам нужно определить указатель на массив, то следует использовать круглые скобки при описании:

      int (*x)[10];

      Здесь к имени x сначала применяется операция * определения указателя;

    • операции определения массива [] (квадратные скобки после имени) и определения функции (круглые скобки после имени) имеют одинаковый приоритет, более высокий, чем звездочка. Примеры:

      int f();

      Описан прототип функции f без аргументов, возвращающей значение типа int.

      int (*f())[10];

      Описан прототип функции f без аргументов, возвращающей значение типа указатель на массив из 10 элементов типа int;

  • последний пример уже не является очевидным. Общий алгоритм разбора сложного описания можно охарактеризовать как чтение изнутри. Сначала находим описываемое имя. Затем определяем, какая операция применяется к имени первой. Если нет круглых скобок для группировки, то это либо определение указателя (звездочка слева от имени), либо определение массива (квадратные скобки справа от имени), либо определение функции (круглые скобки справа от имени). Таким образом получается первый шаг сложного описания. Затем находим следующую операцию описания, которая применяется к уже выделенной части сложного описания, и повторяем это до тех пор, пока не исчерпаем все описание. Проиллюстрируем этот алгоритм на примере:

    void (*a[100])(int x);

    Описывается переменная a. К ней сначала применяется операция описания массива из 100 элементов, далее - определение указателя, далее - функция от одного целочисленного аргумента x типа int, наконец - определение возвращаемого типа void. Описание читается следующим образом:

    1. a - это
    2. массив из 100 элементов типа
    3. указатель на
    4. функцию с одним аргументом x типа int, возвращающую значение типа
    5. void.

    Ниже расставлены номера операций в порядке их применения в описании переменной a:

    void (* a [100])(int x); 5) 3) 1) 2) 4)



Содержание раздела