Estou examinando alguns programas de exemplo para me familiarizar novamente com C ++ e me deparei com a seguinte pergunta. Primeiro, aqui está o código de exemplo:
void print_string(const char * the_string)
{
cout << the_string << endl;
}
int main () {
print_string("What's up?");
}
No código acima, o parâmetro para print_string poderia ter sido const char * const the_string
. Qual seria mais correto para isso?
Eu entendo que a diferença é que um é um ponteiro para um caractere constante, enquanto o outro é um ponteiro constante para um caractere constante. Mas por que ambos funcionam? Quando isso seria relevante?
const char *
é muito melhor porqueconst
está no lado oposto completo.Ponteiro mutável para um caractere mutável
Ponteiro mutável para um caractere constante
Ponteiro constante para um personagem mutável
Ponteiro constante para um caractere constante
fonte
const char* p; --> constant pointer to mutable character
echar *const p; --> mutable pointer to constant character
const char * p
como: "p é um ponteiro para uma constante de caractere" ou um ponteiro mutável para um caractere constante, como James afirma corretamente. mesmo com o segundo :).const char * const
significa que o ponteiro, assim como os dados para os quais o ponteiro apontou, são ambos const!const char *
significa que apenas os dados para os quais o ponteiro apontou são const. o ponteiro em si, entretanto, não é const.Exemplo.
fonte
(Eu sei que isso é antigo, mas queria compartilhar assim mesmo.)
Só queria elaborar a resposta de Thomas Matthews. A regra direita-esquerda de declarações de tipo C diz basicamente: ao ler uma declaração de tipo C, comece no identificador e vá para a direita quando puder e para a esquerda quando não puder.
Isso é melhor explicado com alguns exemplos:
Exemplo 1
Comece no identificador, não podemos ir para a direita, então vamos para a esquerda
foo é uma constante ...
Continue para a esquerda
foo é um ponteiro constante para ...
Continue para a esquerda
foo é um ponteiro constante para char ...
Continue para a esquerda
foo é um ponteiro constante para a constante char (Completo!)
Exemplo 2
Comece no identificador, não podemos ir para a direita, então vamos para a esquerda
foo é uma constante ...
Continue para a esquerda
foo é um ponteiro constante para ...
Continue para a esquerda
foo é um ponteiro constante para char (Completo!)
Exemplo 1337
Comece pelo identificador, mas agora podemos dar certo!
foo é um array de 8 ...
Aperte parênteses para não poder mais ir para a direita, vá para a esquerda
foo é uma matriz de 8 ponteiros para ...
Terminado entre parênteses, agora pode ir para a direita
foo é uma matriz de 8 ponteiros para função que retorna ...
Nada mais à direita, vá para a esquerda
foo é uma matriz de 8 ponteiros para função que retorna um ponteiro para ...
Continue para a esquerda
foo é uma matriz de 8 ponteiros para funções que retorna um ponteiro para uma constante ...
Continue para a esquerda
foo é uma matriz de 8 ponteiros para funções que retorna um ponteiro para um ponteiro constante para um ...
Continue para a esquerda
foo é uma matriz de 8 ponteiros para funções que retorna um ponteiro para um ponteiro constante para um char ...
Continue para a esquerda
foo é um array de 8 ponteiros para funções que retorna um ponteiro para um ponteiro constante para uma constante char (Completo!)
Explicação adicional: http://www.unixwiz.net/techtips/reading-cdecl.html
fonte
Muitas pessoas sugerem a leitura do especificador de tipo da direita para a esquerda.
Em ambos os formulários, o ponteiro está apontando para dados constantes ou somente leitura.
Na segunda forma, o ponteiro não pode ser alterado; o ponteiro sempre apontará para o mesmo lugar.
fonte
A diferença é que sem o extra
const
o programador poderia mudar, dentro do método, para onde o ponteiro aponta; por exemplo:Isso seria ilegal se a assinatura fosse
void print_string(const char * const the_string)
Muitos programadores consideram muito prolixo (na maioria dos cenários) a
const
palavra-chave extra e a omitem, mesmo que seja semanticamente correta.fonte
Neste último você está garantindo que não vai modificar o ponteiro e o caractere no primeiro você só garante que o conteúdo não irá mudar mas você pode mover o ponteiro
fonte
Não há razão para que nenhum deles funcione. Tudo o que
print_string()
faz é imprimir o valor. Não tenta modificá-lo.É uma boa ideia criar uma função que não modifique os argumentos da marca como const. A vantagem é que as variáveis que não podem ser alteradas (ou que você não deseja) podem ser passadas para essas funções sem erros.
No que diz respeito à sintaxe exata, você deseja indicar quais tipos de argumentos são "seguros" para serem transmitidos à função.
fonte
Acho que variam raramente são relevantes, porque sua função não está sendo chamada com argumentos como & * the_string ou ** the_string. O ponteiro em si é um argumento de tipo de valor, portanto, mesmo se você modificá-lo, não mudará a cópia que foi usada para chamar sua função. A versão que você está mostrando garante que a string não mudará, e acho que isso é suficiente neste caso.
fonte
const char *
significa que você não pode usar o ponteiro para alterar o que é apontado. Você pode alterar o ponteiro para apontar para outra coisa, no entanto.Considerar:
O parâmetro é um ponteiro não const para const char, portanto, pode ser alterado para outro
const char *
valor (como uma string constante). Se, no entanto, escrevermos por engano*text = '\0'
, obteremos um erro de compilação.Indiscutivelmente, se você não pretende alterar o que o parâmetro está apontando, você poderia fazer o parâmetro
const char * const text
, mas não é comum fazer isso. Normalmente permitimos que as funções alterem os valores passados para os parâmetros (como passamos parâmetros por valor, qualquer mudança não afeta o chamador).BTW: é uma boa prática evitar
char const *
porque muitas vezes é mal interpretado - significa o mesmo queconst char *
, mas muitas pessoas lêem como significadochar * const
.fonte
const char *
e a assinaturachar const *
- a maneira como você redigiu seu BTW realmente ajudou!Quase todas as outras respostas estão corretas, mas elas perdem um aspecto disso: quando você usa o extra
const
em um parâmetro em uma declaração de função, o compilador irá essencialmente ignorá-lo. Por um momento, vamos ignorar a complexidade do seu exemplo ser um ponteiro e apenas usar umint
.declara a mesma função que
Apenas na definição da função o extra é
const
significativo:Esta definição é compatível com qualquer uma das declarações acima. O chamador não se importa que
x
éconst
--que é um detalhe de implementação não é relevante no site da chamada.Se você tiver um
const
ponteiro paraconst
dados, as mesmas regras se aplicam:Poucos programadores C ++ se preocupam em criar parâmetros
const
, mesmo quando poderiam ser, independentemente de esses parâmetros serem ponteiros.fonte
const
ao parâmetro de função na definição, mas não na declaração.A diferença entre os dois é que char * pode apontar para qualquer ponteiro arbitrário. Const char * por contraste, aponta para constantes definidas na seção DATA do executável. E, como tal, você não pode modificar os valores dos caracteres de uma string const char *.
fonte
const char*
pode apontar para qualquer lugar que desejar.