Qual è la differenza tra char * const e const char *?


279

Qual è la differenza tra:

char * const 

e

const char *


8
La prima cosa a sinistra della "const" è ciò che è costante. Se "const" è la cosa più lontana a sinistra, allora la prima cosa a destra è ciò che è costante.
Cupcake,

4
Come suggerimento amichevole, non dimenticare mai che cdecl è una cosa.
Braden Best,

C'è un altro carattere const * che è il tipo restituito di eccezione :: what ()
Zhang

Risposte:


363

La differenza è che const char *è un puntatore a const char, mentre char * constè un puntatore costante a char.

Il primo, il valore indicato non può essere modificato, ma può essere il puntatore. Il secondo, il valore puntato può cambiare ma il puntatore non può (simile a un riferimento).

C'è anche un

const char * const

che è un puntatore costante a un carattere costante (quindi nulla può essere modificato).

Nota:

Le seguenti due forme sono equivalenti:

const char *

e

char const *

Il motivo esatto è descritto nello standard C ++, ma è importante notare ed evitare la confusione. Conosco diversi standard di codifica che preferiscono:

char const

al di sopra di

const char

(con o senza puntatore) in modo che il posizionamento constdell'elemento sia lo stesso di un puntatore const.


6
Vale la pena notare cosa succede se nella stessa dichiarazione vengono specificate più variabili? Credo const int *foo,*bar;che dichiarerebbe entrambi fooe bardi essere int const *, ma int const *foo, *bardichiarerebbe foodi essere un int const *e bardi essere int *. Penso typedef int * intptr; const intptr foo,bar;che dichiarerebbe entrambe le variabili int * const; Non conosco alcun modo per utilizzare una dichiarazione combinata per creare due variabili di quel tipo senza un typedef.
supercat

1
@supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Sì. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: No! Sarebbe esattamente lo stesso del caso precedente. (Vedi ideone.com/RsaB7n dove ottieni lo stesso errore sia per foo che per bar). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Sì. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Beh, int *const foo, *const bar;. Sintassi del dichiaratore C ...
gx_

@gx_: Quindi ho sbagliato - la mia incertezza era il motivo per cui ho suggerito che potrebbe essere utile dire quali sono le regole. Cosa farebbe int const *foo, *volatile barper bar? Renderlo entrambi conste volatile? Separazione di I Miss Pascal pulita di nomi di variabili dichiarati e le loro tipologie (un puntatore a un array di puntatori a interi sarebbero var foo: ^Array[3..4] of ^Integer.;. `Sarebbe alcuni divertenti cosa parentesi nidificato in C, credo
Supercat

3
@supercat (oh, solo C, scusate il collegamento al codice C ++, sono arrivato qui da una domanda C ++) Riguarda la sintassi della dichiarazione C , con una parte di tipo ("puro") seguita da un dichiaratore . In " int const *foo, *volatile bar" la parte del tipo è int const(si ferma prima del *) e i dichiaratori sono *foo(l'espressione *fooindicherà un int const) e *volatile bar; lettura da destra a sinistra (buona regola per i qualificatori cv ), fooè un puntatore a un const int ed barè un puntatore volatile a un const int (il puntatore stesso è volatile, l'int puntato è [accessibile come] const).
gx_

@supercat E per quanto riguarda "un puntatore a un array di puntatori a interi" (non so Pascal, non sicuro circa la [3..4]sintassi, quindi cerchiamo di prendere un array di 10 elementi): int *(*foo)[10];. Riflette il suo (futuro) uso come espressione: *(*foo)[i](con iun numero intero nell'intervallo [0, 10)cioè [0, 9]) farà prima il dereference fooper arrivare all'array, quindi accederà all'elemento in index i(perché postfix si []lega più stretto del prefisso *), quindi dereference questo elemento, infine cedere un int(vedi ideone.com/jgjIjR ). Ma typedefrende più semplice (vedi ideone.com/O3wb7d ).
gx_

102

Per evitare confusione, aggiungere sempre il qualificatore const.

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
Perché? "Per evitare confusione" non spiega quale sia la confusione per me.
Andrew Weir,

14
@Andrew: stavo accennando alla coerenza e quindi alla leggibilità. Scrivere tutte le qualificazioni di tipo in modo che modificano ciò che è alla loro sinistra, sempre , è quello che uso.
diapir,

1
In realtà è la migliore risposta sull'argomento che ho trovato in SO
Trap il

8
Come standard di codice, raramente ho riscontrato questo stile e quindi non ho probabilità di adottarlo. Tuttavia, come strumento di apprendimento, questa risposta è stata molto utile! (Quindi immagino che questo non sia uno stile più comune.)
Natevw,

8
@Alla: pnon riguarda il tipo: (const int *const). Nel bene o nel male (peggio se me lo chiedi) il qualificatore const, sia in C che in C ++, è pensato per essere postfix: cf const membro function void foo(int a) const;. La possibilità di dichiarare const intè l'eccezione piuttosto che la regola.
diapir,

44

const modifica sempre la cosa che le precede (alla sua sinistra), TRANNE quando è la prima cosa in una dichiarazione di tipo, dove modifica la cosa che la segue (alla sua destra).

Quindi questi due sono gli stessi:

int const *i1;
const int *i2;

definiscono i puntatori a const int. Puoi cambiare dove i1e i2punti, ma non puoi cambiare il valore a cui puntano.

Questo:

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

definisce un constpuntatore a un numero intero e lo inizializza in modo che punti nella posizione di memoria 12345678. È possibile modificare il intvalore all'indirizzo 12345678, ma non è possibile modificare l'indirizzo a cui i3punta.



18

const char*è un puntatore a un carattere costante
char* constè un puntatore costante a un personaggio
const char* constè un puntatore costante a un carattere costante


9

Regola empirica: leggi la definizione da destra a sinistra!


const int *foo;

Significa " foopunti ( *) a un intche non può cambiare ( const)".
Per il programmatore questo significa "Non cambierò il valore di ciò che fooindica".

  • *foo = 123;o foo[0] = 123;sarebbe non valido.
  • foo = &bar; È permesso.

int *const foo;

Significa " fooimpossibile cambiare ( const) e punta ( *) a un int".
Per il programmatore questo significa "Non cambierò l' indirizzo di memoria a cui si fooriferisce".

  • *foo = 123;o foo[0] = 123;è permesso.
  • foo = &bar; sarebbe invalido.

const int *const foo;

Significa " fooimpossibile cambiare ( const) e punta ( *) a un intche non può cambiare ( const)".
Per il programmatore questo significa "Non cambierò il valore di ciò a cui foopunta, né cambierò l' indirizzo a cui si fooriferisce".

  • *foo = 123;o foo[0] = 123;sarebbe non valido.
  • foo = &bar; sarebbe invalido.

8
  1. const char * x Qui X è sostanzialmente un puntatore a caratteri che punta a un valore costante

  2. char * const x si riferisce al puntatore di carattere che è costante, ma la posizione a cui punta può essere modificata.

  3. const char * const x è una combinazione di 1 e 2, significa che è un puntatore a carattere costante che punta a un valore costante.

  4. const * char x provocherà un errore del compilatore. non può essere dichiarato.

  5. char const * x è uguale al punto 1.

la regola empirica è se const è con il nome var quindi il puntatore sarà costante ma la posizione di puntamento può essere cambiata , altrimenti il puntatore punterà a una posizione costante e il puntatore può puntare su un'altra posizione ma il contenuto della posizione di puntamento non può essere cambiato .


1
"char * const x si riferisce al puntatore di carattere che è costante, ma la posizione che punta può essere cambiata." Sbagliato. Il valore nella posizione può essere modificato non nella posizione stessa.
Aiutatemi il

3

Il primo è un errore di sintassi. Forse intendevi la differenza tra

const char * mychar

e

char * const mychar

In tal caso, il primo è un puntatore a dati che non possono cambiare, e il secondo è un puntatore che punta sempre allo stesso indirizzo.


3

Un'altra regola del pollice è controllare dove const è :

  1. prima * => il valore memorizzato è costante
  2. dopo * => il puntatore stesso è costante

3

Molte risposte forniscono tecniche specifiche, regola dei pollici ecc. Per comprendere questa particolare istanza di dichiarazione variabile. Ma esiste una tecnica generica per comprendere qualsiasi dichiarazione:

Regola in senso orario / a spirale

UN)

const char *a;

Secondo la regola in senso orario / spirale aè puntatore a carattere che è costante. Ciò significa che il carattere è costante ma il puntatore può cambiare. cioè a = "other string";va bene ma a[2] = 'c';non riuscirà a compilare

B)

char * const a;

Secondo la regola, aè puntatore const a un personaggio. cioè puoi farlo a[2] = 'c';ma non puoi farloa = "other string";


1
Conosciuta anche come regola della destra (almeno così ho imparato): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(Sarebbe molto meglio se l'essenza della risposta non fosse nascosta dietro un collegamento, con il testo che qui non cita nemmeno, o almeno si riferisce a uno dei suoi dettagli, al di là di un generico "come da regola".)
sz.

@Sz. Hai qualche confusione specifica qui che posso chiarire? Non c'è davvero molto da fare dopo aver conosciuto la regola.
PnotNP

1

Suppongo che intendi const char * e char * const.

Il primo, const char *, è un puntatore a un carattere costante. Il puntatore stesso è modificabile.

Il secondo, char * const è un puntatore costante a un carattere. Il puntatore non può cambiare, il carattere a cui punta può.

E poi c'è const char * const in cui il puntatore e il carattere non possono cambiare.


I tuoi primi due sono in realtà gli stessi e il terzo è un errore del compilatore :)
workmad3

1

Ecco una spiegazione dettagliata con il codice

/*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 Grazie.
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. Puntatore costante: un puntatore costante può puntare solo a una singola variabile del rispettivo tipo di dati durante l'intero programma. È possibile modificare il valore della variabile puntata dal puntatore. L'inizializzazione dovrebbe essere effettuata durante il periodo della dichiarazione stessa.

Sintassi:

datatype *const var;

char *const rientra in questo caso.

/*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. Puntatore a un valore const : in questo un puntatore può puntare un numero qualsiasi di variabili del rispettivo tipo ma non possiamo cambiare il valore dell'oggetto puntato dal puntatore in quel momento specifico.

Sintassi:

const datatype *varo datatype const *var

const char* rientra in questo caso.

/* 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 e const char *?

  1. Indicando un valore costante

const char * p; // il valore non può essere modificato

  1. Puntatore costante a un valore

char * const p; // l'indirizzo non può essere modificato

  1. Puntatore costante a un valore costante

const char * const p; // entrambi non possono essere modificati.


1

Il const modificatore viene applicato al termine immediatamente alla sua sinistra. L'unica eccezione a ciò è quando non c'è nulla alla sua sinistra, quindi si applica a ciò che è immediatamente alla sua destra.

Questi sono tutti modi equivalenti di dire "puntatore costante a una costante char":

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

Dipende dal compilatore? gcc produce per "const char const *" e "const const char *" e "char const const *" lo stesso risultato -> puntatore potrebbe puntare verso un'altra posizione.
cosinus0

1

Due regole

  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.

per esempio

  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

Vorrei sottolineare che l'utilizzo int const *(o const int *) non riguarda un puntatore che punta a una const intvariabile, ma che questa variabile è constper questo puntatore specifico.

Per esempio:

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

Il codice sopra si compila perfettamente bene. _ppunta a una constvariabile, sebbene varnon sia costante.


1

Ricordo dal libro ceco su C: leggi la dichiarazione che inizi con la variabile e vai a sinistra. Così per

char * const a;

puoi leggere come: " aè una variabile di tipo puntatore costante a char",

char const * a;

puoi leggere come: " aè un puntatore a variabile costante di tipo char. Spero che questo ti aiuti.

Bonus:

const char * const a;

Leggerai come aè puntatore costante alla variabile costante di tipo char.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.