o que você quer dizer com " constante literal string" em C (não C ++)
gbulmer
1
... char * nome pode ser feita para apontar para um literal string constante
Iceman
a constante em "literal de cadeia constante" é redundante, pois todos os literais de cadeia são, em teoria, entidades constantes. É o conteúdo da variável que pode ser constante ou mutável. A declaração "const" simplesmente irá lançar um erro de tempo de compilação se você tentar alterar o conteúdo do caráter apontada pelo "nome"
Cupcake
Simples: o nome "char * name" é um ponteiro para char, ou seja, ambos podem ser alterados aqui. O nome "const char * name" é um ponteiro para const char, ou seja, o ponteiro pode mudar, mas não char.
AKD
Leia estas coisas da direita para a esquerda.
Jiapeng Zhang
Respostas:
406
char*é um ponteiro mutável para um caractere / sequência mutável .
const char*é um ponteiro mutável para um caractere / sequência imutável . Você não pode alterar o conteúdo dos locais para os quais este ponteiro aponta. Além disso, os compiladores são obrigados a fornecer mensagens de erro quando você tenta fazer isso. Pelo mesmo motivo, a conversão de const char *para char*foi preterida.
char* consté um ponteiro imutável (não pode apontar para nenhum outro local), mas o conteúdo do local no qual aponta é mutável .
const char* consté um ponteiro imutável para um caractere / sequência imutável .
A confusão pode ser esclarecida com o uso de uma variável após as declarações mencionadas acima e dando referência a essa variável.
Ank.karwasra
3
@ ankit.karwasra, você perdeu mais um:char const *
Pacerier
Suponho que duas opções com caracteres / cadeias de caracteres mutáveis sejam altamente perigosas, pois você pode criar uma memória de falha de segmentação e, se você for realmente inteligente, poderá invadir o computador. É por isso que os compiladores sempre mostravam avisos nessas implementações, eu acho
Daniel N.
1
A mutação não causará char *falha de segmentação durante a execução?
Divyanshu Maithani
1
Então eu uso constse eu quero que o compilador dê erro se eu esqueci e alterei os dados por engano, certo?
precisa saber é o seguinte
43
char*name
Você pode alterar o caractere em que namepontos, e também o caractere em que aponta.
constchar* name
Você pode alterar o caractere em que namepontos, mas não pode modificar o caractere em que aponta. correção: você pode alterar o ponteiro, mas não o caracter para o qual nameaponta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , consulte "Exemplos" ) Nesse caso, o constespecificador se aplica ao char, não ao asterisco.
De acordo com a página do MSDN e http://en.cppreference.com/w/cpp/language/declarations , o constantes do *faz parte da sequência decl-specifier, enquanto o constdepois *faz parte do declarador.
Uma sequência do especificador de declaração pode ser seguida por vários declaradores, razão pela qual const char * c1, c2declara c1comoconst char * e c2como const char.
EDITAR:
A partir dos comentários, sua pergunta parece estar se perguntando sobre a diferença entre as duas declarações quando o ponteiro aponta para uma string literal.
Nesse caso, você não deve modificar o caractere em que namepontos, pois isso pode resultar em comportamento indefinido . Literais de seqüência de caracteres podem ser alocados em regiões de memória somente leitura (implementação definida) e um programa do usuário não deve modificá-lo de qualquer maneira. Qualquer tentativa de fazer isso resulta em comportamento indefinido.
Portanto, a única diferença nesse caso (de uso com literais de seqüência de caracteres) é que a segunda declaração oferece uma pequena vantagem. Os compiladores geralmente emitem um aviso caso você tente modificar a string literal no segundo caso.
#include<string.h>int main(){char*str1 ="string Literal";constchar*str2 ="string Literal";char source[]="Sample string";
strcpy(str1,source);//No warning or error, just Undefined Behavior
strcpy(str2,source);//Compiler issues a warningreturn0;}
Resultado:
cc1: avisos sendo tratados como erros
prog.c: Na função 'main':
prog.c: 9: error: passar o argumento 1 de 'strcpy' descarta qualificadores do tipo de destino do ponteiro
Observe que o compilador avisa para o segundo caso, mas não para o primeiro.
Obrigado .. eu estava misturando com a constante string literal, que é definida como: char * name = "String Literal"; Mudando "String Literal" é indefinido ..
Iceman
@ user1279782: Err, espera! Você está falando de pontos apontando para literais de string aqui? Nesse caso, você não deve modificar o caracter para o qual os namepontos em ambos os casos. Isso pode resultar em UB.
Alok Salvar
Sim, esse era o ponto. Então, nesse caso, char * name e const char * name se comportam de maneira semelhante, certo?
Iceman
4
Essa resposta é extremamente ambígua ou simplesmente errada. Eu interpretaria "Você não pode alterar o caracter para o qual o nome aponta, mas Você pode modificar o caracter para o qual ele aponta". Como não sendo capaz de modificar o ponteiro em si, mas ser capaz de modificar o local da memória que ele aponta, o que é incorreto: ideone.com/6lUY9s alternativamente por puro C: ideone.com/x3PcTP
shroudednight
1
@shroudednight: Você precisa aprender um pouco mais sobre comportamentos indefinidos e precisa distinguir entre: permitido e não deve ser feito. :)
Alok Salvar
16
char mystring[101]="My sample string";constchar* constcharp = mystring;// (1)charconst* charconstp = mystring;// (2) the same as (1)char*const charpconst = mystring;// (3)
constcharp++;// ok
charconstp++;// ok
charpconst++;// compile error
constcharp[3]='\0';// compile error
charconstp[3]='\0';// compile error
charpconst[3]='\0';// ok// String literalschar* lcharp ="My string literal";constchar* lconstcharp ="My string literal";
lcharp[0]='X';// Segmentation fault (crash) during run-time
lconstcharp[0]='X';// compile error// *not* a string literalconstchar astr[101]="My mutable string";
astr[0]='X';// compile error((char*)astr)[0]='X';// ok
Nenhum de seus ponteiros aponta para "literais de cadeia constante", conforme a pergunta.
caf
É importante notar que a mudança do char *valor dá falha de segmentação, uma vez que está tentando modificar um literal string (que está presente em memória apenas para leitura)
Divyanshu Maithani
10
Em nenhum dos casos, você pode modificar um literal de cadeia de caracteres, independentemente de o ponteiro para esse literal de cadeia ser declarado como char *ouconst char * .
No entanto, a diferença é que, se o ponteiro estiver const char *, o compilador deverá fornecer um diagnóstico se você tentar modificar o valor apontado, mas se o ponteiro estiver char *, não o fará.
"Em nenhum dos casos você pode modificar uma literal de string, independentemente de ... [ela] ser declarada como char * ou const char *" Concordo que o programador não deve tentar, mas você está dizendo que todo compilador C, em todos os plataforma rejeitará o código, providenciará a falha do código no tempo de execução ou algo mais? Eu acredito que um arquivo pode ter a definição e inicialização, e outro arquivo pode conter extern ... namee ter *name = 'X';. No 'sistema operacional adequado', isso pode falhar, mas em sistemas embarcados, espero que faça algo específico da plataforma / compilador.
gbulmer
@ bulbulmer: Você não pode modificar uma string literal em um programa C correto. O que um programa C incorreto que tenta pode resultar não está aqui nem ali.
caf
@ bulbulmer: Uma definição útil é um programa que não quebra nenhuma restrição especificada pelo padrão da linguagem C. Em outras palavras, um programa que modifica um literal de cadeia de caracteres está incorreto da mesma maneira que aquele que desreferencia um ponteiro nulo ou executa uma divisão por 0 está incorreto.
caf
caf - Eu pensei que poderia ser o que você quis dizer. Então "Em nenhum dos casos você pode modificar uma string literal" parece exagerar. Seria preciso dizer "Em ambos os casos, as restrições especificadas pelo padrão da linguagem C foram quebradas, independentemente ... Não é possível para o compilador ou o sistema de tempo de execução identificar violações do padrão em todos os casos". Suponho que o padrão assume a posição de que o efeito é indefinido?
gbulmer
1
Quando um padrão não pode afirmar nada de qualquer maneira, acho que definir comportamento como "indefinido" parece ser exatamente o limite certo e útil. Afirmar a relação que um 'programa C correto' ' não pode desreferenciar um ponteiro nulo' soa equivalente a provar o problema de parada. Mas eu não me importo. Eu não faria isso e esperar para fugir com ele 'livre scott' :-)
gbulmer
4
CASO 1:
char*str ="Hello";
str[0]='M'//Warning may be issued by compiler, and will cause segmentation fault upon running the programme
O conjunto acima define str para apontar para o valor literal "Hello" que é codificado na imagem binária do programa, que é sinalizada como somente leitura na memória, significa que qualquer alteração nesse literal String é ilegal e causaria falhas de segmentação.
CASO 2:
constchar*str ="Hello";
str[0]='M'//Compile time error
CASO 3:
char str[]="Hello";
str[0]='M';// legal and change the str = "Mello".
O primeiro você pode realmente mudar, se quiser, o segundo, não. Leia sobre constcorreção (há alguns guias legais sobre a diferença). Também há char const * nameonde você não pode refazê-lo.
Não há muita diferença entre os 2 e ambos podem ser vistos como corretos. Devido ao longo legado do código C, os literais de string tiveram um tipo de char[], não const char[], e há muitos códigos mais antigos que da mesma forma aceitam, em char *vez deconst char * , mesmo quando não modificam os argumentos.
A principal diferença dos 2 em geral é que *cnameou cname[n]será avaliada em valores do tipo const char, enquanto *nameou name[n]será avaliada em valores do tipo char, que são valores modificáveis . Um compilador em conformidade é necessário para produzir uma mensagem de diagnóstico se o destino da atribuição não for um valor lificável modificável ; ele não precisa produzir nenhum aviso na atribuição para lvalues do tipo char:
name[0]='x';// no diagnostics *needed*
cname[0]='x';// a conforming compiler *must* produce a diagnostics message
O compilador não é necessário para interromper a compilação nos dois casos; basta produzir um aviso para a atribuição cname[0]. O programa resultante não é um programa correto . O comportamento da construção é indefinido . Pode travar ou, pior ainda, pode não travar e pode alterar a string literal na memória.
Respostas:
char*
é um ponteiro mutável para um caractere / sequência mutável .const char*
é um ponteiro mutável para um caractere / sequência imutável . Você não pode alterar o conteúdo dos locais para os quais este ponteiro aponta. Além disso, os compiladores são obrigados a fornecer mensagens de erro quando você tenta fazer isso. Pelo mesmo motivo, a conversão deconst char *
parachar*
foi preterida.char* const
é um ponteiro imutável (não pode apontar para nenhum outro local), mas o conteúdo do local no qual aponta é mutável .const char* const
é um ponteiro imutável para um caractere / sequência imutável .fonte
char const *
char *
falha de segmentação durante a execução?const
se eu quero que o compilador dê erro se eu esqueci e alterei os dados por engano, certo?Você pode alterar o caractere em que
name
pontos, e também o caractere em que aponta.Você pode alterar o caractere em quename
pontos, mas não pode modificar o caractere em que aponta.correção: você pode alterar o ponteiro, mas não o caracter para o qual
name
aponta ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , consulte "Exemplos" ) Nesse caso, oconst
especificador se aplica aochar
, não ao asterisco.De acordo com a página do MSDN e http://en.cppreference.com/w/cpp/language/declarations , o
const
antes do*
faz parte da sequência decl-specifier, enquanto oconst
depois*
faz parte do declarador.Uma sequência do especificador de declaração pode ser seguida por vários declaradores, razão pela qual
const char * c1, c2
declarac1
comoconst char *
ec2
comoconst char
.EDITAR:
A partir dos comentários, sua pergunta parece estar se perguntando sobre a diferença entre as duas declarações quando o ponteiro aponta para uma string literal.
Nesse caso, você não deve modificar o caractere em que
name
pontos, pois isso pode resultar em comportamento indefinido . Literais de seqüência de caracteres podem ser alocados em regiões de memória somente leitura (implementação definida) e um programa do usuário não deve modificá-lo de qualquer maneira. Qualquer tentativa de fazer isso resulta em comportamento indefinido.Portanto, a única diferença nesse caso (de uso com literais de seqüência de caracteres) é que a segunda declaração oferece uma pequena vantagem. Os compiladores geralmente emitem um aviso caso você tente modificar a string literal no segundo caso.
Exemplo de amostra online:
Resultado:
Observe que o compilador avisa para o segundo caso, mas não para o primeiro.
fonte
name
pontos em ambos os casos. Isso pode resultar em UB.fonte
char *
valor dá falha de segmentação, uma vez que está tentando modificar um literal string (que está presente em memória apenas para leitura)Em nenhum dos casos, você pode modificar um literal de cadeia de caracteres, independentemente de o ponteiro para esse literal de cadeia ser declarado como
char *
ouconst char *
.No entanto, a diferença é que, se o ponteiro estiver
const char *
, o compilador deverá fornecer um diagnóstico se você tentar modificar o valor apontado, mas se o ponteiro estiverchar *
, não o fará.fonte
extern ... name
e ter*name = 'X';
. No 'sistema operacional adequado', isso pode falhar, mas em sistemas embarcados, espero que faça algo específico da plataforma / compilador.CASO 1:
O conjunto acima define str para apontar para o valor literal "Hello" que é codificado na imagem binária do programa, que é sinalizada como somente leitura na memória, significa que qualquer alteração nesse literal String é ilegal e causaria falhas de segmentação.
CASO 2:
CASO 3:
fonte
O primeiro você pode realmente mudar, se quiser, o segundo, não. Leia sobre
const
correção (há alguns guias legais sobre a diferença). Também háchar const * name
onde você não pode refazê-lo.fonte
A questão é qual é a diferença entre
que aponta para uma constante string literal e
Ou seja, dado
e
Não há muita diferença entre os 2 e ambos podem ser vistos como corretos. Devido ao longo legado do código C, os literais de string tiveram um tipo de
char[]
, nãoconst char[]
, e há muitos códigos mais antigos que da mesma forma aceitam, emchar *
vez deconst char *
, mesmo quando não modificam os argumentos.A principal diferença dos 2 em geral é que
*cname
oucname[n]
será avaliada em valores do tipoconst char
, enquanto*name
ouname[n]
será avaliada em valores do tipochar
, que são valores modificáveis . Um compilador em conformidade é necessário para produzir uma mensagem de diagnóstico se o destino da atribuição não for um valor lificável modificável ; ele não precisa produzir nenhum aviso na atribuição para lvalues do tipochar
:O compilador não é necessário para interromper a compilação nos dois casos; basta produzir um aviso para a atribuição
cname[0]
. O programa resultante não é um programa correto . O comportamento da construção é indefinido . Pode travar ou, pior ainda, pode não travar e pode alterar a string literal na memória.fonte
Na realidade,
char* name
não é um ponteiro para uma constante, mas um ponteiro para uma variável. Você pode estar falando sobre essa outra questão.Qual é a diferença entre char * const e const char *?
fonte