Qual é a diferença entre char * const e const char *?


279

Qual é a diferença entre:

char * const 

e

const char *


8
A primeira coisa à esquerda da "const" é o que é constante. Se "const" é a coisa mais distante à esquerda, a primeira coisa à direita é a constante.
Cupcake

4
Como uma dica amigável, nunca esqueça que o cdecl é uma coisa.
Braden Best

Há um outro const char * que é o tipo de retorno de exceção :: what ()
Zhang

Respostas:


363

A diferença é que const char *é um ponteiro para a const char, enquanto char * consté um ponteiro constante para a char.

A primeira, o valor apontado não pode ser alterado, mas o ponteiro pode ser. O segundo, o valor apontado pode mudar, mas o ponteiro não pode (semelhante a uma referência).

Há também um

const char * const

que é um ponteiro constante para um caractere constante (para que nada possa ser alterado).

Nota:

Os dois seguintes formulários são equivalentes:

const char *

e

char const *

A razão exata para isso é descrita no padrão C ++, mas é importante observar e evitar a confusão. Conheço vários padrões de codificação que preferem:

char const

sobre

const char

(com ou sem ponteiro) para que o posicionamento do constelemento seja o mesmo que com um ponteiro const.


6
Vale a pena observar o que acontece se várias variáveis ​​forem especificadas na mesma declaração? Eu acredito const int *foo,*bar;que declararia ambos fooe barser int const *, mas int const *foo, *bardeclararia fooser um int const *e barser int *. Eu acho typedef int * intptr; const intptr foo,bar;que declararia ambas as variáveis ​​como int * const; Não conheço nenhuma maneira de usar uma declaração combinada para criar duas variáveis ​​desse tipo sem um typedef.
precisa

1
@ supercat I believe const int *foo,*bar; would declare both foo and bar to be int const *: Sim. but int const *foo, *bar would declare foo to be a int const * and bar to be int *: Não! Seria exatamente o mesmo que no caso anterior. (Consulte ideone.com/RsaB7n, onde você obtém o mesmo erro para foo e bar). I think typedef int * intptr; const intptr foo,bar; would declare both variables to be int * const: Sim. I don't know any way to use a combined declaration to create two variables of that type without a typedef: Bem int *const foo, *const bar;,. Sintaxe do declarador C ...
gx_

@gx_: Então eu estava errado - minha incerteza foi por que sugeri que seria útil dizer quais são as regras. O que int const *foo, *volatile barfaria bar? Faça as duas coisas conste volatile? Eu sinto falta da separação limpa de Pascal de nomes de variáveis ​​declaradas e seus tipos (um ponteiro para uma matriz de ponteiros para números inteiros seria var foo: ^Array[3..4] of ^Integer; `. Isso seria algo engraçado entre parênteses aninhados em C, eu acho.
supercat

3
@ supercat (oh, somente C, desculpe pelo link do código C ++, cheguei aqui de uma pergunta em C ++) É tudo sobre a sintaxe da declaração C , com uma parte do tipo ("pura") seguida por um declarador . Em " int const *foo, *volatile bar" a parte do tipo é int const(para antes de *) e os declaradores *foo(a expressão *fooindica um int const) e *volatile bar; ler da direita para a esquerda (boa regra para qualificadores de cv ) fooé um ponteiro para uma const int e baré um ponteiro volátil para uma const int (o ponteiro em si é volátil, o int apontado é [acessado como] const).
gx_ 28/08

@supercat E quanto a "um ponteiro para uma matriz de ponteiros para inteiros" (Eu não sei Pascal, não tenho certeza sobre a [3..4]sintaxe, então vamos dar um array de 10 elementos): int *(*foo)[10];. Ele reflete seu uso (futuro) como uma expressão: *(*foo)[i](com ium número inteiro no intervalo, [0, 10)ie [0, 9]) fará primeiro a desreferência foopara chegar ao array e, em seguida, acessará o elemento no índicei (por causa do sufixo []se liga mais apertados do que prefixo *), em seguida, cancelar a referência desse elemento, finalmente produzindo um int(consulte ideone.com/jgjIjR ). Mas typedeftorna mais fácil (consulte ideone.com/O3wb7d ).
gx_

102

Para evitar confusão, sempre anexe o qualificador 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
Por quê? "Para evitar confusão" não explica qual é a confusão para mim.
Andrew Weir

14
@ Andrew: Eu estava sugerindo consistência e, portanto, legibilidade. Escrever todos os qualificadores de tipo para que eles modifiquem o que está à esquerda, sempre , é o que eu uso.
Diapir #

1
Na verdade, é a melhor resposta sobre o assunto que encontrei no SO
Trap

8
Como padrão de código, raramente encontrei esse estilo e, portanto, provavelmente não o adotarei. No entanto, como uma ferramenta de aprendizado, essa resposta foi muito útil! (Então eu acho muito ruim este não é o estilo mais comum.)
natevw

8
@Alla: pnão se relaciona com o tipo: (const int *const). Para melhor ou pior (pior, se você me perguntar), o qualificador const, tanto em C quanto em C ++, deve ser postfix: cf const member function void foo(int a) const;. A possibilidade de declarar const inté a exceção e não a regra.
Diapr /

44

const sempre modifica o que vem antes (à esquerda), EXCETO quando é a primeira coisa em uma declaração de tipo, onde modifica o que vem depois (à direita).

Então, esses dois são os mesmos:

int const *i1;
const int *i2;

eles definem ponteiros para um const int . Você pode alterar onde i1e i2pontos, mas não pode alterar o valor para o qual eles apontam.

Este:

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

define um constponteiro para um número inteiro e inicializa-o para apontar para o local da memória 12345678. Você pode alterar o intvalor no endereço 12345678, mas não pode alterar o endereço para o qual i3aponta.



18

const char*é um ponteiro para um personagem constante
char* consté um ponteiro constante para um personagem
const char* consté um ponteiro constante para um personagem constante


9

Regra prática: leia a definição da direita para a esquerda!


const int *foo;

Significa " foopontos ( *) para um intque não pode ser alterado ( const)".
Para o programador, isso significa "Não alterarei o valor do que fooaponta para".

  • *foo = 123; ou foo[0] = 123; seria inválido.
  • foo = &bar; é permitido.

int *const foo;

Significa " foonão é possível alterar ( const) e apontar ( *) para um int".
Para o programador, isso significa "Não alterarei o endereço de memória que foose refere a".

  • *foo = 123; ou foo[0] = 123; é permitido.
  • foo = &bar; seria inválido.

const int *const foo;

Significa " foonão é possível alterar ( const) e aponta ( *) para um intque não pode ser alterado ( const)".
Para o programador, isso significa "Eu não alterarei o valor do que fooaponta, nem alterarei o endereço que foose refere a".

  • *foo = 123; ou foo[0] = 123; seria inválido.
  • foo = &bar; seria inválido.

8
  1. const char * x Aqui X é basicamente um ponteiro de caractere que está apontando para um valor constante

  2. char * const x refere-se ao ponteiro de caractere que é constante, mas o local que está apontando pode ser alterado.

  3. const char * const x é uma combinação de 1 e 2, significa que é um ponteiro de caractere constante que está apontando para um valor constante.

  4. const * char x causará um erro do compilador. não pode ser declarado.

  5. char const * x é igual ao ponto 1.

a regra geral é que, se const estiver com o nome var, o ponteiro será constante, mas o local do apontador poderá ser alterado , caso contrário, o ponteiro apontará para um local constante e o ponteiro poderá apontar para outro local, mas o conteúdo do local do apontador não poderá ser alterado .


1
"char * const x se refere ao ponteiro de caractere que é constante, mas o local que está apontando pode ser alterado." Errado. O valor no local pode ser alterado e não o próprio local.
PleaseHelp

3

O primeiro é um erro de sintaxe. Talvez você quis dizer a diferença entre

const char * mychar

e

char * const mychar

Nesse caso, o primeiro é um ponteiro para dados que não podem ser alterados, e o segundo é um ponteiro que sempre apontará para o mesmo endereço.


3

Outra regra básica é verificar onde const está :

  1. antes de * => o valor armazenado ser constante
  2. após * => o ponteiro em si é constante

3

Muitas respostas fornecem técnicas específicas, regra geral, etc. para entender essa instância específica da declaração de variáveis. Mas existe uma técnica genérica de entender qualquer declaração:

Regra no sentido horário / espiral

A)

const char *a;

De acordo com a regra no sentido horário / espiral, aé ponteiro para o caractere constante. O que significa que o caractere é constante, mas o ponteiro pode mudar. ou seja, a = "other string";está bem, masa[2] = 'c'; falhará ao compilar

B)

char * const a;

De acordo com a regra, aé um ponteiro constante para um personagem. ou seja, você pode fazer, a[2] = 'c';mas você não pode fazera = "other string";


1
Também conhecida como regra de direita-esquerda (pelo menos é assim que eu aprendi): jdurrett.ba.ttu.edu/3345/handouts/RL-rule.html
Tomas Pruzina

(Seria muito melhor se a essência da resposta não estivesse escondida atrás de um link, com o texto aqui nem mesmo citando, ou pelo menos se referindo a qualquer uma de suas especificidades, além de um genérico "conforme a regra".)
Sz.

@Sz. Você tem alguma confusão específica aqui que eu possa esclarecer? Realmente não há muito depois de conhecer a regra.
PnotNP

1

Presumo que você queira dizer const char * e char * const.

O primeiro, const char *, é um ponteiro para um caractere constante. O ponteiro em si é mutável.

O segundo, char * const é um ponteiro constante para um personagem. O ponteiro não pode mudar, o caractere que ele aponta pode.

E depois há const char * const onde o ponteiro e o caractere não podem mudar.


Seu dois primeiros são na verdade a mesma e seu terceiro é um erro do compilador :)
workmad3

1

Aqui está uma explicação detalhada com o código

/*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 Obrigado.
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. Ponteiro constante : um ponteiro constante pode apontar apenas para uma única variável do respectivo tipo de dados durante todo o programa. Podemos alterar o valor da variável apontada pelo ponteiro. A inicialização deve ser feita durante o próprio período da declaração.

Sintaxe:

datatype *const var;

char *const vem sob este 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. Ponteiro para um valor const : neste, um ponteiro pode apontar qualquer número de variáveis ​​do tipo respectivo, mas não podemos alterar o valor do objeto apontado pelo ponteiro naquele momento específico.

Sintaxe:

const datatype *varou datatype const *var

const char* vem sob este 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. Apontando para um valor constante

const char * p; // o valor não pode ser alterado

  1. Ponteiro constante para um valor

char * const p; // endereço não pode ser alterado

  1. Ponteiro constante para um valor constante

const char * const p; // ambos não podem ser alterados.


1

O constmodificador é aplicado ao termo imediatamente à sua esquerda. A única exceção é quando não há nada à sua esquerda, então se aplica ao que está imediatamente à sua direita.

Todas essas são maneiras equivalentes de dizer "ponteiro constante para uma constante char":

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

É dependente do compilador? gcc produz para "const char const *" e "const const char *" e "char const const *" o mesmo resultado -> o ponteiro pode apontar para outro local.
precisa

1

Duas regras

  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.

por exemplo

  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

Gostaria de salientar que usar int const *(ou const int *) não é um ponteiro apontando para uma const intvariável, mas que essa variável é constpara esse ponteiro específico.

Por exemplo:

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

O código acima compila perfeitamente. _paponta para uma constvariável, embora varela mesma não seja constante.


1

Lembro-me do livro tcheco sobre C: leia a declaração de que você começa com a variável e vai para a esquerda. Então para

char * const a;

você pode ler como: " aé variável do tipo ponteiro constante para char",

char const * a;

você pode ler como: "a é um ponteiro para variável constante do tipo char. Espero que isso ajude.

Bônus:

const char * const a;

Você lerá o aponteiro constante para a variável constante do tipo char.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.