Quelle est la difference entre char * const et const char *?


279

Quelle est la différence entre:

char * const 

et

const char *


8
La première chose à gauche du "const" est ce qui est constant. Si "const" est la chose la plus à gauche, alors la première chose à droite est ce qui est constant.
Cupcake

4
Comme conseil amical, n'oubliez jamais que cdecl est une chose.
Braden Best

Il y a un autre caractère const * qui est le type de retour d'exception :: what ()
Zhang

Réponses:


363

La différence est qu'il const char *s'agit d'un pointeur vers a const char, tandis que char * constc'est un pointeur constant vers a char.

La première, la valeur pointée ne peut pas être modifiée mais le pointeur peut l'être. La seconde, la valeur pointée peut changer mais pas le pointeur (similaire à une référence).

Il y a aussi

const char * const

qui est un pointeur constant vers un caractère constant (donc rien à ce sujet ne peut être changé).

Remarque:

Les deux formes suivantes sont équivalentes:

const char *

et

char const *

La raison exacte de cela est décrite dans la norme C ++, mais il est important de noter et d'éviter la confusion. Je connais plusieurs normes de codage qui préfèrent:

char const

plus de

const char

(avec ou sans pointeur) afin que le placement de l' constélément soit le même qu'avec un pointeur const.


6
Serait-il intéressant de noter ce qui se passe si plusieurs variables sont spécifiées dans la même déclaration? Je crois const int *foo,*bar;que déclarerait les deux fooet barserait int const *, mais int const *foo, *bardéclarerait fooêtre int const *et barêtre int *. Je pense typedef int * intptr; const intptr foo,bar;que déclarerait les deux variables int * const; Je ne connais aucun moyen d'utiliser une déclaration combinée pour créer deux variables de ce type sans typedef.
supercat

1
@supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Oui. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: Non! Ce serait exactement la même chose que dans le cas précédent. (Voir ideone.com/RsaB7n où vous obtenez la même erreur pour foo et bar). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Oui. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Eh bien, int *const foo, *const bar;. Syntaxe du déclarant C ...
gx_

@gx_: J'avais donc tort - mon incertitude était la raison pour laquelle j'ai suggéré qu'il pourrait être utile de dire quelles sont les règles. Que ferait int const *foo, *volatile bar-il bar? Faites les deux constet volatile? La séparation nette de Pascal des noms de variables déclarées et de leurs types me manque (un pointeur vers un tableau de pointeurs vers des entiers serait var foo: ^Array[3..4] of ^Integer; `. Ce serait une drôle de parenthèse imbriquée en C, je pense.
supercat

3
@supercat (oh, C-only, désolé pour le lien de code C ++, je suis arrivé ici d'une question C ++) Il s'agit de la syntaxe de déclaration C , avec une partie de type ("pure") suivie d'un déclarateur . Dans " int const *foo, *volatile bar", la partie type est int const(s'arrête avant le *) et les déclarants sont *foo(l'expression *foodénote un int const) et *volatile bar; lire de droite à gauche (bonne règle pour les qualificatifs cv ), fooest un pointeur vers un const int, et barest un pointeur volatil vers un const int (le pointeur lui-même est volatil, le pointé est [accédé comme] const).
gx_

@supercat Et comme pour « un pointeur sur un tableau de pointeurs vers des entiers » (je ne sais pas Pascal, pas sûr de la [3..4]syntaxe, de sorte que nous allons prendre un tableau de 10 éléments): int *(*foo)[10];. Il reflète son utilisation (future) en tant qu'expression: *(*foo)[i](avec iun entier dans la plage, [0, 10)c'est-à-dire [0, 9]) déréférencera d'abord foopour atteindre le tableau, puis accédera à l'élément à l'index i(car postfix []se lie plus étroitement que le préfixe *), puis déréférencer cet élément, enfin donnant un int(voir ideone.com/jgjIjR ). Mais typedefc'est plus facile (voir ideone.com/O3wb7d ).
gx_

102

Pour éviter toute confusion, ajoutez toujours le qualificatif 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
Pourquoi? "Pour éviter la confusion" ne m'explique pas ce qu'est la confusion.
Andrew Weir

14
@Andrew: Je faisais allusion à la cohérence et donc à la lisibilité. J'écris tous les qualificatifs de type pour qu'ils modifient ce qui est à leur gauche, toujours .
diapir

1
En fait, c'est la meilleure réponse sur le sujet que j'ai trouvé dans SO
Trap

8
En tant que norme de code, j'ai rarement rencontré ce style et je ne suis donc pas susceptible de l'adopter. Cependant, en tant qu'outil d'apprentissage, cette réponse a été très utile! (Donc je suppose que ce n'est pas un style plus commun.)
natevw

8
@Alla: pne se rapporte pas au type: (const int *const). Pour le meilleur ou pour le pire (pire si vous me le demandez), le qualificatif const, à la fois en C et C ++, est censé être postfix: cf fonction membre const void foo(int a) const;. La possibilité de déclarer const intest l'exception plutôt que la règle.
diapir

44

const modifie toujours la chose qui la précède (à gauche de celle-ci), SAUF quand c'est la première chose dans une déclaration de type, où elle modifie la chose qui la suit (à sa droite).

Donc, ces deux sont les mêmes:

int const *i1;
const int *i2;

ils définissent des pointeurs vers a const int. Vous pouvez modifier où i1et les i2points, mais vous ne pouvez pas modifier la valeur vers laquelle ils pointent.

Ce:

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

définit un constpointeur sur un entier et l'initialise pour pointer à l'emplacement de mémoire 12345678. Vous pouvez modifier la intvaleur à l'adresse 12345678, mais vous ne pouvez pas modifier l'adresse qui i3pointe vers.



18

const char*est un pointeur vers un caractère constant
char* constest un pointeur constant vers un caractère
const char* constest un pointeur constant vers un caractère constant


9

Règle générale: lisez la définition de droite à gauche!


const int *foo;

Signifie " foopointe ( *) vers un intqui ne peut pas changer ( const)".
Pour le programmeur, cela signifie "Je ne changerai pas la valeur de ce qui foopointe vers".

  • *foo = 123;ou foo[0] = 123;serait invalide.
  • foo = &bar; est autorisée.

int *const foo;

Signifie " foone peut pas changer ( const) et pointe ( *) en int".
Pour le programmeur, cela signifie "Je ne changerai pas l' adresse mémoire qui foofait référence à".

  • *foo = 123;ou foo[0] = 123;est autorisé.
  • foo = &bar; serait invalide.

const int *const foo;

Signifie " foone peut pas changer ( const) et pointe ( *) sur un intqui ne peut pas changer ( const)".
Pour le programmeur, cela signifie «Je ne changerai pas la valeur de ce qui foopointe vers, ni je ne changerai l' adresse qui foofait référence».

  • *foo = 123;ou foo[0] = 123;serait invalide.
  • foo = &bar; serait invalide.

8
  1. const char * x Ici, X est essentiellement un pointeur de caractère qui pointe vers une valeur constante

  2. char * const x fait référence au pointeur de caractère qui est constant, mais l'emplacement qu'il pointe peut être modifié.

  3. const char * const x est une combinaison de 1 et 2, signifie qu'il s'agit d'un pointeur de caractère constant qui pointe vers une valeur constante.

  4. const * char x provoquera une erreur de compilation. il ne peut pas être déclaré.

  5. char const * x est égal au point 1.

la règle générale est que si const est avec le nom var, le pointeur sera constant mais l'emplacement de pointage peut être modifié , sinon le pointeur pointera vers un emplacement constant et le pointeur peut pointer vers un autre emplacement mais le contenu de l'emplacement de pointage ne peut pas être modifié .


1
"char * const x fait référence au pointeur de caractère qui est constant, mais l'emplacement qu'il pointe peut être modifié." Faux. La valeur à l'emplacement peut être modifiée et non l'emplacement lui-même.
Aidez

3

Le premier est une erreur de syntaxe. Peut-être que vous vouliez dire la différence entre

const char * mychar

et

char * const mychar

Dans ce cas, le premier est un pointeur vers des données qui ne peuvent pas changer, et le second est un pointeur qui pointera toujours vers la même adresse.


3

Une autre règle empirique consiste à vérifier où est const :

  1. avant * => la valeur stockée est constante
  2. après * => le pointeur lui-même est constant

3

Beaucoup de réponses fournissent des techniques spécifiques, des règles empiriques, etc. pour comprendre cette instance particulière de déclaration de variable. Mais il existe une technique générique pour comprendre toute déclaration:

Règle horaire / spirale

UNE)

const char *a;

Selon la règle horaire / spirale, le apointeur sur le caractère est constant. Ce qui signifie que le caractère est constant mais que le pointeur peut changer. c'est-à a = "other string";- dire est bien, mais a[2] = 'c';ne parviendra pas à compiler

B)

char * const a;

Selon la règle, aest le pointeur const vers un caractère. c'est-à-dire que vous pouvez faire a[2] = 'c';mais vous ne pouvez pas fairea = "other string";


1
Également connu sous le nom de règle droite-gauche (du moins c'est comme ça que je l'ai appris): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(Ce serait beaucoup mieux si l'essence de la réponse n'était pas cachée derrière un lien, le texte ici ne citant même pas, ou du moins faisant référence, à l'une de ses spécificités, au-delà d'un générique "selon la règle".)
Sz.

@Sz. Avez-vous ici une confusion particulière que je peux clarifier? Il n'y a vraiment pas grand-chose après avoir connu la règle.
PnotNP

1

Je suppose que vous voulez dire const char * et char * const.

Le premier, const char *, est un pointeur sur un caractère constant. Le pointeur lui-même est modifiable.

Le second, char * const est un pointeur constant vers un caractère. Le pointeur ne peut pas changer, le caractère vers lequel il pointe peut.

Et puis il y a const char * const où le pointeur et le caractère ne peuvent pas changer.


Vos deux premiers sont en fait les mêmes et votre troisième est une erreur de compilation :)
workmad3

1

Voici une explication détaillée avec le 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 Merci.
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. Pointeur constant: Un pointeur constant peut pointer uniquement vers une seule variable du type de données respectif pendant tout le programme. Nous pouvons changer la valeur de la variable pointée par le pointeur. L'initialisation doit être effectuée pendant la période de déclaration elle-même.

Syntaxe:

datatype *const var;

char *const relève de ce cas.

/*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. Pointeur vers une valeur const : un pointeur peut pointer n'importe quel nombre de variables du type respectif, mais nous ne pouvons pas changer la valeur de l'objet pointé par le pointeur à ce moment précis.

Syntaxe:

const datatype *varou datatype const *var

const char* relève de ce cas.

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

  1. Pointant vers une valeur constante

const char * p; // la valeur ne peut pas être modifiée

  1. Pointeur constant vers une valeur

char * const p; // l'adresse ne peut pas être modifiée

  1. Pointeur constant vers une valeur constante

const char * const p; // les deux ne peuvent pas être modifiés.


1

Le constmodificateur est appliqué au terme immédiatement à sa gauche. La seule exception à cela est quand il n'y a rien à sa gauche, alors cela s'applique à ce qui est immédiatement à sa droite.

Ce sont toutes des façons équivalentes de dire "pointeur constant vers une constante char":

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

Est-il dépendant du compilateur? gcc produit pour "const char const *" et "const const char *" et "char const const *" le même résultat -> le pointeur pourrait pointer vers un autre emplacement.
cosinus0

1

Deux règles

  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.

par exemple

  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

Je voudrais souligner que l'utilisation int const *(ou const int *) ne concerne pas un pointeur pointant vers une const intvariable, mais que cette variable est constpour ce pointeur spécifique.

Par exemple:

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

Le code ci-dessus compile parfaitement bien. _ppointe vers une constvariable, varmême si elle-même n'est pas constante.


1

Je me souviens d'un livre tchèque sur C: lisez la déclaration que vous commencez avec la variable et allez à gauche. Donc pour

char * const a;

vous pouvez lire comme: " aest une variable de type pointeur constant vers char",

char const * a;

vous pouvez lire comme: " aest un pointeur vers une variable constante de type char. J'espère que cela aide.

Prime:

const char * const a;

Vous lirez tel aquel un pointeur constant vers une variable constante de type char.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.