Porque é que este simples segfault atribuição corda?
-
03-07-2019 - |
Pergunta
Eu tenho o seguinte código:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << a << ", " << b << endl;
return 0;
}
Este compila e obras, ie. impressões bar,
bar
. Agora eu gostaria de demonstrar que o que acontece aqui não é copiar uma string. Eu gostaria de mudar b
e mostrar que a
também muda. Eu vim com este código simples:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
b[1] = 'u'; // ← just this line added
cout << a << ", " << b << endl;
return 0;
}
... mas segfaults. Por quê? O interessante é que a seguinte modificação funciona muito bem:
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char b[] = "bar"; // ← declaration changed here
a = b;
b[1] = 'u';
cout << a << ", " << b << endl;
return 0;
}
Por que não ele segfault como o anterior? Eu acho que eu estou faltando alguma diferença importante entre o estilo de ponteiro e a inicialização seqüência de estilo matriz.
Solução
Você não pode mudar as constantes string, que é o que você começa quando você usa a sintaxe ponteiro-to-literal como nas primeiras amostras de código.
Veja também esta pergunta: é um literal de cadeia em c ++ criado em memória estática? .
Outras dicas
Quando você escreve o seguinte:
char *b = "bar";
o compilador aloca uma (sem nome) área de memória anônima para armazenar a string literal "bar". strings literais não podem ser modificados, para que o compilador (com a ajuda do vinculador e sistema operacional) coloca o literal de cadeia em uma parte do espaço de memória do programa em execução que é protegido contra gravação. Ao tentar modificá-lo, as capturas do sistema operacional em que ele e faz com que seu programa para falha de segmentação.
(O código é C ++, não C, mas isso é irrelevante para esta pergunta.)
Quando você escreve:
char *foo = "bar";
O que realmente acontece é que o "bar" é armazenado no segmento de somente leitura de memória. Portanto, é imutável. Você começa um segfault porque você tentar modificar um segmento somente leitura.
Você também pode mostrar que 'a' foi alterado por imprimir o valor do ponteiro.
#include <iostream>
using namespace std;
int main()
{
char* a = "foo";
char* b = "bar";
a = b;
cout << (void*)a << ", " << (void*)b << endl;
}
Isto irá imprimir o endereço que 'a' ponto e 'b' em.
Você tem que elenco para '* vazio' porque o operador << é sobrecarregado para 'char *' para imprimir a seqüência de qualquer outro ponteiro irá imprimir o endereço.
Em teoria, um literal de cadeia não deve ser capaz de ser atribuído a um char *, apenas uma 'const char *'. Em seguida, o compilador iria pará-lo antes que você escreveu SEG falha código.
Essa diferença talvez seja específico do compilador. Para demonstrar seu uso ponto de malloc para alocar o buffer, em seguida, copiar a cadeia para este buffer e não se esqueça de usar livre quando você não precisa mais do string.