Const int *, const int * const ve int const * arasındaki fark nedir?


1356

Her zaman const int*, nasıl const int * constve int const *doğru bir şekilde kullanacağımı karıştırıyorum . Neler yapabileceğinizi ve yapamayacağınızı tanımlayan bir dizi kural var mı?

Görevler, işlevlere geçme vb. Bakımından tüm yapılacak ve yapılmayacak şeyleri bilmek istiyorum.


175
Çoğu C ve C ++ bildirimini deşifre etmek için "Saat Yönünde / Spiral Kural" kullanabilirsiniz.
James McNellis

52
cdecl.org , C beyanlarını sizin için otomatik olarak çeviren harika bir web sitesidir.
Dave Gallagher

6
@Calmarius: tür adının olduğu / olması gerektiği yerden başlayın, mümkün olduğunda sağa, gerektiğinde sola gidin . int *(*)(char const * const). Parantez sağındaki başlayın *biz sola hareket etmek zorunda o zaman: pointer. Pars dışında, biz doğru hareket edebilir: pointer to function of .... Sonra sol hareket etmek zorunda: pointer to function of ... that returns pointer to int. Parametre (genişletmek için tekrarlayın ...): pointer to function of (constant pointer to constant char) that returns pointer to int. Pascal gibi kolay okunan bir dilde eşdeğer tek satırlık beyan ne olurdu?
Mark K Cowan

1
@MarkKCowan Pascal'da böyle bir şey olurdu function(x:^char):^int. İşlev türleri, bir işleve bir işaretçi anlamına gelir, bu nedenle onu belirtmeye gerek yoktur ve Pascal const doğruluğunu zorunlu kılmaz. Soldan sağa okunabilir.
Calmarius

5
"Sabit" in solundaki ilk şey sabit olan şeydir. Eğer "const" en soldaki şeyse, sağındaki ilk şey sabit olan şeydir.
Cupcake

Yanıtlar:


2208

Geriye doğru okuyun ( Clockwise / Spiral Kural tarafından yönlendirildiği gibi ):

  • int* - int işaretçisi
  • int const * - int int işaretçisi
  • int * const - int için const işaretçisi
  • int const * const - const int için const işaretçisi

Şimdi ilk consttürün her iki tarafında olabilir yani:

  • const int * == int const *
  • const int * const == int const * const

Eğer gerçekten çıldırmak istiyorsanız, bunun gibi şeyler yapabilirsiniz:

  • int ** - işaretçi int
  • int ** const - int işaretçisine sabit işaretçi
  • int * const * - int için sabit bir işaretçiye bir işaretçi
  • int const ** - sabit bir işaretçiye bir işaretçi int
  • int * const * const - int için bir sabit işaretçiye bir sabit işaretçi
  • ...

Ve şu anlamlara dikkat ettiğimizden emin olmak için 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.           

foosabit bir tamsayının değişken göstergesidir. Bu, işaret ettiğiniz değeri değiştirmenizi sağlar, ancak işaret ettiğiniz değeri değiştirmez. Çoğu zaman bu, bir işaretçiye sahip olduğunuz C stili dizelerle görülür const char. Hangi dizeyi işaret ettiğinizi değiştirebilirsiniz ancak bu dizelerin içeriğini değiştiremezsiniz. Dizenin kendisi bir programın veri segmentindeyse ve değiştirilmemesi gerektiğinde bu önemlidir.

bardeğiştirilebilir bir değerin sabit veya sabit bir göstergesidir. Bu, ekstra sözdizimsel şekeri olmayan bir referans gibidir. Bu nedenle, T* constişaretçilere izin vermeniz gerekmediği sürece , genellikle bir işaretçi kullanacağınız bir referans kullanırsınız NULL.


481
Ben 'const' işaretçi veya sivri veri için geçerli olup olmadığını keşfetmek hatırlamak yardımcı olabilir bir başparmak kural eklemek istiyorum: asterix işareti ifadeyi bölmek, sonra, const anahtar kelime sol kısımda görünür (gibi 'const int * foo') - sağ kısımdaysa ('int * const bar') - işaretçi verilere aittir.
Michael

14
@Michael: Const kuralını hatırlamak / anlamak için böyle basit bir kural için Michael'a Kudos.
sivabudh

10
@Jeffrey: parantez olmadığı sürece geriye doğru okudum. Sonra, iyi ... typedefs kullanın
Mooing Duck 28:13

12
1, daha iyi bir özeti olacaktır olsa: okuma işaret beyanları geriye , araçlar, yakın @Michael 'ın açıklamalarına şu: normal soldan sağa okuma durdurmak ilk yıldız işareti.
Wolf

3
@gedamial işe yarıyor, gayet iyi çalışıyor, ancak beyan ettiğiniz anda atamalısınız (çünkü bir "sabit işaretçiyi" yeniden atayamazsınız). const int x = 0; const int *const px = &x; const int *const *const p = &px;gayet iyi çalışıyor.
RastaJedi

356

Clockwise / Spiral Kuralı hakkında bilgi sahibi olmayanlar için: Değişkenin adından başlayın, saat yönünde (bu durumda, geriye doğru hareket ettirin) bir sonraki işaretçiye veya türe gidin . İfade bitene kadar tekrarlayın.

İşte bir demo:

int için işaretçi

int const için const işaretçisi

int const için işaretçi

const için işaretçi int

int için işaretçi const


8
@ Karmaşık örnek bağlantısının izinleri yok. doğrudan buraya gönderebilir veya görüntüleme kısıtlamalarını kaldırabilir misiniz?
R71

8
@Rog tüm açık erişim izinlerine sahipti ... Maalesef makaleyi yazmadım ve erişim izinlerine sahip değilim. Ancak, makalenin hala çalışan arşivlenmiş bir sürümü: archive.is/SsfMX
Jan Rüegg

8
Karmaşık örnek hala sağdan soladır, ancak parantezlerin normalde olduğu gibi çözümlenmesini içerir. Saat yönünde sarmal olan şey bunu kolaylaştırmaz.
Matthew

4
Nihai örnek: void (*signal(int, void (*fp)(int)))(int);archive.is/SsfMX
naXa

3
Bu kurala güvenmeyin. Bu evrensel değil. Başarısız olduğu bazı durumlar vardır.
haccks

150

Sanırım burada her şey zaten cevaplandı, ama sadece typedefs dikkat edin eklemek istiyorum ! Bunlar sadece metin değiştirme DEĞİLDİR.

Örneğin:

typedef char *ASTRING;
const ASTRING astring;

Türü astringolduğunu char * const, değil const char *. Bu, her zaman consttürün sağına koyma eğilimimin bir sebebidir ve asla başlangıçta değil.


20
Ve benim için işaretçileri asla tanımlamamanın nedeni budur. typedef int* PINT(C'deki uygulamalardan gelen bir şey olduğunu ve birçok geliştiricinin bunu yapmaya devam ettiğini düşünüyorum) gibi şeylerde fayda görmüyorum . Büyük, bunu değiştirilen *bir ile P, bu yazma hızlandırmak, artı söz sorunu tanıtan etmez.
Mephane

1
@Mephane - Bunu görebiliyorum. Bununla birlikte, bu dil özelliğini güvenle kullanabilmeniz için istisnai sözdizimsel kuralından kaçınmak yerine, istisnai bir sözdizimsel kuralı ("const" yerleştirme hakkında) kullanmaya devam etmek için güzel bir dil özelliğinden kaçınmak biraz geriye doğru görünüyor. .
TED

6
@Mephane PINT, bir typedef'in oldukça aptal bir kullanımıdır, özellikle de sistem depolarının hafıza için bira kullandığını düşündürüyor. typedef s, işlevlere işaretçilerle uğraşmak için oldukça yararlıdır.
ApproachingDarknessFish

5
@KazDragon TEŞEKKÜRLER! O olmasaydı PVOID, LPTSTRWin32 api tüm bu tip tanımlı şeyler ile berbat olurdu !
David Lee

2
@Mephane: Bir türü kabul etmek için yazılan belirli eski makroları kullanırken pSomething'i birkaç kez kullanmak zorunda kaldım, ancak tür tek bir alfasayısal tanımlayıcı olmasaydı parçalanacaktı. :)
Groo

56

Herkesin işaret ettiği gibi:

Ne arasındaki fark var const X* p, X* const pve const X* const p?

İşaretçi bildirimlerini sağdan sola okumalısınız.

  • const X* p "p sabit olan bir X'i işaret eder" anlamına gelir: X nesnesi p ile değiştirilemez.

  • X* const p "p, sabit olmayan bir X'in sabit göstergesidir": p işaretçisinin kendisini değiştiremezsiniz, ancak X nesnesini p ile değiştirebilirsiniz.

  • const X* const p "p, sabit olan bir X'in sabit göstergesidir" anlamına gelir: p işaretçisinin kendisini değiştiremezsiniz veya X nesnesini p ile değiştiremezsiniz.


3
Unutmayın const X* p;= = X const * p;olduğu gibi"p points to an X that is const": the X object can't be changed via p.
Jesse Chisholm

basit ve güzel bir açıklama!
Edison Lo

50
  1. Sürekli referans:

    Sabit olan bir değişkene (burada int) başvuru. Değişkeni esas olarak referans olarak geçiririz, çünkü referanslar gerçek değerden daha küçüktür, ancak bir yan etkisi vardır ve bunun nedeni gerçek değişkenin bir takma adı olmasıdır. Takma adı tam erişimimizle yanlışlıkla ana değişkeni değiştirebiliriz, bu nedenle bu yan etkiyi önlemeyi sürekli hale getiririz.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
  2. Sabit işaretçiler

    Sabit bir işaretçi bir değişkeni gösterdiğinde, başka bir değişkeni gösteremez.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
  3. Sabit ile işaretçi

    Birinin işaret ettiği bir değişkenin değerini değiştiremediği bir işaretçi, sabite işaretçi olarak bilinir.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
  4. Sabit bir sabite işaretçi

    Sabit bir sabit işaretçi, işaret ettiği adresi değiştiremeyen ve bu adreste tutulan değeri değiştiremeyen bir işaretçi.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error

20

Genel kural, constanahtar kelimenin kendisinden önce gelen anahtar kelimeye uygulanmasıdır. İstisna, constaşağıdakilere bir başlangıç uygulanır.

  • const int*ile aynıdır int const*ve "sabit int işaretçisi" anlamına gelir .
  • const int* constaynıdır int const* constve aracı "sabit int sabit pointer" .

Düzenleme: Yapılacaklar ve Yapılmayacaklar için, eğer bu cevap yeterli değilse, ne istediğiniz konusunda daha kesin olabilir misiniz?


19

Bu soru, neden sorularımda bahsettiğim şekilde tür kimlik kabul edilebilir const sonra const olduğunu gibi şeyler yapmak istiyorum tam olarak gösterir ?

Kısacası, kuralı hatırlamanın en kolay yolunu "const" un geçerli olduğu şeyin peşinden gitmesi olduğunu düşünüyorum. Sorunuzda "int const *", int'in sabit olduğu anlamına gelirken, "int * const", işaretçinin sabit olduğu anlamına gelir.

Birisi ön tarafa koymaya karar verirse (örneğin: "const int *"), bu durumda özel bir istisna olarak, bundan sonraki şey için geçerlidir.

Birçok insan bu özel istisnayı kullanmayı sever çünkü daha hoş göründüğünü düşünürler. Bunu sevmiyorum, çünkü bu bir istisna ve bu yüzden işleri karıştırıyor.


2
Bu konuda paramparça oldum. Mantıksal olarak mantıklı. Ancak çoğu c ++ geliştiricisi yazacaktı const T*ve daha doğal hale geldi. Zaten ne sıklıkta kullanıyorsunuz T* const, genellikle bir referans iyi olur. Bir keresinde bütün bunları biraz ısırdım boost::shared_ptr<const T>ve yerine yazdı const boost::shared_ptr<T>. Aynı konu biraz farklı bir bağlamda.
Matt Price

Aslında, sabit işaretçileri sabitleri kullandığımdan daha sık kullanıyorum. Ayrıca, işaretçilerin varlığında işaretçilere (vb.) Nasıl tepki vereceğinizi düşünmeniz gerekir. Kuşkusuz bunlar daha nadirdir, ancak bu durumları applomb ile ele alabileceğiniz bir şekilde düşünmek güzel olurdu.
TED

1
Const'u türün sağına yerleştirmenin bir diğer güzel avantajı, şimdi herhangi constbirinin solundaki her şeyin const olanın tipi olması ve sağındaki her şeyin aslında const olmasıdır. Örnek int const * const * p;olarak alalım. Hayır normalde böyle yazmıyorum, bu sadece bir örnek. İlk olarak constint yazın, Ve const olan int, const işaretçisinin içeriği olan içeriğidir p. İkinci const: tür constint işaretçi , const oblect içeriğip
dgnuff

18

Basit Kullanımı const .

En basit kullanım, adlandırılmış bir sabit bildirmektir. Bunu yapmak için, bir değişkeni sanki bir değişkenmiş gibi bildirir ancak constondan önce ekler . Kişi derhal kurucuda başlatmalıdır, çünkü elbette, değeri daha sonra değiştireceği için ayarlayamaz. Örneğin:

const int Constant1=96; 

yaratıcı olmayan bir tamsayı sabiti oluşturacak Constant196 değerine sahip .

Bu tür sabitler, programda kullanılan ancak program derlendikten sonra değiştirilmesi gerekmeyen parametreler için kullanışlıdır. C önişlemcisine göre programcılar için bir avantajı vardır#define komutuna göre , çünkü ana derleyiciye ulaşmadan önce sadece önişlemci tarafından program metninin yerine değil, derleyicinin kendisi tarafından anlaşılması ve kullanılması, bu nedenle hata mesajları çok daha yararlıdır.

constİşaretçilerle de çalışır, ancak işaretçinin veya neyi gösterdiğinin sabit olup olmadığını veya her ikisini birden belirlemeye dikkat etmek gerekir . Örneğin:

const int * Constant2 

Constant2sabit bir tamsayıya değişken gösterici olduğunu bildirir ve:

int const * Constant2

aynı şeyi yapan alternatif bir sözdizimidir.

int * const Constant3

Constant3değişken bir tamsayının sabit göstergesini bildirir ve

int const * const Constant4

beyan Constant4sabit bir tamsayı sürekli işaretçidir. Temel olarak 'const' hemen solundaki her şey için geçerlidir (orada hiçbir şey yoksa, bu durumda hemen sağ olan her şey için geçerlidir).

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html


9

C ++ Guru Scott Meyers'ın bu kitabına rastlayana kadar seninle aynı şüphem vardı . Kullanımı hakkında ayrıntılı olarak konuştuğu bu kitaptaki üçüncü Öğeye bakın const.

Sadece bu tavsiyeye uyun

  1. Sözcük constyıldız işaretinin solunda görünüyorsa, işaret edilen şey sabittir
  2. Sözcük constyıldız işaretinin sağında görünüyorsa, işaretçinin kendisi sabittir
  3. Her constiki tarafta görünürse, her ikisi de sabittir

7

Çok basit ama zor. Biz takas lütfen unutmayın const(herhangi bir veri türü ile eleme int, char,float vb.)

Aşağıdaki örnekleri görelim.


const int *p==> *psalt okunurdur [ psabit bir tamsayının göstergesidir]

int const *p==> *psalt okunurdur [ psabit bir tamsayının göstergesidir]


int *p const==> Yanlış Açıklama. Derleyici bir sözdizimi hatası atar.

int *const p==> psalt okunurdur [ pbir tamsayının sabit göstergesidir]. pBuradaki işaretçi salt okunur olduğundan, bildirim ve tanım aynı yerde olmalıdır.


const int *p const ==> Yanlış Açıklama. Derleyici bir sözdizimi hatası atar.

const int const *p ==> *psalt okunur

const int *const p1 ==> *pve psalt okunurdur [ psabit bir tamsayının sabit bir göstergesidir]. pBuradaki işaretçi salt okunur olduğundan, bildirim ve tanım aynı yerde olmalıdır.


int const *p const ==> Yanlış Açıklama. Derleyici bir sözdizimi hatası atar.

int const int *p ==> Yanlış Açıklama. Derleyici bir sözdizimi hatası atar.

int const const *p ==> *psalt okunur ve eşdeğerdirint const *p

int const *const p ==> *pve psalt okunurdur [ psabit bir tamsayının sabit bir göstergesidir]. pBuradaki işaretçi salt okunur olduğundan, bildirim ve tanım aynı yerde olmalıdır.


6

C ++ 'da const doğruluğunu çevreleyen başka birçok ince nokta vardır. Burada soru sadece C ile ilgili olduğunu varsayalım, ancak etiket C ++ olduğu için ilgili bazı örnekler vereceğim:

  • Genellikle TYPE const &, nesnelerin değiştirilmesini veya kopyalanmasını önleyen dizeler gibi büyük argümanlar iletirsiniz . Misal :

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Fakat TYPE & constanlamsızdır çünkü referanslar her zaman sabittir.

  • Her zaman sınıfı değiştirmeyen sınıf yöntemlerini etiketlemelisiniz const, aksi takdirde yöntemi bir TYPE const &başvurudan çağıramazsınız . Misal :

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Hem dönüş değerinin hem de yöntemin sabit olması gereken yaygın durumlar vardır. Misal :

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    Aslında, const yöntemleri dahili sınıf verilerini const-non-const referansı olarak döndürmemelidir.

  • Sonuç olarak, const aşırı yüklemesi kullanılarak genellikle hem const hem de const olmayan bir yöntem oluşturulmalıdır. Örneğin, tanımlarsanız T const& operator[] (unsigned i) const;, muhtemelen şu şekilde sabit olmayan sürümü de istersiniz:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, C'de const işlevi yoktur, üye olmayan işlevlerin kendileri C ++ 'da const olamaz, const yöntemlerinin yan etkileri olabilir ve derleyici yinelenen işlev çağrılarını önlemek için const işlevlerini kullanamaz. Aslında, basit bir int const &referans bile, başka bir yerde değiştirildiği değere tanık olabilir.


6

C ve C ++ bildirim sözdizimi, orijinal tasarımcılar tarafından tekrar tekrar başarısız bir deneme olarak tanımlanmıştır.

Bunun yerine, “pointer to ” türünü adlandıralımType ; Ben diyeceğim Ptr_:

template< class Type >
using Ptr_ = Type*;

Şimdi Ptr_<char>bir işaretçi char.

Ptr_<const char>bir göstericidir const char.

Ve const Ptr_<const char>bir constişaretçi const char.

Orada.

resim açıklamasını buraya girin


3
ilk cümle için bir teklifin var mı?
sp2danny

@ sp2danny: “C sözdizimi başarısız deneyi” yapmak, Bjarne Stroustrup'la sadece bu yönde görüşünü ifade ettiği bir dizi görüşmeyi öksürüyor , örn. Bu yüzden C'nin orijinal tasarımcılarının bakış açıları hakkındaki iddiam için hiçbir referansım yok, sanırım yeterince güçlü bir araştırma çabasıyla bulunabilir veya belki de sadece onlara sorarak çürütülebilir, ama şimdi olduğu gibi daha iyi olduğunu düşünüyorum. iddianın bu kısmı ile, hala kararsız ve muhtemelen doğru :)
Şerefe ve hth. - Alf

1
"C ve C ++ bildirim sözdizimi, orijinal tasarımcılar tarafından tekrar tekrar başarısız bir deneme olarak tanımlandı." C için yanlış lütfen C hakkındaki cümlenizi değiştirin veya bazı alıntılar yapın.
Stargateur

3
@Stargateur: Görünüşe göre önceki yorumları okudunuz ve bilgiçlikten yararlanabileceğiniz bir şey buldunuz. Hayatında iyi şanslar. Her neyse, benim gibi eski zamanlayıcılar, çok zaman alan bir araştırmaya girmeden kanıtlayamayacağımız çok şey hatırlıyorlar. Sadece sözümü alabilirsin.
Şerefe ve s. - Alf


6

Benim için, constyani SOL veya SAĞA mı yoksa SOLA ve SAĞA mı göründüğünün konumu *, gerçek anlamı anlamama yardımcı olur.

  1. constSOL ile A *arasındaki işaretçi ile gösterilen constnesnenin bir nesne olduğunu belirtir .

  2. constİle SAĞ arasındaki A *, işaretçinin bir constişaretçi olduğunu gösterir .

Aşağıdaki tablo Stanford CS106L Standart C ++ Programlama Laboratuvarı Kurs Okuyucudan alınmıştır.

resim açıklamasını buraya girin


3

Bu çoğunlukla ikinci satırı ele alır: en iyi uygulamalar, ödevler, fonksiyon parametreleri vb.

Genel Pratik. constYapabileceğiniz her şeyi yapmaya çalışın . Ya da başka bir deyişle, herşeyi constbaşlatabilir ve daha sonra constprogramın çalışmasına izin vermek için gereken minimum s kümesini tam olarak kaldırabilirsiniz . Bu, doğruluk doğruluğuna ulaşmada büyük bir yardımcı olacak ve insanlar değiştirmeleri gerekmeyen şeylere girmeye çalıştıklarında ince hataların ortaya çıkmamasına yardımcı olacaktır.

Veba gibi const_cast <> kullanmaktan kaçının. Bunun için bir veya iki meşru kullanım durumu var, ancak bunlar çok az ve çok uzak. Bir constnesneyi değiştirmeye çalışıyorsanız , onu constilk hızda kimin bildirdiğini bulmak ve ne olması gerektiği konusunda bir fikir birliğine varmak için konuyu onlarla konuşmak için çok daha iyi yapacaksınız .

Bu da çok düzgün bir şekilde ödevlere yol açar. Bir şeye ancak sabit değilse atayabilirsiniz. Sabit bir şeye atamak istiyorsanız, yukarıya bakın. Bildirimlerde int const *foo;ve int * const bar;farklı şeyler olduğunu unutmayın const- buradaki diğer cevaplar bu sorunu takdirle karşıladı, bu yüzden içine girmeyeceğim.

Fonksiyon parametreleri:

Değere göre geçin: ör void func(int param). Arayan sitede şu veya bu şekilde umursamazsınız. Fonksiyonu şöyle bildirmek için kullanım örnekleri olduğu, void func(int const param)ancak arayan üzerinde, sadece fonksiyonun kendisi üzerinde hiçbir etkisi olmayan argümanların çağrı sırasında fonksiyon tarafından değiştirilemeyeceği argümanı yapılabilir .

Referans ile geç: Örneğin void func(int &param), şimdi bir fark yaratıyor. Sadece beyan edildiği gibi funcdeğişmesine izin verilir paramve herhangi bir çağrı sitesi sonuçları ile başa çıkmak için hazır olmalıdır. Beyannamenin değiştirilmesi void func(int const &param)sözleşmeyi değiştirir ve funcşimdi değiştirilemeyen garantiler param, yani neyin geçeceği anlamına gelir. Diğerlerinin de belirttiği gibi, bu, değiştirmek istemediğiniz büyük bir nesneyi ucuza geçirmek için çok yararlıdır. Bir referans iletmek, büyük bir nesneyi değere göre geçirmekten daha ucuzdur.

İşaretçi ile geçin : örneğin void func(int *param)ve void func(int const *param)Bu ikisi, referans sözleşmeleriyle hemen hemen eşanlamlıdır, çağrılan işlevin artık nullptrbaşka bir sözleşme garantisi funcasla içeri girmeyeceğini garanti etmediği sürece kontrol etmesi gereken uyarıyla nullptrbirlikte param.

Bu konudaki fikir parçası. Böyle bir durumda doğruluğu kanıtlamak çok zor, bir hata yapmak çok kolay. Bu yüzden şansınızı denemeyin ve her zaman işaretçi parametrelerini kontrol edin nullptr. Kendinizi acı ve ıstıraptan kurtaracak ve uzun vadede böcek bulmak zor olacaksınız. Ve çek maliyetine gelince, kir ucuzdur ve derleyiciye yerleştirilen statik analizin onu yönetebileceği durumlarda, optimizer yine de onu seçecektir. MSVC için Link Time Code Generation'ı veya GCC için WOPR'yi (sanırım) açın ve program genişliğinde, yani bir kaynak kodu modülü sınırını aşan işlev çağrılarında bile.

Günün sonunda, yukarıdakilerin tümü, her zaman işaretçi referanslarını tercih etmek için çok sağlam bir durum ortaya koyar. Her yönden daha güvenli.


3

Her iki tarafta int bulunan sabit, sabit int'e işaretçi yapar :

const int *ptr=&i;

veya:

int const *ptr=&i;

constafter int* için sabit bir işaretçi yapacak :

int *const ptr=&i;

Bu durumda, bunların tümü sabit tam sayıya işaretçi olmakla birlikte, bunların hiçbiri sabit işaretçi değildir:

 const int *ptr1=&i, *ptr2=&j;

Bu durumda, hepsi sabit tam sayıya işaretçi ve ptr2 sabit tam sayıya sabit işaretçi olur . Ancak ptr1 sabit bir işaretçi değildir:

int const *ptr1=&i, *const ptr2=&j;

3
  • eğer constbir sola arasında *, bu değeri ifade eder (bu öyle önemli değil ister const intya int const)
  • Eğer constbir sağa arasında *, bu işaretçi kendisi belirtmektedir
  • ikisi de aynı anda olabilir

Önemli bir nokta: const int *p bahsettiğiniz değerin sabit olduğu anlamına gelmez !! . Bu , işaretçiyi kullanarak değiştiremeyeceğiniz anlamına gelir (yani, $ * p = ... `atayamazsınız). Değerin kendisi başka şekillerde değiştirilebilir. Örneğin

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

Bu, çoğunlukla işlev imzalarında, işlevin iletilen argümanları yanlışlıkla değiştiremeyeceğini garanti etmek için kullanılır.


2

Sadece diğer açıklamaları takip ederek C için tamlık uğruna, C ++ için emin değilim.

  • pp - işaretçi işaretçi
  • p - işaretçi
  • veri - işaret eden şey, örneklerde x
  • kalın - salt okunur değişken

Işaretçi

  • p verileri - int *p;
  • p verileri -int const *p;
  • p verileri -int * const p;
  • p verileri -int const * const p;

İşaretçiden işaretçiye

  1. pp p verileri - int **pp;
  2. pp p verileri -int ** const pp;
  3. pp p verileri -int * const *pp;
  4. pp p verileri -int const **pp;
  5. pp p verileri -int * const * const pp;
  6. pp p verileri -int const ** const pp;
  7. pp p verileri -int const * const *pp;
  8. pp p verileri -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 Düzensizlik Seviyesi

Sadece devam et, ama insanlık seni aforoz edebilir.

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);

0
  1. const int*- sabit intnesneye işaretçi .

İşaretçinin değerini değiştirebilirsiniz; intnesnenin değerini değiştiremezsiniz , işaretçi işaret eder.


  1. const int * const- sabit intnesneye sabit işaretçi .

İşaretçinin değerini veya intişaretçinin işaret ettiği nesnenin değerini değiştiremezsiniz.


  1. int const *- sabit intnesneye işaretçi .

Bu ifade 1 ile eşdeğerdir. const int*- İşaretçinin değerini değiştirebilirsiniz, ancak intişaretçinin işaret ettiği nesnenin değerini değiştiremezsiniz .


Aslında, bir 4. seçenek var:

  1. int * const- intnesneye sabit işaretçi .

İşaretçinin işaret ettiği nesnenin değerini değiştirebilirsiniz, ancak işaretçinin değerini değiştiremezsiniz. İşaretçi her zaman aynı intnesneyi gösterecektir, ancak bu nesnenin bu değeri intdeğiştirilebilir.


Belirli bir C veya C ++ yapısını belirlemek istiyorsanız, David Anderson tarafından yapılan Clockwise / Spiral Kuralı kullanabilirsiniz ; ama Ross J. Anderson'ın yaptığı oldukça kural olan Anderson'ın Kuralı ile karıştırmamak .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.