Dlaczego gwiazdka występuje przed nazwą zmiennej, a nie po typie?

187

Dlaczego większość programistów C nazywa takie zmienne:

int *myVariable;

zamiast tego:

int* myVariable;

Oba są ważne. Wydaje mi się, że gwiazdka jest częścią typu, a nie częścią nazwy zmiennej. Czy ktoś może wyjaśnić tę logikę?

WBlasko
źródło
1
Drugi styl wydaje się ogólnie bardziej intuicyjny, ale ten pierwszy sposób pozwala uniknąć błędów związanych z typem w kodzie. Jeśli naprawdę przywiązujesz się do tego drugiego stylu, zawsze możesz iść typedefs, ale to doda niepotrzebnej złożoności, IMHO.
Chmura,

Odpowiedzi:

250

Są DOKŁADNIE równoważne. Jednak w

int *myVariable, myVariable2;

Wydaje się oczywiste, że moja zmienna ma typ int * , natomiast moja zmienna2 ma typ int . W

int* myVariable, myVariable2;

może się wydawać oczywiste, że oba są typu int * , ale to nie jest poprawne, ponieważ myVariable2ma typ int .

Dlatego pierwszy styl programowania jest bardziej intuicyjny.

luiscubal
źródło
135
być może, ale nie mieszałbym i nie dopasowywał typów w jednej deklaracji.
BobbyShaftoe,
15
@BobbyShaftoe Zgoda. Nawet po przeczytaniu każdego argumentu tutaj trzymam się int* someVarosobistych projektów. To ma więcej sensu.
Alyssa Haroldsen
30
@Kupiakos Ma to większy sens, dopóki nie nauczysz się składni deklaracji C opartej na „deklaracjach następujących po użyciu”. Deklaracje używają dokładnie tej samej składni, co przy użyciu zmiennych tego samego typu. Kiedy deklarujesz tablicę int, to nie wygląda: int[10] x. To po prostu nie jest składnia C. Gramatyka wyraźnie analizuje jako: int (*x)a nie jako (int *) x, więc umieszczenie gwiazdki po lewej stronie jest po prostu mylące i oparte na nieporozumieniu składni deklaracji C.
Peaker
8
Korekta: dlatego nigdy nie należy deklarować więcej niż jednej zmiennej w jednym wierszu. Zasadniczo nie należy motywować określonego stylu kodowania na podstawie innego niepowiązanego, złego i niebezpiecznego stylu kodowania.
Lundin
6
Dlatego trzymam się jednej zmiennej na deklarację wskaźnika. int* myVariable; int myVariable2;Zamiast tego nie ma absolutnie żadnych wątpliwości .
Patrick Roberts,
122

Jeśli spojrzysz na to z innej strony, *myVariablejest to rodzaj int, co ma sens.

biozynk
źródło
6
To moje ulubione wytłumaczenie i działa dobrze, ponieważ wyjaśnia ogólnie dziwactwa deklaracji C - nawet obrzydliwą i sękatą składnię wskaźnika funkcji.
Benjamin Pollack
12
To trochę fajne, ponieważ możesz sobie wyobrazić, że nie ma żadnych rzeczywistych typów wskaźników. Istnieją tylko zmienne, które przy odpowiednim odwołaniu lub odwołaniu dają jeden z podstawowych typów.
biozynk
1
W rzeczywistości „* moja zmienna” może być typu NULL. Co gorsza, może to być po prostu losowa pamięć.
qonf
4
qonf: NULL nie jest typem. myVariablemoże być NULL, w którym to przypadku *myVariablepowoduje błąd segmentacji, ale nie ma typu NULL.
Daniel Roethlisberger
28
Ten punkt może być mylący w takim kontekście: int x = 5; int *pointer = &x;ponieważ sugeruje, że int przypisujemy *pointerpewnej wartości, a nie pointersamej.
rafalcieslak
40

Ponieważ * w tym wierszu wiąże się ściślej ze zmienną niż z typem:

int* varA, varB; // This is misleading

Jak wskazuje @Lundin poniżej, const dodaje jeszcze więcej subtelności do przemyślenia. Możesz całkowicie tego uniknąć, deklarując jedną zmienną na linię, co nigdy nie jest dwuznaczne:

int* varA;
int varB;

Trudno jest znaleźć równowagę między czystym kodem a zwięzłym kodem - tuzin zbędnych wierszy również int a;nie jest dobry. Mimo to domyślnie przyjmuję jedną deklarację na wiersz i martwię się o późniejsze połączenie kodu.

ojrac
źródło
2
Cóż, pierwszy wprowadzający w błąd przykład jest moim zdaniem błędem w projekcie. Gdybym mógł, usunęłbym całkowicie ten sposób deklaracji z C i sprawiłem, że oba są typu int *.
Adam Bajger
1
„* wiąże się ściślej ze zmienną niż z typem” To naiwny argument. Zastanów się int *const a, b;. Gdzie * „wiąże”? Typ ajest int* const, więc jak możesz powiedzieć, że * należy do zmiennej, gdy jest częścią samego typu?
Lundin
1
Specyficzne dla pytania lub obejmujące wszystkie przypadki: wybierz jeden. Zrobię notatkę, ale jest to kolejny dobry argument na moją ostatnią sugestię: jedna deklaracja na linię zmniejsza możliwości zepsucia tego.
ojrac
36

Do tej pory nikt tu nie wspomniał, że ta gwiazdka jest w rzeczywistości „ operatorem dereferencyjnym ” w C.

*a = 10;

Linia powyżej nie znaczy, że chcesz przypisać 10do a, oznacza to, że chcę, aby przypisać 10do dowolnych lokalizacji pamięci awskazuje. I nigdy nie widziałem, żeby ktoś pisał

* a = 10;

czy ty? Więc operator dereferencji jest prawie zawsze zapisywany bez spacji. Jest to prawdopodobnie w celu odróżnienia tego od mnożenia podzielonego na wiele linii:

x = a * b * c * d
  * e * f * g;

To *ebyłoby mylące, prawda?

Okej, teraz co właściwie oznacza następujący wiersz:

int *a;

Większość ludzi powiedziałaby:

Oznacza to, że ajest wskaźnikiem intwartości.

Jest to technicznie poprawne, większość ludzi lubi to widzieć / czytać w ten sposób i tak definiują to współczesne standardy C (zauważ, że sam język C wyprzedza wszystkie normy ANSI i ISO). Ale to nie jedyny sposób, aby na to spojrzeć. Możesz także przeczytać ten wiersz w następujący sposób:

Dereferencjonowana wartość ajest typu int.

Tak więc gwiazdka w tej deklaracji może być również postrzegana jako operator dereferencyjny, co również wyjaśnia jej umieszczenie. I to ajest wskaźnik, który nie jest tak naprawdę zadeklarowany, wynika z faktu, że jedyną rzeczą, którą można tak naprawdę wyrejestrować, jest wskaźnik.

Norma C definiuje tylko dwa znaczenia dla *operatora:

  • operator pośredni
  • operator mnożenia

I pośrednictwo jest tylko jednym znaczeniem, nie ma dodatkowego znaczenia dla deklaracji wskaźnika, jest tylko pośrednie, czyli to, co robi operacja dereferencji, wykonuje dostęp pośredni, więc również w takiej instrukcji int *a;jest dostęp pośredni ( *oznacza pośredni dostęp), a zatem drugie oświadczenie powyżej jest znacznie bliższe standardowi niż pierwsze.

Mecki
źródło
6
Dzięki za uratowanie mnie przed napisaniem tutaj kolejnej odpowiedzi. BTW Zwykle czytam int a, *b, (*c)();jako coś w stylu „zadeklaruj następujące obiekty jako int: obiekt a, obiekt wskazywany przez bi obiekt zwracany z funkcji wskazywanej przez c”.
Antti Haapala
1
*W int *a;nie jest operator, i nie jest dereferencing a(który nie jest jeszcze nawet wyżej)
MM
1
@MM Proszę podać numer strony i wiersza dowolnego standardu ISO C, jeśli ten standard mówi, że gwiazdka może być czymś innym niż mnożenie lub pośrednie. Pokazuje tylko „deklarację wskaźnika” na przykładzie, nigdzie nie definiuje trzeciego znaczenia gwiazdki (i nie definiuje żadnego znaczenia, które nie byłoby operatorem). Och, nigdzie nie twierdziłem, że coś jest „zdefiniowane”, wymyśliłeś to. Lub, jak ujął to Jonathan Leffler, w standardzie C * jest zawsze „gramatyką”, nie jest częścią wymienionych specyfikatorów deklaracji (więc nie jest częścią deklaracji, więc musi być operatorem)
Mecki
1
@MM 6.7.6.1 pokazuje tylko oświadczenie przykład, dokładnie tak, jak powiedziałem, to nie daje sens do *(to daje tylko sens ogólnej ekspresji, a nie do *wewnątrz wyrazu!). Mówi, że „int a;” deklaruje wskaźnik, którego nie twierdzi, nigdy nie twierdził inaczej, ale bez znaczenia nadanego *, odczytanie go jako * wartość dereferencyjna wartości aint jest nadal całkowicie poprawna, ponieważ ma to samo znaczenie faktyczne. Nic, a właściwie nic napisanego w 6.7.6.1 nie byłoby sprzeczne z tym stwierdzeniem.
Mecki,
2
Nie ma „całkowitego wyrażenia”. int *a;jest deklaracją, a nie wyrażeniem. anie jest zaniedbywany przez int *a;. ajeszcze nie istnieje w momencie *przetwarzania. Czy uważasz, że int *a = NULL;jest to błąd, ponieważ nie uwzględnia wskaźnika zerowego?
MM
17

Mam zamiar iść w opałach tutaj i powiedzieć, że nie ma prostej odpowiedzi na to pytanie , zarówno dla deklaracji zmiennych i typów parametrów i powrotu, który jest to, że gwiazdka powinna iść obok nazwy: int *myVariable;. Aby docenić dlaczego, spójrz na to, jak deklarujesz inne typy symboli w C:

int my_function(int arg); dla funkcji;

float my_array[3] dla tablicy.

Ogólny wzorzec, zwany deklaracją po użyciu , polega na tym, że typ symbolu jest dzielony na część przed nazwą, a części wokół nazwy, a te części wokół nazwy naśladują składnię, której użyłbyś, aby uzyskać wartość typu po lewej:

int a_return_value = my_function(729);

float an_element = my_array[2];

i: int copy_of_value = *myVariable;.

C ++ rzuca klucz w pracy z referencjami, ponieważ składnia w punkcie, w którym używasz referencji, jest identyczna z typami wartości, więc możesz argumentować, że C ++ ma inne podejście do C. Z drugiej strony, C ++ zachowuje to samo zachowanie C w przypadku wskaźników, więc referencje naprawdę są pod tym względem dziwne.

Injektilo
źródło
12

To tylko kwestia preferencji.

Kiedy czytasz kod, rozróżnianie zmiennych i wskaźników jest łatwiejsze w drugim przypadku, ale może prowadzić do zamieszania, gdy umieszczasz zarówno zmienne, jak i wskaźniki wspólnego typu w jednym wierszu (co samo jest często zniechęcane przez wytyczne projektu, ponieważ zmniejsza czytelność).

Wolę deklarować wskaźniki za pomocą odpowiedniego znaku obok nazwy typu, np

int* pMyPointer;
macbirdie
źródło
3
Pytanie dotyczy C, gdzie nie ma odnośników.
Antti Haapala
Dziękujemy za zwrócenie na to uwagi, chociaż pytanie nie dotyczyło wskaźników ani referencji, ale w zasadzie formatowania kodu.
macbirdie
8

Wielki guru powiedział kiedyś: „Musisz to przeczytać w kompilatorze, musisz”.

http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835

To prawda, że ​​dotyczyło to umieszczania const, ale tutaj obowiązuje ta sama zasada.

Kompilator czyta to jako:

int (*a);

nie jako:

(int*) a;

Jeśli przyzwyczaisz się umieszczać gwiazdę obok zmiennej, ułatwi to odczytanie twoich deklaracji. Pozwala także uniknąć owrzodzeń, takich jak:

int* a[10];

-- Edytować --

Wyjaśnienie dokładnie, co mam na myśli, gdy mówię, że jest ono parsowane int (*a), oznacza to, że *wiąże się ściślej aniż z nim int, w bardzo podobny sposób, w jaki w wyrażeniu 4 + 3 * 7 3wiąże się ściślej 7niż z 4powodu wyższego pierwszeństwa *.

Z przeprosinami za sztukę ascii, streszczenie AST do parsowania int *awygląda mniej więcej tak:

      Declaration
      /         \
     /           \
Declaration-      Init-
Secifiers       Declarator-
    |             List
    |               |
    |              ...
  "int"             |
                Declarator
                /       \
               /        ...
           Pointer        \
              |        Identifier
              |            |
             "*"           |
                          "a"

Jak wyraźnie pokazano, *wiąże się ściślej, aponieważ ich wspólnym przodkiem jest Declarator, podczas gdy musisz przejść całą górę drzewa, Declarationaby znaleźć wspólnego przodka, który obejmuje int.

dgnuff
źródło
Nie, kompilator zdecydowanie czyta ten typ jako (int*) a.
Lundin
@Lundin Jest to wielkie nieporozumienie, które ma większość współczesnych programistów C ++. Analiza deklaracji zmiennej przebiega mniej więcej tak. Krok 1. Przeczytaj pierwszy token, który stanie się „typem podstawowym” deklaracji. intw tym przypadku. Krok 2. Przeczytaj deklarację, w tym wszelkiego rodzaju dekoracje. *aw tym przypadku. Krok 3 Przeczytaj następny znak. Jeśli przecinek, użyj go i wróć do kroku 2. Jeśli średnik się zatrzyma. Jeśli cokolwiek innego wyrzuci błąd składniowy. ...
dgnuff,
@Lundin ... Jeśli parser przeczyta to tak, jak sugerujesz, będziemy mogli napisać int* a, b;i uzyskać parę wskaźników. Chodzi mi o to, że *wiąże się ze zmienną i jest analizowana z nią, a nie z typem, aby utworzyć „typ podstawowy” deklaracji. Jest to również jeden z powodów, dla których wprowadzono typedefs, aby umożliwić typedef int *iptr; iptr a, b;utworzenie kilku wskaźników. Za pomocą typedef ty może się wiązało *do int.
dgnuff
1
... Oczywiście kompilator „łączy” typ podstawowy Declaration-Specifierz „dekoracjami” w Declaratorcelu uzyskania ostatecznego typu dla każdej zmiennej. Jednak nie „przenosi” dekoracji do specyfikatora Deklaracji, w przeciwnym razie int a[10], b;dałoby całkowicie absurdalne wyniki, parsuje się int *a, b[10];jako int *a , b[10] ;. Nie ma innego sposobu, aby to opisać, który ma sens.
dgnuff,
1
Tak, cóż, ważną częścią tutaj nie jest tak naprawdę składnia ani kolejność analizowania kompilatora, ale to, że typ int*ajest w końcu odczytywany przez kompilator jako: „ ama typ int*”. O to mi chodziło w moim oryginalnym komentarzu.
Lundin,
3

Ponieważ ma to większy sens, gdy masz deklaracje takie jak:

int *a, *b;
Greg Rogers
źródło
5
Jest to dosłownie przykład pytania. Nie, w ten sposób nie ma to większego sensu. „int * a, b” może równie dobrze zrobić oba wskaźniki.
MichaelGG,
1
@MichaelGG Masz ogon machający tam psem. Pewien K & R mogłyby określono, że int* a, b;popełnił bwskaźnik do int. Ale nie zrobili tego. I nie bez powodu. W proponowanym systemie jaki jest typ bnastępującej deklaracji int* a[10], b;:?
dgnuff
2

Aby zadeklarować wiele wskaźników w jednym wierszu, wolę tę, int* a, * b;która bardziej intuicyjnie deklaruje „a” jako wskaźnik do liczby całkowitej i nie miesza stylów, kiedy również deklaruje „b”. Jak ktoś powiedział, i tak nie zadeklarowałbym dwóch różnych typów w tym samym oświadczeniu.

heyitsluke
źródło
2

Ludzie, którzy wolą, int* x;próbują wtłoczyć swój kod do fikcyjnego świata, w którym typ znajduje się po lewej stronie, a identyfikator (nazwa) po prawej stronie.

Mówię „fikcyjny”, ponieważ:

W C i C ++, w ogólnym przypadku, deklarowany identyfikator jest otoczony informacją o typie.

To może zabrzmieć szalenie, ale wiesz, że to prawda. Oto kilka przykładów:

  • int main(int argc, char *argv[])oznacza „ mainjest funkcją, która pobiera inttablicę wskaźników chari zwraca an int”. Innymi słowy, większość informacji o typie znajduje się po prawej stronie. Niektórzy uważają, że deklaracje funkcji nie liczą się, ponieważ są w jakiś sposób „wyjątkowe”. OK, spróbujmy zmiennej.

  • void (*fn)(int)oznacza fnwskaźnik do funkcji, która przyjmuje inti nic nie zwraca.

  • int a[10]deklaruje „a” jako tablicę 10 ints.

  • pixel bitmap[height][width].

  • Najwyraźniej wybrałem przykłady, które po prawej stronie mają wiele informacji o typie, aby wyrazić swoje zdanie. Istnieje wiele deklaracji, w których większość - jeśli nie wszystkie - tego typu znajduje się po lewej stronie struct { int x; int y; } center.

Ta składnia deklaracji wynikała z chęci K&R, aby deklaracje odzwierciedlały użycie. Czytanie prostych deklaracji jest intuicyjne, a czytanie bardziej złożonych można opanować, ucząc się reguły prawo-lewo-prawo (czasami nazywaj regułę spiralną lub po prostu prawą lewą).

C jest na tyle proste, że wielu programistów C przyjmuje ten styl i pisze proste deklaracje jako int *p.

W C ++ składnia stała się nieco bardziej złożona (z klasami, referencjami, szablonami, klasami enum), a w reakcji na tę złożoność będziesz musiał włożyć więcej wysiłku w oddzielenie typu od identyfikatora w wielu deklaracjach. Innymi słowy, możesz zobaczyć więcej int* pdeklaracji w stylu, jeśli wypiszesz duży obszar kodu C ++.

W każdym języku zawsze możesz mieć typ po lewej stronie deklaracji zmiennych przez (1), nigdy nie deklarując wielu zmiennych w tej samej instrukcji, i (2) korzystając z typedefdeklaracji s (lub aliasów, które, jak na ironię, umieszczają alias identyfikatory po lewej stronie typów). Na przykład:

typedef int array_of_10_ints[10];
array_of_10_ints a;
Adrian McCarthy
źródło
Małe pytanie, dlaczego nie może void (* fn) (int) oznaczać „fn jest funkcją, która przyjmuje int i zwraca (void *)?
Soham Dongargaonkar
1
@ a3y3: Ponieważ w nawiasach (*fn)wskaźnik jest powiązany fnraczej z typem zwracanym niż.
Adrian McCarthy
Rozumiem. Myślę, że jest wystarczająco ważne, aby zostać dodanym w odpowiedzi, wkrótce zasugeruję edycję.
Soham Dongargaonkar
1
Myślę, że to zaśmieca odpowiedź bez dodawania dużej wartości. To jest po prostu składnia języka. Większość ludzi pytających o to, dlaczego składnia jest taka, prawdopodobnie zna już reguły. Każdy, kto jest zdezorientowany w tym punkcie, może zobaczyć wyjaśnienie w tych komentarzach.
Adrian McCarthy
1

Odpowiedziałem już na podobne pytanie w CP i, ponieważ nikt o tym nie wspominał, również tutaj muszę zaznaczyć, że C jest językiem dowolnego formatu , niezależnie od wybranego stylu, podczas gdy parser może rozróżnić każdy token. Ta osobliwość C prowadzi do bardzo szczególnego rodzaju konkursu zwanego C zaciemnianiem .

Frankie_C
źródło
1

Wiele argumentów w tym temacie jest subiektywnie subiektywnych, a spór o „gwiazdę wiąże się z nazwą zmiennej” jest naiwny. Oto kilka argumentów, które nie są tylko opiniami:


Zapomniane kwalifikatory typu wskaźnika

Formalnie „gwiazda” nie należy ani do typu, ani do nazwy zmiennej, jest częścią własnego elementu gramatycznego o nazwie wskaźnik . Formalna składnia C (ISO 9899: 2018) to:

(6.7) deklaracja:
specyfikatory deklaracji init-declarator-list opt ;

Gdzie specyfikatory deklaracji zawierają typ (i pamięć), a lista init-declarator- zawiera wskaźnik i nazwę zmiennej. Co widzimy, jeśli dokładniej przeanalizujemy składnię listy deklaratorów:

(6.7.6) deklarator:
wskaźnik opt direct-declarator
...
(6.7.6) wskaźnik:
* type-qualifier-list opt
* type-qualifier-list opt wskaźnik

W przypadku gdy deklaratorem jest cała deklaracja, deklaratorem bezpośrednim jest identyfikator (nazwa zmiennej), a wskaźnik jest gwiazdą, po której następuje opcjonalna lista kwalifikatorów typu należąca do samego wskaźnika.

Różnorodne argumenty dotyczące stylu „gwiazda należy do zmiennej” są niespójne, ponieważ zapomnieli o kwalifikatorach typu wskaźnika. int* const x, int *const xLub int*const x?

Zastanów się int *const a, b;, jakie są rodzaje ai b? Nie tak oczywiste, że „gwiazda należy już do zmiennej”. Raczej zaczyna się zastanawiać, do kogo constnależy.

Z pewnością można podać rozsądny argument, że gwiazda należy do kwalifikatora typu wskaźnika, ale niewiele więcej.

Lista kwalifikatorów typu wskaźnika może powodować problemy dla osób używających int *astylu. Ci, którzy używają wskaźników wewnątrz typedef(czego nie powinniśmy, bardzo zła praktyka!) I myślą, że „gwiazda należy do nazwy zmiennej”, mają tendencję do pisania tego bardzo subtelnego błędu:

    /*** bad code, don't do this ***/
    typedef int *bad_idea_t; 
    ...
    void func (const bad_idea_t *foo);

To się kompiluje. Teraz możesz pomyśleć, że kod jest poprawny. Skąd! Ten kod jest przypadkowo sfałszowaną poprawnością const.

Typ foojest w rzeczywistości int*const*- najbardziej zewnętrzny wskaźnik został ustawiony tylko do odczytu, a nie wskazał na dane. Więc wewnątrz tej funkcji możemy to zrobić **foo = n;i zmieni ona wartość zmiennej w wywołującym.

Jest tak, ponieważ w wyrażeniu const bad_idea_t *footutaj *nie należy do nazwy zmiennej! W pseudokodzie deklarację parametru należy czytać jako const (bad_idea_t *) fooa nie jako (const bad_idea_t) *foo. Gwiazda należy w tym przypadku do typu ukrytego wskaźnika - typ jest wskaźnikiem, a wskaźnik o stałej nazwie jest zapisywany jako *const.

Ale potem źródłem problemu w powyższym przykładzie jest praktyka ukrywania wskaźników za stylem, typedefa nie za nim *.


Odnośnie deklaracji wielu zmiennych w jednym wierszu

Deklarowanie wielu zmiennych w jednym wierszu jest powszechnie uznawane za złą praktykę 1) . CERT-C ładnie podsumowuje:

DCL04-C. Nie deklaruj więcej niż jednej zmiennej na deklarację

Tylko czytanie po angielsku, to zdrowy rozsądek zgadza się, że deklaracja powinna być jedna deklaracja.

I nie ma znaczenia, czy zmienne są wskaźnikami, czy nie. Deklaracja każdej zmiennej w jednym wierszu sprawia, że ​​kod jest jaśniejszy w prawie każdym przypadku.

Dlatego argument o pomyleniu programisty int* a, bjest zły. Przyczyną problemu jest użycie wielu deklaratorów, a nie ich umieszczenie *. Niezależnie od stylu powinieneś pisać to:

    int* a; // or int *a
    int b;

Innym rozsądnym, ale subiektywnym argumentem byłoby to, że biorąc int* apod uwagę typ ajest bez pytania, int*więc gwiazda należy do kwalifikatora typu.

Ale zasadniczo mój wniosek jest taki, że wiele przytoczonych tutaj argumentów jest subiektywnych i naiwnych. Nie można tak naprawdę uzasadnić żadnego z tych stylów - jest to naprawdę kwestia subiektywnych preferencji osobistych.


1) CERT-C DCL04-C .

Lundin
źródło
Raczej zabawnie, jeśli czytasz ten artykuł, który podłączyłem, jest krótki rozdział na temat typedef int *bad_idea_t; void func(const bad_idea_t bar); Jak uczy wielki prorok, Dan Saks Saks: „Jeśli zawsze umieścisz consttak daleko w prawo, jak to możliwe, bez zmiany znaczenia semantycznego”, to całkowicie przestaje być problemem. Sprawia również, że constdeklaracje są bardziej spójne w czytaniu. „Wszystko po prawej stronie słowa const jest tym, co jest const, wszystko po lewej stronie jest jego rodzajem”. Dotyczy to wszystkich stałych w deklaracji. Spróbuj zint const * * const x;
dgnuff
-1

Rozważać

int *x = new int();

To nie przekłada się na

int *x;
*x = new int();

To właściwie tłumaczy

int *x;
x = new int();

To sprawia, że int *xnotacja jest nieco niespójna.

Urquhart
źródło
newjest operatorem C ++. Jego pytanie jest oznaczone jako „C”, a nie „C ++”.
Sapphire_Brick