Ik verknoei altijd hoe ik const int*
, const int * const
en int const *
correct moet gebruiken. Is er een reeks regels die bepalen wat u wel en niet kunt doen?
Ik wil alle do’s en don’ts weten op het gebied van opdrachten, doorgeven aan de functies, etc.
Antwoord 1, autoriteit 100%
Lees het achterstevoren (zoals bepaald door Met de klok mee/spiraalregel):
int*
– verwijzing naar intint const *
– verwijzing naar const intint * const
– const-wijzer naar intint const * const
– const pointer naar const int
Nu kan de eerste const
aan weerszijden van het type staan, dus:
const int *
==int const *
const int * const
==int const * const
Als je echt gek wilt worden, kun je dit soort dingen doen:
int **
– pointer naar pointer naar intint ** const
– een const-wijzer naar een aanwijzer naar een intint * const *
– een pointer naar een const pointer naar een intint const **
– een verwijzing naar een verwijzing naar een const intint * const * const
– een const-wijzer naar een const-wijzer naar een int- …
En om er zeker van te zijn dat we duidelijk zijn over de betekenis van const
:
int a = 5, b = 10, c = 15;
const int* foo; // pointer to constant int.
foo = &a; // assignment to where foo points to.
/* dummy statement*/
*foo = 6; // the value of a can´t get changed through the pointer.
foo = &b; // the pointer foo can be changed.
int *const bar = &c; // constant pointer to int
// note, you actually need to set the pointer
// here because you can't change it later ;)
*bar = 16; // the value of c can be changed through the pointer.
/* dummy statement*/
bar = &a; // not possible because bar is a constant pointer.
foo
is een variabele pointer naar een constant geheel getal. Hiermee kunt u wijzigen waarnaar u verwijst, maar niet de waarde waarnaar u verwijst. Meestal zie je dit bij C-stijl strings waar je een pointer hebt naar een const char
. U kunt wijzigen naar welke tekenreeks u verwijst, maar u kunt de inhoud van deze tekenreeksen niet wijzigen. Dit is belangrijk wanneer de string zelf zich in het datasegment van een programma bevindt en niet mag worden gewijzigd.
bar
is een constante of vaste wijzer naar een waarde die kan worden gewijzigd. Dit is als een referentie zonder de extra syntactische suiker. Vanwege dit feit zou u gewoonlijk een referentie gebruiken waar u een T* const
-aanwijzer zou gebruiken, tenzij u NULL
-aanwijzers moet toestaan.
Antwoord 2, autoriteit 17%
Voor degenen die niets weten over Clockwise/Spiral Rule:
Begin met de naam van de variabele, ga met de klok mee (in dit geval achteruit) naar de volgende aanwijzerof type. Herhaal totdat de uitdrukking eindigt.
Hier is een demo:
Antwoord 3, autoriteit 7%
Ik denk dat alles hier al beantwoord is, maar ik wil er alleen aan toevoegen dat je moet oppassen voor typedef
s! Het zijn NIET alleen tekstvervangingen.
Bijvoorbeeld:
typedef char *ASTRING;
const ASTRING astring;
Het type astring
is char * const
, niet const char *
. Dit is een van de redenen waarom ik altijd de neiging heb om const
rechts van het type te zetten, en nooit aan het begin.
Antwoord 4, autoriteit 2%
Zoals vrijwel iedereen opmerkte:
Wat is het verschil tussen const X* p
, X* const p
en const X* const p
?
Je moet pointerverklaringen lezen
van rechts naar links.
const X* p
betekent “p wijst naar een X die const is”: het X-object kan niet worden gewijzigd via p.
X* const p
betekent “p is een const-wijzer naar een X die niet-const is”: je kunt de aanwijzer p zelf niet veranderen, maar je kunt de X wel veranderen object via p.
const X* const p
betekent “p is een const-wijzer naar een X die const is”: je kunt de aanwijzer p zelf niet veranderen, noch kun je het X-object veranderen via p.
Antwoord 5, autoriteit 2%
-
Constante referentie:
Een verwijzing naar een variabele (hier int), die constant is. We geven de variabele voornamelijk door als referentie, omdat referenties kleiner zijn dan de werkelijke waarde, maar er is een neveneffect en dat is omdat het een alias is voor de werkelijke variabele. We kunnen per ongeluk de hoofdvariabele wijzigen door onze volledige toegang tot de alias, dus we maken deze constant om deze bijwerking te voorkomen.
int var0 = 0; const int &ptr1 = var0; ptr1 = 8; // Error var0 = 6; // OK
-
Constante aanwijzingen
Zodra een constante aanwijzer naar een variabele wijst, kan deze niet naar een andere variabele wijzen.
int var1 = 1; int var2 = 0; int *const ptr2 = &var1; ptr2 = &var2; // Error
-
Aanwijzer naar constante
Een aanwijzer waardoor men de waarde van een variabele waarnaar hij verwijst niet kan veranderen, staat bekend als een aanwijzer naar een constante.
int const * ptr3 = &var2; *ptr3 = 4; // Error
-
Constante aanwijzer naar een constante
Een constante aanwijzer naar een constante is een aanwijzer die het adres waarnaar hij verwijst niet kan veranderen en evenmin de waarde die op dat adres wordt bewaard.
int var3 = 0; int var4 = 0; const int * const ptr4 = &var3; *ptr4 = 1; // Error ptr4 = &var4; // Error
Antwoord 6
De algemene regel is dat het sleutelwoord const
onmiddellijk van toepassing is op wat eraan voorafgaat. Uitzondering, een beginnende const
is van toepassing op wat volgt.
const int*
is hetzelfde alsint const*
en betekent “aanwijzer naar constante int”.const int* const
is hetzelfde alsint const* const
en betekent “constante aanwijzer naar constante int”.
Bewerken:
Voor de do’s en don’ts, als dit antwoordis niet genoeg, kun je wat preciezer zijn over wat je wilt?
Antwoord 7
Deze vraag laat precieszien waarom ik de dingen graag doe zoals ik vermeldde in mijn vraag is const na type id acceptabel?
Kortom, ik denk dat de gemakkelijkste manier om de regel te onthouden is dat de “const” nagaat waar het op van toepassing is. Dus in uw vraag betekent “int const *” dat de int constant is, terwijl “int * const” zou betekenen dat de aanwijzer constant is.
Als iemand besluit om het helemaal vooraan te plaatsen (bijv.: “const int *”), dan geldt het als een speciale uitzondering voor het ding erachter.
Veel mensen gebruiken die speciale uitzondering graag omdat ze denken dat het er mooier uitziet. Ik vind het niet leuk, omdat het een uitzondering is, en dus dingen in de war brengt.
Antwoord 8
Eenvoudig gebruik van const
.
Het eenvoudigste gebruik is om een benoemde constante te declareren. Om dit te doen, declareert men een constante alsof het een variabele is, maar voegt u er const
aan toe. Men moet het onmiddellijk in de constructor initialiseren, omdat men de waarde natuurlijk niet later kan instellen, omdat dit het zou veranderen. Bijvoorbeeld:
const int Constant1=96;
maakt een integer-constante, zonder fantasie Constant1
genoemd, met de waarde 96.
Dergelijke constanten zijn handig voor parameters die in het programma worden gebruikt, maar die niet hoeven te worden gewijzigd nadat het programma is gecompileerd. Het heeft een voordeel voor programmeurs ten opzichte van het C-preprocessor #define
-commando omdat het wordt begrepen & gebruikt door de compiler zelf, niet alleen vervangen door de preprocessor in de programmatekst voordat deze de hoofdcompiler bereikt, dus foutmeldingen zijn veel nuttiger.
Het werkt ook met aanwijzers, maar men moet voorzichtig zijn met const
om te bepalen of de aanwijzer of waarnaar hij verwijst constant is of beide. Bijvoorbeeld:
const int * Constant2
verklaart dat Constant2
een variabele pointer is naar een constant geheel getal en:
int const * Constant2
is een alternatieve syntaxis die hetzelfde doet, terwijl
int * const Constant3
verklaart dat Constant3
een constante pointer is naar een variabel geheel getal en
int const * const Constant4
verklaart dat Constant4
een constante pointer is naar een constant geheel getal. In principe is ‘const’ van toepassing op alles wat direct links is (behalve als er niets is, in welk geval het van toepassing is op alles wat direct rechts is).
ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html
Antwoord 9
Ik had dezelfde twijfel als jij totdat ik deze boekdoor de C++ Guru Scott Meyers. Verwijs naar het derde item in dit boek waar hij in detail praat over het gebruik van const
.
Volg gewoon dit advies
- Als het woord
const
links van de asterisk wordt weergegeven, is de verwijzing constant - Als het woord
const
rechts van de asterisk verschijnt, is de aanwijzer zelf constant - Als
const
aan beide kanten verschijnt, zijn beide constant
Antwoord 10
Het is eenvoudig maar lastig. Houd er rekening mee dat we de kwalificatie const
kunnen omwisselen met elk gegevenstype (int
, char
, float
, enz. ).
Laten we de onderstaande voorbeelden bekijken.
const int *p
==> *p
is alleen-lezen [p
is een pointer naar een constant geheel getal]
int const *p
==> *p
is alleen-lezen [p
is een pointer naar een constant geheel getal]
int *p const
==> Fouteverklaring. Compiler geeft een syntaxisfout.
int *const p
==> p
is alleen-lezen [p
is een constante pointer naar een geheel getal].
Aangezien pointer p
hier alleen-lezen is, moeten de declaratie en definitie op dezelfde plaats staan.
const int *p const
==> Fouteverklaring. Compiler geeft een syntaxisfout.
const int const *p
==> *p
is alleen-lezen
const int *const p1
==> *p
en p
zijn alleen-lezen [p
is een constante pointer naar een constant geheel getal]. Aangezien pointer p
hier alleen-lezen is, moeten de declaratie en definitie op dezelfde plaats staan.
int const *p const
==> Fouteverklaring. Compiler geeft een syntaxisfout.
int const int *p
==> Fouteverklaring. Compiler geeft een syntaxisfout.
int const const *p
==> *p
is alleen-lezen en komt overeen met int const *p
int const *const p
==> *p
en p
zijn alleen-lezen [p
is een constante pointer naar een constant geheel getal]. Aangezien pointer p
hier alleen-lezen is, moeten de declaratie en definitie op dezelfde plaats staan.
Antwoord 11
Voor mij helpt de positie van const
, dwz of het LINKS of RECHTS of zowel LINKS als RECHTS ten opzichte van *
verschijnt, me de werkelijke betekenis te achterhalen .
-
Een
const
LINKS van*
geeft aan dat het object waarnaar de aanwijzer wijst eenconst
-object is. -
Een
const
rechts van*
geeft aan dat de aanwijzer eenconst
aanwijzer is.
De volgende tabel is afkomstig uit Stanford CS106L Standard C++ Programming Laboratory Course Reader.
Antwoord 12
Er zijn veel andere subtiele punten rond const correctheid in C++. Ik veronderstel dat de vraag hier gewoon over C ging, maar ik zal enkele gerelateerde voorbeelden geven aangezien de tag C++ is:
-
Je geeft vaak grote argumenten zoals strings door als
TYPE const &
waardoor het object niet kan worden gewijzigd of gekopieerd. Voorbeeld :TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }
Maar
TYPE & const
is zinloos omdat referenties altijd const zijn. -
Je moet klassemethoden die de klasse niet wijzigen altijd labelen als
const
, anders kun je de methode niet aanroepen vanuit eenTYPE const &
-referentie. Voorbeeld :bool TYPE::operator==(const TYPE &rhs) const { ... }
-
Er zijn veelvoorkomende situaties waarin zowel de retourwaarde als de methode constant moeten zijn. Voorbeeld :
const TYPE TYPE::operator+(const TYPE &rhs) const { ... }
In feite mogen const-methoden geen interne klassegegevens retourneren als een verwijzing naar niet-const.
-
Als gevolg hiervan moet men vaak zowel een const- als een niet-const-methode maken met behulp van const-overbelasting. Als u bijvoorbeeld
T const& operator[] (unsigned i) const;
, dan wil je waarschijnlijk ook de niet-const versie gegeven door :inline T& operator[] (unsigned i) {
return const_cast<char&>(
static_cast<const TYPE&>(*this)[](i)
);
}
Afaik, er zijn geen const-functies in C, niet-ledenfuncties kunnen zelf geen const zijn in C++, const-methoden kunnen bijwerkingen hebben en de compiler kan geen const-functies gebruiken om dubbele functieaanroepen te voorkomen. In feite kan zelfs een eenvoudige int const &
-referentie de waarde waarnaar het verwijst ergens anders worden gewijzigd.
Antwoord 13
De declaratiesyntaxis van C en C++ is door de oorspronkelijke ontwerpers herhaaldelijk beschreven als een mislukt experiment.
Laten we in plaats daarvan het type “pointer to type
” noemen; Ik noem het Ptr_
:
template< class Type >
using Ptr_ = Type*;
Nu is Ptr_<char>
een verwijzing naar char
.
Ptr_<const char>
is een verwijzing naar const char
.
En const Ptr_<const char>
is een const
-aanwijzer naar const char
.
Daar.
Antwoord 14
De const met de int aan weerszijden maakt pointer naar constante int:
const int *ptr=&i;
of:
int const *ptr=&i;
const
na *
maakt constante aanwijzer naar int:
int *const ptr=&i;
In dit geval zijn dit allemaal pointer naar constant geheel getal, maar geen van deze zijn constante pointers:
const int *ptr1=&i, *ptr2=&j;
In dit geval zijn ze allemaal pointer naar constant geheel getalen ptr2 is constante pointer naar constant geheel getal. Maar ptr1 is geen constante aanwijzer:
int const *ptr1=&i, *const ptr2=&j;
Antwoord 15
Dit richt zich vooral op de tweede regel: best practices, toewijzingen, functieparameters enz.
Huisartsenpraktijk. Probeer alles const
te maken wat je kunt. Of om dat anders te zeggen, maak eerst alles const
en verwijder dan precies de minimale set const
en die nodig is om het programma te laten functioneren. Dit zal een grote hulp zijn bij het verkrijgen van const-correctheid en zal ervoor zorgen dat er geen subtiele bugs worden geïntroduceerd wanneer mensen dingen proberen toe te wijzen aan dingen die ze niet geacht worden te wijzigen.
Vermijd const_cast<> als de pest. Er zijn een of twee legitieme use-cases voor, maar die zijn er maar heel weinig. Als u een const
-object probeert te wijzigen, doet u er veel beter aan om degene die het const
heeft verklaard in het eerste tempo te vinden en de kwestie met hen te bespreken overeenstemming bereiken over wat er moet gebeuren.
Dat leidt heel netjes naar opdrachten. Je kunt alleen iets toewijzen als het niet-const is. Als je iets wilt toewijzen dat const is, zie hierboven. Onthoud dat in de verklaringen int const *foo;
en int * const bar;
verschillende dingen const
zijn – andere antwoorden hier hebben dat probleem bewonderenswaardig behandeld , dus ik ga er niet op in.
Functieparameters:
Waarde doorgeven: b.v. void func(int param)
het maakt je op de een of andere manier niet uit op de bellende site. Het argument kan worden gemaakt dat er use-cases zijn voor het declareren van de functie als void func(int const param)
maar dat heeft geen effect op de aanroeper, alleen op de functie zelf, in die zin dat welke waarde dan ook wordt doorgegeven kan tijdens het gesprek niet door de functie worden gewijzigd.
Geef een referentie door: b.v. void func(int ¶m)
Nu maakt het wel degelijk een verschil. Zoals zojuist aangegeven mag func
param
wijzigen, en elke aanroepende site moet klaar zijn om de gevolgen op te vangen. Het wijzigen van de declaratie in void func(int const ¶m)
verandert het contract en garandeert dat func
nu param
niet kan veranderen, wat betekent wat wordt doorgegeven, komt er weer uit. Zoals anderen al hebben opgemerkt, is dit erg handig voor het goedkoop doorgeven van een groot object dat u niet wilt veranderen. Een referentie doorgeven is een stuk goedkoper dan een groot object op waarde doorgeven.
Voorbij aanwijzer: b.v. void func(int *param)
en void func(int const *param)
Deze twee zijn vrijwel synoniem met hun referentie-tegenhangers, met het voorbehoud dat de aangeroepen functie nu nodig heeft om te controleren op nullptr
tenzij een andere contractuele garantie func
verzekert dat het nooit een nullptr
in param
zal ontvangen.
Opiniestuk over dat onderwerp. Juistheid bewijzen in een geval als dit is hels moeilijk, het is gewoon te verdomd gemakkelijk om een fout te maken. Dus neem geen risico en controleer altijd de pointer parameters voor nullptr
. U bespaart uzelf pijn en lijden en moeilijk te vinden bugs op de lange termijn. En wat betreft de kosten van de controle, deze is spotgoedkoop, en in gevallen waarin de statische analyse die in de compiler is ingebouwd het kan beheren, zal de optimizer het toch weglaten. Schakel Link Time Code Generation in voor MSVC, of WOPR (denk ik) voor GCC, en je krijgt het programma breed, d.w.z. zelfs in functieaanroepen die de grens van een broncodemodule overschrijden.
Uiteindelijk is al het bovenstaande een zeer solide argument om altijd de voorkeur te geven aan verwijzingen boven verwijzingen. Ze zijn gewoon overal veiliger.
Antwoord 16
- als
const
linksvan*
is, verwijst het naar de waarde (het maakt niet uit of hetconst int
ofint const
) - als
const
rechtsvan*
staat, verwijst het naar de aanwijzer zelf - het kan allebei tegelijk
Een belangrijk punt: const int *p
betekent niet dat de waarde waarnaar u verwijst constant is!!. Het betekent dat je het via die aanwijzerniet kunt veranderen (wat betekent dat je $*p = …` niet kunt toewijzen). De waarde zelf kan op andere manieren worden gewijzigd. Bijv.
int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error
Dit is bedoeld om meestal te worden gebruikt in functiehandtekeningen, om te garanderen dat de functie de doorgegeven argumenten niet per ongeluk kan wijzigen.
Antwoord 17
Voor de volledigheid voor C na de andere uitleg, niet zeker voor C++.
- pp – aanwijzer naar aanwijzer
- p – aanwijzer
- data – het ding wees, in voorbeelden
x
- vet– alleen-lezen variabele
Aanwijzer
- p data –
int *p;
- p data–
int const *p;
- pdata –
int * const p;
- pdata–
int const * const p;
Aanwijzer naar aanwijzer
- pp p data –
int **pp;
- ppp data –
int ** const pp;
- pp pgegevens –
int * const *pp;
- pp p data–
int const **pp;
- pppdata –
int * const * const pp;
- ppp data–
int const ** const pp;
- pp pdata–
int const * const *pp;
- pppdata–
int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);
// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);
N-niveaus van dereferentie
Ga gewoon door, maar moge de mensheid je excommuniceren.
int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;
printf("%d \n", ****pppp);
Antwoord 18
const int*
– pointer naar constantint
object.
U kunt de waarde van de aanwijzer wijzigen; je kunt de waarde van het int
object, waar de aanwijzer naar verwijst, niet veranderen.
const int * const
– constante pointer naar constantint
object.
U kunt de waarde van de aanwijzer noch de waarde van het int
object waarnaar de aanwijzer verwijst, wijzigen.
int const *
– pointer naar constantint
object.
Deze instructie is gelijk aan 1. const int*
– U kunt de waarde van de aanwijzer wijzigen, maar u kunt de waarde van het int
-object, de aanwijzer, niet wijzigen wijst naar.
Eigenlijk is er een vierde optie:
int * const
– constante aanwijzer naarint
object.
U kunt de waarde van het object waarnaar de aanwijzer verwijst, wijzigen, maar u kunt de waarde van de aanwijzer zelf niet wijzigen. De aanwijzer wijst altijd naar hetzelfde int
-object, maar deze waarde van dit int
-object kan worden gewijzigd.
Als je een bepaald type C- of C++-constructie wilt bepalen, kun je de gebruiken Met de klok mee/spiraalregelgemaakt door David Anderson; maar niet te verwarren met Anderson’s Rulegemaakt door Ross J. Anderson , wat iets heel anders is.
Antwoord 19
eenvoudig geheugensteuntje:
type
aanwijzer <- *
-> pointee name
Ik zie int *i
graag als een verklaring van “de dereferentie van i
is int
“; in deze zin betekent const int *i
“de deref van i
is const int
“, terwijl int *const i
betekent “deref van const i
is int
“.
(het enige gevaar van zo denken is dat het kan leiden tot een voorkeur voor int const *i
stijl van declaratie, wat mensen misschien haten/afkeuren)
Antwoord 20
Om op een gemakkelijke manier te onthouden:
Als const vóór * staat, is waarde constant.
Als const na * komt, is adres constant.
Als const zowel voor als na * beschikbaar is, zijn zowel waarde als adres constant.
bijv.
-
int * const var; //hier is het adres constant.
-
int const * var; //hier is de waarde constant.
-
int const * const var; // zowel waarde als adres zijn constant.
Antwoord 21
Veel mensen hebben correct geantwoord. Ik zal het hier gewoon goed organiseren en wat extra info plaatsen die ontbreekt in de gegeven antwoorden.
Const is een sleutelwoord in C-taal, ook wel kwalificatie genoemd. Const kan
toegepast op de declaratie van een variabele om aan te geven dat het een waarde is
zal niet veranderen
const int a=3,b;
a=4; // give error
b=5; // give error as b is also const int
you have to intialize while declaring itself as no way to assign
it afterwards.
Hoe te lezen?
lees gewoon van rechts naar links elke verklaring werkt soepel
3 hoofdzaken
type a. p is ptr to const int
type b. p is const ptr to int
type c. p is const ptr to const int
[Fout]
if * comes before int
twee soorten
1. const int *
2. const const int *
wij kijken eerst
Hoofdtype 1. const int*
manieren om 3 dingen op 3 plaatsen te regelen 3!=6
i. * bij het begin
*const int p [Error]
*int const p [Error]
ii. const aan het begin
const int *p type a. p is ptr to const int
const *int p [Error]
iii. int aan het begin
int const *p type a.
int * const p type b. p is const ptr to int
Hoofdtype 2. const const int*
manieren om 4 dingen te rangschikken op 4 plaatsen waarvan er 2 hetzelfde zijn 4!/2!=12
i. * bij het begin
* int const const p [Error]
* const int const p [Error]
* const const int p [Error]
ii. int aan het begin
int const const *p type a. p is ptr to const int
int const * const p type c. p is const ptr to const int
int * const const p type b. p is const ptr to int
iii. const aan het begin
const const int *p type a.
const const * int p [Error]
const int const *p type a.
const int * const p type c.
const * int const p [Error]
const * const int p [Error]
alles in één knijpen
typ een. p is ptr tot const int (5)
const int *p
int const *p
int const const *p
const const int *p
const int const *p
typ b. p is const ptr naar int (2)
int * const p
int * const const p;
type c. p is const ptr tot const int (2)
int const * const p
const int * const p
slechts een kleine berekening
1. const int * p total arrangemets (6) [Errors] (3)
2. const const int * p total arrangemets (12) [Errors] (6)
beetje extra
int const * p,p2 ;
here p is ptr to const int (type a.)
but p2 is just const int please note that it is not ptr
int * const p,p2 ;
similarly
here p is const ptr to int (type b.)
but p2 is just int not even cost int
int const * const p,p2 ;
here p is const ptr to const int (type c.)
but p2 is just const int.
Klaar