tło
Instrukcja deklaracji zmiennej w C składa się z trzech części: nazwy zmiennej, jej typu podstawowego i modyfikatora (-ów) typu .
Istnieją trzy rodzaje modyfikatorów typów:
- Wskaźnik
*
(przedrostek) - Array
[N]
(postfix) - Funkcja
()
(postfiks)- Możesz podać listę argumentów funkcji w parenach, ale ze względu na to wyzwanie zignorujmy je i po prostu użyjmy
()
(co technicznie oznacza, że „funkcja może przyjmować dowolne argumenty”).
- Możesz podać listę argumentów funkcji w parenach, ale ze względu na to wyzwanie zignorujmy je i po prostu użyjmy
Sposób odczytania notacji jest następujący:
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
Chodzi o to, że możemy mieszać je wszystkie, aby utworzyć bardziej skomplikowany typ, taki jak tablica tablic lub tablica wskaźników funkcji lub wskaźnik do tablicy wskaźników :
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
Jak przeczytałem te skomplikowane wypowiedzi?
- Zacznij od nazwy zmiennej.
(name) is ...
- Wybierz modyfikator o najwyższym priorytecie.
- Przeczytaj to:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
- Na koniec przeczytaj typ podstawowy.
... (base type).
W języku C operatory Postfiks mają pierwszeństwo przed operatorami Prefiks, a modyfikatory typów nie są wyjątkiem. Dlatego []
i ()
najpierw wiążę *
. Wszystko w parze parenów (...)
(nie mylić z operatorem funkcji) wiąże się najpierw nad czymkolwiek na zewnątrz.
Ilustrowany przykład:
int (*fptrs[10])();
fptrs fptrs is ...
[10] array of 10 ... // [] takes precedence over *
(* ) pointer to ...
() function returning ...
int int
Zadanie
Biorąc pod uwagę wiersz instrukcji deklaracji zmiennej napisanej w C, wypisz angielskie wyrażenie opisujące linię, używając metody pokazanej powyżej.
Wejście
Dane wejściowe to pojedyncza instrukcja C, która zawiera jeden typ podstawowy, jedną nazwę zmiennej, zero lub więcej modyfikatorów typu i końcowy średnik. Musisz zaimplementować wszystkie elementy składni opisane powyżej, a także:
- Zarówno typ podstawowy, jak i nazwa zmiennej pasują do wyrażenia regularnego
[A-Za-z_][A-Za-z0-9_]*
. - Teoretycznie twój program powinien obsługiwać nieograniczoną liczbę modyfikatorów typów.
Możesz uprościć inne elementy składni C na następujące sposoby (mile widziane jest również pełne wdrożenie):
- Typ bazowy jest zawsze jedno słowo, na przykład
int
,float
,uint32_t
,myStruct
. Coś takiegounsigned long long
nie będzie testowane. - Dla notacji tablicy
[N]
, liczbaN
zawsze będzie jedna dodatnia napisany w bazie 10. Co jakint a[5+5]
,int a[SIZE]
alboint a[0x0f]
nie będą testowane. - W przypadku notacji funkcji w
()
ogóle nie zostaną określone parametry, jak wskazano powyżej. - W przypadku białych znaków
0x20
zostanie użyty tylko znak spacji . Możesz ograniczyć program do określonego użycia białych znaków, np- Użyj tylko jednej spacji za typem podstawowym
- Użyj odstępu pomiędzy żetonami
- Nie można jednak użyć dwóch lub więcej następujących po sobie spacji, aby przekazać więcej informacji niż separator tokenów.
Zgodnie ze składnią C następujące trzy kombinacje są nieprawidłowe i dlatego nie będą testowane:
f()()
Funkcja zwracająca funkcjęf()[]
Funkcja zwracająca tablicęa[]()
Tablica funkcji N.
Programiści C używają zamiast tego tych równoważnych formularzy (wszystkie z nich są omówione w przypadkach testowych):
(*f())()
Funkcja zwracająca wskaźnik do funkcji*f()
Funkcja zwracająca wskaźnik do pierwszego elementu tablicy(*a[])()
Tablica N wskaźników do działania
Wydajność
Wynikiem jest pojedyncze zdanie angielskie. Nie musisz (ale możesz, jeśli chcesz) szanować gramatykę angielską, np. Użycie a, an, the
formy liczby pojedynczej / mnogiej i kropki (kropki). Każde słowo powinno być oddzielone jedną lub więcej białymi spacjami (spacja, tabulator, nowa linia), aby wynik był czytelny dla człowieka.
Ponownie oto proces konwersji:
- Zacznij od nazwy zmiennej.
(name) is ...
- Wybierz modyfikator o najwyższym priorytecie.
- Przeczytaj to:
* -> pointer to ...
[N] -> array of N ...
() -> function returning ...
- Powtarzaj 2 i 3, aż modyfikatory się wyczerpią.
- Na koniec przeczytaj typ podstawowy.
... (base type).
Przypadki testowe
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 */
Kryterium punktacji i wygranej
To wyzwanie dla golfa . Program z najmniejszą liczbą bajtów wygrywa.
int arr[3][4];
jest an array of 3 arrays of 4 ints
(jak mówisz), czy an array of 4 arrays of 3 ints
?
sizeof(arr[0]) == sizeof(int[4])
, więc element arr
zawiera cztery int
s.
;
koniec na końcu linii?