Фон
Заява змінної декларації в 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 оператори Postfix мають перевагу над префіксними операторами, і модифікатори типу не є винятком. Тому []
і ()
зв’яжіть спочатку, потім *
. Все, що знаходиться всередині пари паронів (...)
(не плутати з оператором функції), пов'язує спочатку над чим-небудь зовнішнім.
Ілюстрований приклад:
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_]*
. - Теоретично ваша програма повинна підтримувати необмежену кількість модифікаторів типів.
Ви можете спростити інші елементи синтаксису С наступними способами (також можлива повна реалізація):
- Базовий тип завжди одне слово, наприклад
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
?
sizeof(arr[0]) == sizeof(int[4])
, тому елемент arr
містить чотири int
с.
;
в кінці рядка?