Задний план
Оператор объявления переменной в C состоит из трех частей: имя переменной, ее базовый тип и модификатор (ы) типа .
Существует три вида модификаторов типов:
- Указатель
*
(префикс) - Массив
[N]
(постфикс) - Функция
()
(постфикс)- Вы можете указать список аргументов функции внутри паренов, но ради этого вызова давайте проигнорируем его и просто используем
()
(что технически означает «функция может принимать аргументы любого типа»).
- Вы можете указать список аргументов функции внутри паренов, но ради этого вызова давайте проигнорируем его и просто используем
И способ считывания обозначений заключается в следующем:
int i; // i is an int
float *f; // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func(); // func is a function returning an int
Уловка в том, что мы можем смешать все это, чтобы сформировать более сложный тип, такой как массив массивов или массив указателей на функции или указатель на массив указателей :
int arr[3][4];
// arr is an array of 3 arrays of 4 ints
int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int
float *(*p)[16];
// p is a pointer to an array of 16 pointers to float
Как я прочитал эти сложные заявления?
- Начните с имени переменной.
(name) is ...
- Выберите модификатор с наивысшим приоритетом.
- Прочитайте это:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Повторите 2 и 3, пока модификаторы не будут исчерпаны.
- Наконец, прочитайте базовый тип.
... (base type).
В C постфиксные операторы имеют приоритет над префиксными операторами, и модификаторы типов не являются исключением. Поэтому []
и ()
связывай сначала, потом *
. Все, что находится в паре паренов (...)
(не путать с оператором функции), сначала связывается с чем-либо снаружи.
Иллюстрированный пример:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
задача
Учитывая строку оператора объявления переменной, написанную на C, выведите английское выражение, которое описывает строку, используя метод, показанный выше.
вход
Входные данные представляют собой один оператор C, который включает в себя один базовый тип, одно имя переменной, ноль или более модификаторов типов и конечную точку с запятой. Вы должны реализовать все элементы синтаксиса, описанные выше, плюс:
- И базовый тип, и имя переменной соответствуют регулярному выражению
[A-Za-z_][A-Za-z0-9_]*
. - Теоретически, ваша программа должна поддерживать неограниченное количество модификаторов типов.
Вы можете упростить другие элементы синтаксиса C следующими способами (полная реализация также приветствуется):
- Базовый тип всегда одно слово, например
int
,float
,uint32_t
,myStruct
. Нечто подобноеunsigned long long
не будет проверено. - Для обозначения массива
[N]
, числоN
всегда будет одно целое положительное число записывается в базе 10. Такие вещи , какint a[5+5]
,int a[SIZE]
илиint a[0x0f]
не будут проверены. - Для обозначения функции
()
никакие параметры не будут указаны вообще, как указано выше. - Для пробелов
0x20
будет использоваться только пробел . Вы можете ограничить вашу программу определенным использованием пробелов, например- Используйте только один пробел после базового типа
- Используйте пробел везде между токенами
- Однако вы не можете использовать два или более последовательных пробела для передачи большего количества информации, чем в качестве разделителя токенов.
Согласно синтаксису C, следующие три комбинации недопустимы и, следовательно, не будут проверяться:
f()()
Функция возврата функцииf()[]
Функция, возвращающая массивa[]()
Массив из N функций
Разработчики на C вместо этого используют эти эквивалентные формы (и все они описаны в тестовых примерах):
(*f())()
Функция, возвращающая указатель на функцию*f()
Функция, возвращающая указатель на первый элемент массива(*a[])()
Массив из N указателей для работы
Выход
Результатом является одно английское предложение. Вам не нужно (но вы можете, если хотите) соблюдать грамматику английского языка, например, использование a, an, the
форм единственного / множественного числа и конечную точку (точка). Каждое слово должно быть разделено одним или несколькими пробелами (пробел, табуляция, новая строка), чтобы результат был удобочитаемым.
Опять же, вот процесс преобразования:
- Начните с имени переменной.
(name) is ...
- Выберите модификатор с наивысшим приоритетом.
- Прочитайте это:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Повторите 2 и 3, пока модификаторы не будут исчерпаны.
- Наконец, прочитайте базовый тип.
... (base type).
Контрольные примеры
int i; // i is int
float *f; // f is pointer to float
my_struct_t s[10]; // s is array of 10 my_struct_t
int func(); // func is function returning int
int arr[3][4]; // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16]; // p is pointer to array of 16 pointer to float
_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
1234 array of 567 _RANdom_TYPE_123 */
uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
pointer to uint32_t */
uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens
some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
function returning pointer to function returning pointer to
function returning pointer to function returning some_type */
Критерий оценки и выигрыша
Это вызов для игры в гольф . Программа с наименьшим количеством байтов побеждает.
int arr[3][4];
есть an array of 3 arrays of 4 ints
(как ты говоришь) или an array of 4 arrays of 3 ints
?
;
в конце строки?