const karakter * sabit ve sabit karakter *?


110

Kendimi C ++ ile yeniden tanımak için bazı örnek programlardan geçiyorum ve aşağıdaki soruyla karşılaştım. İlk olarak, işte örnek kod:

void print_string(const char * the_string)
{
    cout << the_string << endl;
}

int main () {
    print_string("What's up?");
}

Yukarıdaki kodda, bunun yerine print_string parametresi olabilirdi const char * const the_string. Bunun için hangisi daha doğru olur?

Farkın, birinin sabit bir karaktere işaretçi, diğerinin ise sabit bir karaktere sabit bir işaretçi olmasıdır. Peki bunların ikisi de neden işe yarıyor? Ne zaman alakalı olacak?

Yanıtlar:


244

İkincisi, the_stringiçeride değişiklik yapmanızı engeller print_string. Aslında burada uygun olurdu, ancak ayrıntılar geliştiriciyi erteledi.

char* the_string: charHangi the_stringnoktaları değiştirebilirim ve hangi noktalara işaret ettiğini değiştirebilirim char.

const char* the_string: charHangi the_stringnoktaları değiştirebilirim , ancak işaret ettiği noktaları değiştiremem char.

char* const the_string: charHangi the_stringnoktalara göre değiştiremem ama işaret ettiği noktayı değiştirebilirim char.

const char* const the_string: charHangi the_stringnoktaları değiştiremem ne de işaret ettiği noktaları değiştiremem char.


11
Son cümle için +1. Sabit doğruluk ayrıntılıdır, ancak buna değer.
mskfisher

6
@Xeo: Formunuz daha da kafa karıştırıcı çünkü anlamını tamamen değiştirmekten bir transpozisyon uzakta. const char *çok daha iyi çünkü consttam tersi tarafta.
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

7
@R ..: En azından benim için değil. Sağdan sola okurken "pointer to const char" alıyorum. Benim için böylesi daha iyi hissettiriyor.
Xeo

6
Kendini kandırıyorsun çünkü C türleri soldan sağa değil, içten dışa doğru okunur. :-)
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

11
Biraz ben görünüşe sadece bunu anlamıyor biriyim mahçup dilerim ... ama "char arasındaki fark nedir için bu işaret hangi" ve "char de işaret ettiği hangi"?
Lack

138
  1. Değiştirilebilir bir karaktere değişken işaretçi

    char *p;
  2. Sabit bir karaktere değişken işaretçi

    const char *p;
  3. Değişebilir bir karaktere sabit işaretçi

    char * const p; 
  4. Sabit bir karaktere sabit işaretçi

    const char * const p;

Bu şu olmamalı: const char* p; --> constant pointer to mutable characterve char *const p; --> mutable pointer to constant character
PnotNP

2
@NulledPointer No. C ++ bildirimleri sağdan sola oluşturulur. Böylece şöyle okuyabilirsiniz const char * p: "p, bir karakter sabitinin göstericisidir" veya James'in doğru bir şekilde belirttiği gibi, sabit bir karaktere değiştirilebilir bir göstericidir. ikincisi ile aynı :).
Samidamaru

28

const char * constaraçlar işaretçi vardır işaret verilerin yanı sıra işaretçisi hem const!

const char *yalnızca işaretçinin işaret ettiği verilerin const olduğu anlamına gelir . göstericinin kendisi ancak const değildir.

Misal.

const char *p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //okay, changing the non-const pointer. 

const char * const p = "Nawaz";
p[2] = 'S'; //error, changing the const data!
p="Sarfaraz"; //error, changing the const pointer. 

20

(Bunun eski olduğunu biliyorum ama yine de paylaşmak istedim.)

Thomas Matthews'un cevabını detaylandırmak istedim. C tipi bildirimlerin Sağ-Sol Kuralı hemen hemen şunu söyler: bir C tipi bildirimi okurken tanımlayıcıdan başlayın ve yapabildiğiniz zaman sağa, yapamadığınız zaman sola gidin.

Bu, en iyi birkaç örnekle açıklanır:

örnek 1

  • Tanımlayıcıdan başla, sağa gidemeyiz, bu yüzden sola gideriz

    const char* const foo
                ^^^^^

    foo sabittir ...

  • Sola devam edin

    const char* const foo
              ^

    foo, sürekli bir göstericidir ...

  • Sola devam edin

    const char* const foo
          ^^^^

    foo, karaktere sabit bir göstericidir ...

  • Sola devam edin

    const char* const foo
    ^^^^^

    foo, char sabitine sabit bir göstericidir (Tamamlandı!)

Örnek 2

  • Tanımlayıcıdan başla, sağa gidemeyiz, bu yüzden sola gideriz

    char* const foo
          ^^^^^

    foo sabittir ...

  • Sola devam edin

    char* const foo
        ^

    foo, sürekli bir göstericidir ...

  • Sola devam edin

    char* const foo
    ^^^^

    foo, char (Tamamlandı!)

Örnek 1337

  • Tanımlayıcıdan başlayın, ancak şimdi sağa gidebiliriz!

    const char* const* (*foo[8])()
                            ^^^

    foo, 8 ...

  • Paranteze basın, böylece artık sağa gidemezsiniz, sola gidin

    const char* const* (*foo[8])()
                        ^

    foo bir 8 gösterici dizisidir ...

  • Parantez içinde tamamlandı, şimdi sağa gidebilir

    const char* const* (*foo[8])()
                                ^^

    foo, işlevi döndüren 8 gösterici dizisidir ...

  • Daha sağa gitme, sola git

    const char* const* (*foo[8])()
                     ^

    foo, bir ...

  • Sola devam edin

    const char* const* (*foo[8])()
                ^^^^^

    foo, bir sabite bir gösterici döndüren işlevlere yönelik 8 gösterici dizisidir ...

  • Sola devam edin

    const char* const* (*foo[8])()
              ^

    foo, sabit bir göstericiye bir göstericiyi bir ...

  • Sola devam edin

    const char* const* (*foo[8])()
          ^^^^

    foo, bir karaktere sabit bir göstericiye bir gösterici döndüren işlevler için 8 gösterici dizisidir ...

  • Sola devam edin

    const char* const* (*foo[8])()
    ^^^^^

    foo, sabit bir göstericiye bir göstericiyi bir karakter sabitine (Tamamlandı!) döndüren işlevler için 8 gösterici dizisidir.

Daha fazla açıklama: http://www.unixwiz.net/techtips/reading-cdecl.html


CMIIW, const char * const foo, char const * const foo ile eşdeğer olmalıdır?
luochenhuan

@luochenhuan Evet, gerçekten öyleler.
Garrett

12

Çoğu kişi tür belirleyiciyi sağdan sola okumanızı önerir.

const char * // Pointer to a `char` that is constant, it can't be changed.
const char * const // A const pointer to const data.

Her iki biçimde de, işaretçi sabit veya salt okunur veriyi gösteriyor.

İkinci biçimde, işaretçi değiştirilemez; işaretçi her zaman aynı yeri gösterecektir.


3

Aradaki fark, constprogramcının fazladan olmadan , işaretçinin gösterdiği yöntemin içinde değişebilir; Örneğin:

 void print_string(const char * the_string)
 {
    cout << the_string << endl;
    //....
    the_string = another_string();
    //....

 }

İmza olsaydı bu yasa dışı olurdu void print_string(const char * const the_string)

Çoğu programcı ekstra constanahtar kelimeyi çok ayrıntılı (çoğu senaryoda) hisseder ve anlamsal olarak doğru olsa bile onu atlar.


2

İkincisinde, ilkinde hem işaretçiyi hem de karakteri değiştirmemeyi garanti edersiniz, yalnızca içeriğin değişmeyeceğini garanti edersiniz, ancak işaretçiyi hareket ettirebilirsiniz.


Ahh yani son sabit olmadan, işaretçiyi tamamen farklı bir dizgeye işaret edecek şekilde ayarlayabilir miyim?
PICT

Evet, bu son sabit olmadan, işaretçi aritmetiği ile bazı yinelemeler yapmak için parametre işaretçisini kullanabilirsiniz, burada eğer bu sabit varsa, o parametrenin bir kopyası olan kendi işaretçinizi oluşturmanız gerekir.
Jesus Ramos

2

İkisinin de işe yaramaması için hiçbir sebep yok. Herşeyprint_string() yaptığı değeri yazdırmaktır. Onu değiştirmeye çalışmaz.

Sabit olarak işaret bağımsız değişkenlerini değiştirmeyen bir işlev yapmak iyi bir fikirdir. Bunun avantajı, değiştirilemeyen (veya değiştirmek istemediğiniz) değişkenlerin bu işlevlere hatasız olarak geçirilebilmesidir.

Tam sözdizimine gelince, hangi tür bağımsız değişkenlerin işleve aktarılmasının "güvenli" olduğunu belirtmek istersiniz.


2

Bunun nadiren alakalı olduğunu düşünüyorum, çünkü işleviniz & * the_string veya ** the_string gibi argümanlarla çağrılmıyor. İşaretçinin kendisi bir değer türü argümanıdır, bu nedenle onu değiştirseniz bile, işlevinizi çağırmak için kullanılan kopyayı değiştirmeyeceksiniz. Gösterdiğiniz sürüm, dizenin değişmemesini sağlar ve bu durumda bunun yeterli olduğunu düşünüyorum.


2

const char *gösterilecek şeyi değiştirmek için işaretçiyi kullanamayacağınız anlamına gelir. İşaretçiyi başka bir şeye işaret edecek şekilde değiştirebilirsiniz.

Düşünmek:

const char * promptTextWithDefault(const char * text)
{
    if ((text == NULL) || (*text == '\0'))
        text = "C>";
    return text;
}

Parametre, const char için const olmayan bir göstericidir, bu nedenle başka bir const char *değere değiştirilebilir (sabit bir dizge gibi). Ancak, yanlışlıkla yazarsak, *text = '\0'derleme hatası alırız.

Muhtemelen, parametrenin gösterdiği şeyi değiştirmek istemiyorsanız, parametreyi yapabilirsiniz const char * const text, ancak bunu yapmak yaygın değildir. Genellikle fonksiyonların parametrelere aktarılan değerleri değiştirmesine izin veririz (parametreleri değere göre geçirdiğimiz için, herhangi bir değişiklik çağıranı etkilemez).

BTW: Kaçınılması iyi bir uygulamadır char const *çünkü genellikle yanlış okunur - aynı anlama gelir const char *, ancak çok fazla insan onu anlam olarak okur char * const.


Vaov! Benim const char *ve imzam arasındaki farkı anlamaya çalışıyordum char const *- BTW'nizi ifade etme biçiminiz gerçekten yardımcı oldu!
adaçayı

1

Neredeyse diğer yanıtların tümü doğrudur, ancak bunun bir yönünü gözden kaçırırlar: constBir fonksiyon bildirimindeki bir parametrede fazladan kullandığınızda , derleyici bunu esasen yok sayar. Bir an için, örneğinizin işaretçi olmasının karmaşıklığını görmezden gelelim ve sadece bir int.

void foo(const int x);

ile aynı işlevi ilan eder

void foo(int x);

Yalnızca fonksiyonun tanımında ekstra constanlamlıdır:

void foo(const int x) {
    // do something with x here, but you cannot change it
}

Bu tanım, yukarıdaki beyanlardan herhangi biriyle uyumludur. Arayan kişi bunun umurunda değil - bu x, constarama sitesinde alakalı olmayan bir uygulama detayıdır.

Verilere bir constişaretçiniz varsa const, aynı kurallar geçerlidir:

// these declarations are equivalent
void print_string(const char * const the_string);
void print_string(const char * the_string);

// In this definition, you cannot change the value of the pointer within the
// body of the function.  It's essentially a const local variable.
void print_string(const char * const the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // COMPILER ERROR HERE
}

// In this definition, you can change the value of the pointer (but you 
// still can't change the data it's pointed to).  And even if you change
// the_string, that has no effect outside this function.
void print_string(const char * the_string) {
    cout << the_string << endl;
    the_string = nullptr;  // OK, but not observable outside this func
}

Çok az C ++ programcısı const, bu parametrelerin işaretçi olup olmadığına bakılmaksızın, olabildiğinde bile parametre oluşturmaya zahmet eder .


"derleyici bunu esasen yok sayacaktır" her zaman doğru değildir, Visual C ++ 2015 const, tanımdaki işlev parametrenize fazlalık eklerseniz ancak bildirimde bulunmazsanız uyarı üretecektir .
raymai97

@ raymai97: Bunun 2015 derleyicisinde bir hata olduğunu düşünüyorum, ancak 2015'i test etmek için kullanışlı değilim. Bazı standart uzmanlarıyla yaptığım görüşmelere göre beklenen davranış olan 2017'de anlattığım gibi çalışıyorum.
Adrian McCarthy

-1

İkisi arasındaki fark, char * 'ın herhangi bir rastgele işaretçiyi gösterebilmesidir. Const char *, aksine, yürütülebilir dosyanın DATA bölümünde tanımlanan sabitleri gösterir. Ve bu nedenle, const char * dizesinin karakter değerlerini değiştiremezsiniz.


Char * ve const char * arasındaki farkı sormuyorum. Const char * ve const char * const arasında soruyorum
pict

Bu cevap yanlıştır. A const char*, istediği her yere işaret edebilir.
Kübik
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.