Я пытаюсь выяснить некоторые C-декларации. В чем смысл этих С-деклараций?
double (*b)[n]; double (*c[n])(); double (*d())[n];
double (*b)[n];
b – указатель на массив из n удвоений
double (*c[n])();
c – массив из n указателей на функции, принимающие неопределенное количество аргументов и возвращающих двойные
double (*d())[n];
d – функция, принимающая неопределенное число аргументов и возвращающая указатель на массив из n удвоений
В общем, для того, чтобы разобрать эти декларации в вашей голове, сделайте следующий подход. Давайте посмотрим последнее объявление, например
double (*d())[n];
что первое, что делается с d? Он вызывается с помощью (), поэтому это функция, которая принимает неопределенное количество аргументов и возвращает … что сработало с результатом? Он разыменован (*), поэтому он является указателем на . Затем результат индексируется, поэтому он представляет собой массив n … что осталось? двойной, поэтому из двухместных . Читая части, выделенные жирным шрифтом, вы получите ответ.
Давайте посмотрим другой пример
void (*(*f)(int)[n])(char)
Здесь f сначала разыменовывается, поэтому он является указателем на … он затем вызывается с (int), поэтому функция принимает int и возвращает , результат затем индексируется с помощью [n], поэтому массив из n . Результат разыменовывается снова, поэтому указывает на . Тогда результат вызывается (char), поэтому функции, принимающие char и возвращающие (все оставлены недействительными) void . Таким образом, f является указателем на функцию, принимающую int и возвращающую массив из n указателей на функции, принимающие char и возвращающие void .
НТН
Основное правило для синтаксического анализа деклараций C «читается справа налево, а изнутри выпрыгивает вправо, оставляя пару круглых скобок», т.е. начинаем самую глубоко вложенную пару круглых скобок, а затем начинаем искать вправо. Технически вы должны знать ассоциативность операторов, но она работает достаточно хорошо в большинстве ситуаций.
Теперь примените это (упрощенное) правило к вашему вопросу:
double (*b)[n]; ^
b –
double (*b)[n]; ^
указатель на
double (*b)[n]; ^^^
и массив
double (*b)[n]; ^^^^^^
двойников.
double (*c[n])(); ^^^^
c – массив
double (*c[n])(); ^
указатели на
double (*c[n])(); ^^
функции
double (*c[n])(); ^^^^^^
возrotation двойным.
double (*d())[n]; ^^^
d – функция
double (*d())[n]; ^
возвращая указатель на
double (*d())[n]; ^^^
массив
double (*d())[n]; ^^^^^^
двойники
Существует чистая утилита, найденная на большинстве * nixes, называемая cdecl , которая берет строку декларации C и превращает ее в предложение естественного языка.
Попробуйте этот путь.
во-первых, вы должны быть знакомы с этими тремя символами:
1. * - указатель. 2. [] - массив. 3. () - функция. (Извещение: не круглые скобки)
в качестве примера возьмем «double (* d ()) [n]».
первый шаг – найти идентификатор в объявлении, идентификатор – это имя переменной, здесь это «d».
(я) - что такое «d»? -------------------------------------------------- ---------------------- посмотрите на правую часть идентификатора, чтобы увидеть, есть ли «[]» или «()»: ... d [] ...: d - массив. ... d () ...: d - функция. если нет, посмотрите на левую сторону, чтобы увидеть, есть ли «*»: ... * d ...: d - указатель. -------------------------------------------------- ----------------------
теперь мы обнаружили, что d является функцией. используйте x для замены d (), тогда объявление становится «double (* x) [n]»
(II) - что такое «х»? -------------------------------------------------- ---------------------- repeat (i), мы находим, что x является указателем. это означает, что d - это функция, возвращающая указатель. -------------------------------------------------- ----------------------
используйте y для замены * x, тогда объявление становится «double y [n]»
(III) - что такое «у»? -------------------------------------------------- ---------------------- repeat (i), мы находим, что y является массивом из n элементов. это означает, что d - это функция, возвращающая указатель на массив из n элементов. -------------------------------------------------- ----------------------
используйте z для замены y [n], тогда объявление становится «double z»,
(IV) - Что такое «z»? -------------------------------------------------- ---------------------- Повторяем (i), получаем, что z является двойным. это означает, что d - это функция, возвращающая указатель на массив из n двойных элементов. -------------------------------------------------- ----------------------
давайте посмотрим другое выражение:
void (* (* f) (int) [n]) (char)
1. мы найдем f. 2. f - указатель. * f -> a void (* a (int) [n]) (char) 3. a - функция. a () -> b void (* b [n]) (char) -f - указатель на функцию (с параметром int) - 4. b - массив. b [] -> c void (* c) (char) -f - указатель на функцию, возвращающую массив (из n элементов) - 5. c - указатель. * c -> d void d (char) -f - указатель на функцию, возвращающую массив из n указателей - 6. d - функция, возвращающая пустоту. -f - указатель на функцию, возвращающую массив из n указателей на функции (с параметром char), возвращающий void -
Есть два больших ресурса для понимания «C gibberish»:
Вывод cdecl.org:
double (*c[n])()
: Синтаксическая ошибка ( n
здесь недействительна) double (*c[])()
: объявить c как массив указателя на функцию, возвращающую double