Was ist der Unterschied zwischen char * const und const char *?


279

Was ist der Unterschied zwischen:

char * const 

und

const char *


8
Das erste, was links von der "const" steht, ist die Konstante. Wenn "const" das am weitesten links liegende ist, dann ist das erste, was rechts davon ist, das, was konstant ist.
Cupcake

4
Vergessen Sie als freundlichen Tipp niemals, dass cdecl eine Sache ist.
Braden Best

Es gibt eine andere char const *, die der Rückgabetyp der Ausnahme ist :: what ()
Zhang

Antworten:


363

Der Unterschied besteht darin, dass const char *es sich um einen Zeiger auf a handelt const char, während char * constes sich um einen konstanten Zeiger auf a handelt char.

Der erste Wert, auf den gezeigt wird, kann nicht geändert werden, der Zeiger jedoch. Der zweite Wert, auf den gezeigt wird, kann sich ändern, der Zeiger jedoch nicht (ähnlich einer Referenz).

Da ist auch ein

const char * const

Dies ist ein konstanter Zeiger auf ein konstantes Zeichen (daher kann nichts daran geändert werden).

Hinweis:

Die folgenden zwei Formen sind äquivalent:

const char *

und

char const *

Der genaue Grund hierfür ist im C ++ - Standard beschrieben, es ist jedoch wichtig, die Verwirrung zu beachten und zu vermeiden. Ich kenne mehrere Codierungsstandards, die Folgendes bevorzugen:

char const

Über

const char

(mit oder ohne Zeiger), so dass die Platzierung des constElements dieselbe ist wie bei einem Zeiger const.


6
Wäre es sinnvoll zu beachten, was passiert, wenn mehrere Variablen in derselben Deklaration angegeben werden? Ich glaube, const int *foo,*bar;würde beides erklären foound barsein int const *, aber int const *foo, *barwürde erklären foo, ein int const *und barzu sein int *. Ich denke typedef int * intptr; const intptr foo,bar;, beide Variablen würden deklariert int * const; Ich kenne keine Möglichkeit, eine kombinierte Deklaration zu verwenden, um zwei Variablen dieses Typs ohne typedef zu erstellen.
Supercat

1
@ Supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Ja. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: Nein! Es wäre genau das gleiche wie im vorherigen Fall. (Siehe ideone.com/RsaB7n, wo Sie den gleichen Fehler für foo und bar erhalten). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Ja. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Nun, int *const foo, *const bar;. C-Deklaratorsyntax ...
gx_

@gx_: Also habe ich mich geirrt - meine Unsicherheit war, warum ich vorgeschlagen habe, dass es hilfreich sein könnte, die Regeln zu sagen. Was würde int const *foo, *volatile barich tun bar? Machen Sie es beide constund volatile? Ich vermisse Pascals saubere Trennung von Namen deklarierter Variablen und ihren Typen (ein Zeiger auf ein Array von Zeigern auf ganze Zahlen wäre var foo: ^Array[3..4] of ^Integer; `. Das wäre eine lustige Sache in verschachtelten Klammern in C, denke ich.
Supercat

3
@supercat (oh, C-only, sorry für den C ++ Code - Link, habe ich hier aus einer C ++ Frage) Es geht um die C - Deklaration Syntax , mit einem ( "rein") Typ Teil , gefolgt von einem declarator . In " int const *foo, *volatile bar" ist der Typ Teil int const(stoppt vor dem *) und die Deklaratoren sind *foo(der Ausdruck *foobezeichnet ein int const) und *volatile bar; Lesen von rechts nach links (gute Regel für cv-Qualifier ), fooist ein Zeiger auf einen const int, und barist ein flüchtiger Zeiger auf ein const int (der Zeiger selbst ist flüchtig, auf das spitze int wird [als] const zugegriffen).
gx_

@supercat Und was "einen Zeiger auf ein Array von Zeigern auf ganze Zahlen" betrifft (ich kenne Pascal nicht, bin mir der [3..4]Syntax nicht sicher , also nehmen wir ein Array von 10 Elementen) : int *(*foo)[10];. Es spiegelt seine (zukünftige) Verwendung als Ausdruck wider: *(*foo)[i](mit ieiner Ganzzahl im Bereich [0, 10)dh [0, 9]) wird zuerst dereferenziert foo, um auf das Array zuzugreifen, dann auf das Element am Index zuzugreifen i(da das Postfix []enger als das Präfix bindet *) und dieses Element schließlich dereferenziert Nachgeben eines int(siehe ideone.com/jgjIjR ). Aber typedefmacht es einfacher (siehe ideone.com/O3wb7d ).
gx_

102

Um Verwirrung zu vermeiden, hängen Sie immer das const-Qualifikationsmerkmal an.

int       *      mutable_pointer_to_mutable_int;
int const *      mutable_pointer_to_constant_int;
int       *const constant_pointer_to_mutable_int;
int const *const constant_pointer_to_constant_int;

10
Warum? "Um Verwirrung zu vermeiden" erklärt mir nicht, was die Verwirrung ist.
Andrew Weir

14
@ Andrew: Ich habe auf Konsistenz und damit Lesbarkeit hingewiesen. Schreiben aller Art - Qualifikation , so dass sie ändern , was auf ihrer linken ist, immer ist, was ich benutze.
Diapir

1
Eigentlich ist es die beste Antwort zu dem Thema, das ich in SO
Trap

8
Als Codestandard bin ich selten auf diesen Stil gestoßen und werde ihn daher wahrscheinlich nicht übernehmen. Als Lernwerkzeug war diese Antwort jedoch sehr hilfreich! (Also ich denke schade, dass dies nicht üblicher Stil ist.)
Natevw

8
@Alla: pbezieht sich nicht auf den Typ : (const int *const). Zum Guten oder Schlechten (schlechter, wenn Sie mich fragen) ist das const-Qualifikationsmerkmal sowohl in C als auch in C ++ als Postfix: cf const-Member-Funktion gedacht void foo(int a) const;. Die Möglichkeit zu deklarieren const intist eher die Ausnahme als die Regel.
Diapir

44

const Ändert immer das, was davor steht (links davon), AUSSER wenn es das erste in einer Typdeklaration ist, wo es das Ding ändert, das danach kommt (rechts davon).

Diese beiden sind also gleich:

int const *i1;
const int *i2;

sie definieren Zeiger auf a const int. Sie können wo i1und i2Punkte ändern , aber Sie können den Wert, auf den sie zeigen, nicht ändern.

Dies:

int *const i3 = (int*) 0x12345678;

Definiert einen constZeiger auf eine Ganzzahl und initialisiert ihn so, dass er auf den Speicherplatz 12345678 zeigt. Sie können den intWert an der Adresse 12345678 ändern, aber die Adresse, auf die i3zeigt, kann nicht geändert werden .



18

const char*ist ein Zeiger auf ein konstantes Zeichen
char* constist ein konstanter Zeiger auf ein Zeichen
const char* constist ein konstanter Zeiger auf ein konstantes Zeichen


9

Faustregel: Lesen Sie die Definition von rechts nach links!


const int *foo;

Bedeutet " fooPunkte ( *) auf eine int, die sich nicht ändern kann ( const)".
Für den Programmierer bedeutet dies "Ich werde den Wert dessen, auf was foozeigt, nicht ändern ".

  • *foo = 123;oder foo[0] = 123;wäre ungültig.
  • foo = &bar; ist erlaubt.

int *const foo;

Bedeutet " fookann nicht ändern ( const) und zeigt ( *) auf ein int".
Für den Programmierer bedeutet dies "Ich werde die Speicheradresse, auf die fooBezug genommen wird, nicht ändern ".

  • *foo = 123;oder foo[0] = 123;ist erlaubt.
  • foo = &bar; wäre ungültig.

const int *const foo;

Bedeutet " fookann sich nicht ändern ( const) und zeigt ( *) auf ein int, das sich nicht ändern kann ( const)".
Für den Programmierer bedeutet dies "Ich werde weder den Wert der fooPunkte ändern, noch die Adresse , fooauf die verwiesen wird ".

  • *foo = 123;oder foo[0] = 123;wäre ungültig.
  • foo = &bar; wäre ungültig.

8
  1. const char * x Hier ist X im Grunde ein Zeichenzeiger, der auf einen konstanten Wert zeigt

  2. char * const x bezieht sich auf einen konstanten Zeichenzeiger, aber die Position, auf die er zeigt, kann geändert werden.

  3. const char * const x ist eine Kombination aus 1 und 2, dh es handelt sich um einen konstanten Zeichenzeiger, der auf einen konstanten Wert zeigt.

  4. const * char x verursacht einen Compilerfehler. es kann nicht deklariert werden.

  5. char const * x ist gleich Punkt 1.

Als Faustregel gilt: Wenn const den Namen var hat, ist der Zeiger konstant, aber die Zeigeposition kann geändert werden. Andernfalls zeigt der Zeiger auf eine konstante Position und der Zeiger kann auf eine andere Position zeigen, der Inhalt der Zeigeposition kann jedoch nicht geändert werden .


1
"char * const x bezieht sich auf einen konstanten Zeichenzeiger, aber die Position, auf die er zeigt, kann geändert werden." Falsch. Der Wert am Standort kann geändert werden, nicht der Standort selbst.
Bitte helfen Sie

3

Der erste ist ein Syntaxfehler. Vielleicht hast du den Unterschied zwischen gemeint

const char * mychar

und

char * const mychar

In diesem Fall ist der erste ein Zeiger auf Daten, die sich nicht ändern können, und der zweite ist ein Zeiger, der immer auf dieselbe Adresse zeigt.


3

Eine andere Faustregel ist zu überprüfen, wo const ist :

  1. vor * => gespeicherter Wert ist konstant
  2. nach * => Zeiger selbst ist konstant

3

Viele Antworten bieten spezifische Techniken, Daumenregeln usw., um diese spezielle Instanz der Variablendeklaration zu verstehen. Es gibt jedoch eine generische Technik, um jede Erklärung zu verstehen:

Im Uhrzeigersinn / Spiralregel

EIN)

const char *a;

Gemäß der Regel im Uhrzeigersinn / Spirale aist der Zeiger auf ein Zeichen konstant. Das heißt, das Zeichen ist konstant, aber der Zeiger kann sich ändern. dh a = "other string";ist in Ordnung, kann aber a[2] = 'c';nicht kompiliert werden

B)

char * const a;

Gemäß der Regel aist const Zeiger auf ein Zeichen. dh Sie können tun, a[2] = 'c';aber Sie können nicht tuna = "other string";


1
Auch als Rechts-Links-Regel bekannt (zumindest habe ich das so gelernt): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(Wäre viel besser, wenn das Wesentliche der Antwort nicht hinter einem Link verborgen wäre, wobei der Text hier nicht einmal eine seiner Besonderheiten zitiert oder zumindest auf diese verweist, die über ein generisches "gemäß der Regel" hinausgehen.)
Gr.

@Sz. Haben Sie hier eine bestimmte Verwirrung, die ich beseitigen kann? Es ist wirklich nicht viel dran, nachdem man die Regel gekannt hat.
PnotNP

1

Ich nehme an, Sie meinen const char * und char * const.

Das erste, const char *, ist ein Zeiger auf ein konstantes Zeichen. Der Zeiger selbst ist veränderbar.

Das zweite, char * const, ist ein konstanter Zeiger auf ein Zeichen. Der Zeiger kann sich nicht ändern, das Zeichen, auf das er zeigt, kann.

Und dann gibt es const char * const, wo sich Zeiger und Zeichen nicht ändern können.


Ihre ersten beiden sind tatsächlich gleich und Ihre dritte ist ein Compilerfehler :)
workmad3

1

Hier ist eine detaillierte Erklärung mit Code

/*const char * p;
char * const p; 
const char * const p;*/ // these are the three conditions,

// const char *p;const char * const p; pointer value cannot be changed

// char * const p; pointer address cannot be changed

// const char * const p; both cannot be changed.

#include<stdio.h>

/*int main()
{
    const char * p; // value cannot be changed
    char z;
    //*p = 'c'; // this will not work
    p = &z;
    printf(" %c\n",*p);
    return 0;
}*/

/*int main()
{
    char * const p; // address cannot be changed
    char z;
    *p = 'c'; 
    //p = &z;   // this will not work
    printf(" %c\n",*p);
    return 0;
}*/



/*int main()
{
    const char * const p; // both address and value cannot be changed
    char z;
    *p = 'c'; // this will not work
    p = &z; // this will not work
    printf(" %c\n",*p);
    return 0;
}*/

@ reese moore Danke.
Megharaj

1
// Some more complex constant variable/pointer declaration.
// Observing cases when we get error and warning would help
// understanding it better.

int main(void)
{
  char ca1[10]= "aaaa"; // char array 1
  char ca2[10]= "bbbb"; // char array 2

  char *pca1= ca1;
  char *pca2= ca2;

  char const *ccs= pca1;
  char * const csc= pca2;
  ccs[1]='m';  // Bad - error: assignment of read-only location ‘*(ccs + 1u)’
  ccs= csc;    // Good

  csc[1]='n';  // Good
  csc= ccs;    // Bad - error: assignment of read-only variable ‘csc’

  char const **ccss= &ccs;     // Good
  char const **ccss1= &csc;    // Bad - warning: initialization from incompatible pointer type

  char * const *cscs= &csc;    // Good
  char * const *cscs1= &ccs;   // Bad - warning: initialization from incompatible pointer type

  char ** const cssc=   &pca1; // Good
  char ** const cssc1=  &ccs;  // Bad - warning: initialization from incompatible pointer type
  char ** const cssc2=  &csc;  // Bad - warning: initialization discards ‘const’
                               //                qualifier from pointer target type

  *ccss[1]= 'x'; // Bad - error: assignment of read-only location ‘**(ccss + 8u)’
  *ccss= ccs;    // Good
  *ccss= csc;    // Good
  ccss= ccss1;   // Good
  ccss= cscs;    // Bad - warning: assignment from incompatible pointer type

  *cscs[1]= 'y'; // Good
  *cscs= ccs;    // Bad - error: assignment of read-only location ‘*cscs’
  *cscs= csc;    // Bad - error: assignment of read-only location ‘*cscs’
  cscs= cscs1;   // Good
  cscs= cssc;    // Good

  *cssc[1]= 'z'; // Good
  *cssc= ccs;    // Bad - warning: assignment discards ‘const’
                 //                qualifier from pointer target type
  *cssc= csc;    // Good
  *cssc= pca2;   // Good
  cssc= ccss;    // Bad - error: assignment of read-only variable ‘cssc’
  cssc= cscs;    // Bad - error: assignment of read-only variable ‘cssc’
  cssc= cssc1;   // Bad - error: assignment of read-only variable ‘cssc’
}

1
  1. Konstanter Zeiger : Ein konstanter Zeiger kann während des gesamten Programms nur auf eine einzelne Variable des jeweiligen Datentyps zeigen. Wir können den Wert der Variablen ändern, auf die der Zeiger zeigt. Die Initialisierung sollte zum Zeitpunkt der Deklaration selbst erfolgen.

Syntax:

datatype *const var;

char *const fällt unter diesen Fall.

/*program to illustrate the behaviour of constant pointer */

#include<stdio.h>
int main(){
  int a=10;
  int *const ptr=&a;
  *ptr=100;/* we can change the value of object but we cannot point it to another variable.suppose another variable int b=20; and ptr=&b; gives you error*/
  printf("%d",*ptr);
  return 0;
}
  1. Zeiger auf einen konstanten Wert : In diesem Fall kann ein Zeiger auf eine beliebige Anzahl von Variablen des jeweiligen Typs zeigen, aber wir können den Wert des Objekts, auf das der Zeiger zu diesem bestimmten Zeitpunkt zeigt, nicht ändern.

Syntax:

const datatype *varoder datatype const *var

const char* fällt unter diesen Fall.

/* program to illustrate the behavior of pointer to a constant*/

   #include<stdio.h>
   int main(){
       int a=10,b=20;
       int const *ptr=&a;
       printf("%d\n",*ptr);
       /*  *ptr=100 is not possible i.e we cannot change the value of the object pointed by the pointer*/
       ptr=&b;
       printf("%d",*ptr);
       /*we can point it to another object*/
       return 0;
    }

1

char * const und const char *?

  1. Auf einen konstanten Wert zeigen

const char * p; // Wert kann nicht geändert werden

  1. Konstanter Zeiger auf einen Wert

char * const p; // Adresse kann nicht geändert werden

  1. Konstanter Zeiger auf einen konstanten Wert

const char * const p; // beide können nicht geändert werden.


1

Das const Modifikator wird auf den Begriff unmittelbar links davon angewendet. Die einzige Ausnahme ist, wenn links nichts ist, dann gilt dies für das, was unmittelbar rechts davon ist.

Dies sind alles äquivalente Arten, "konstanter Zeiger auf eine Konstante char" zu sagen :

  • const char * const
  • const char const *
  • char const * const
  • char const const *

Ist es vom Compiler abhängig? gcc erzeugt für "const char const *" und "const const char *" und "char const const *" das gleiche Ergebnis -> Zeiger könnte auf eine andere Position zeigen.
Cosinus0

1

Zwei Regeln

  1. If const is between char and *, it will affect the left one.
  2. If const is not between char and *, it will affect the nearest one.

z.B

  1. char const *. This is a pointer points to a constant char.
  2. char * const. This is a constant pointer points to a char.

1

Ich möchte darauf hinweisen, dass es bei der Verwendung von int const *(oder const int *) nicht um einen Zeiger geht, der auf eine const intVariable zeigt, sondern dass diese Variable constfür diesen bestimmten Zeiger bestimmt ist.

Beispielsweise:

int var = 10;
int const * _p = &var;

Der obige Code wird einwandfrei kompiliert. _pzeigt auf eine constVariable, obwohl sie varselbst nicht konstant ist.


1

Ich erinnere mich aus dem tschechischen Buch über C: Lesen Sie die Erklärung, dass Sie mit der Variablen beginnen und nach links gehen. So für

char * const a;

Sie können lesen als: " aist eine Variable vom Typ Konstantenzeiger auf char",

char const * a;

Sie können lesen als: " aist ein Zeiger auf eine konstante Variable vom Typ char. Ich hoffe, das hilft.

Bonus:

const char * const a;

Sie lesen den akonstanten Zeiger auf eine konstante Variable vom Typ char.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.