Modificando constantes de string C?

Duplicar Possível:
Por que recebo uma falha de segmentação ao gravar em uma string?

Eu quero escrever uma function que inverte a string dada passada para ele. Mas eu não posso. Se eu fornecer a function doReverse (veja o código abaixo) com uma matriz de caracteres, meu código funciona bem.

Eu não consigo descobrir porque isso não funciona. Eu sou capaz de acessar str[0] no doReverse , mas não posso alterar qualquer valor da matriz usando um ponteiro de char. Alguma ideia?

 void doReverse(char *str) { str[0] = 'b'; } void main(void) { char *str = "abc"; doReverse(str); puts(str); } 

Atualizar:

Eu sei como escrever uma function inversa passando uma matriz de caracteres para ela:

 void reverse1(char p[]) { int i, temp, y; for (i = 0, y = strlen(p); i < y; ++i, --y) { temp = p[y-1]; p[y-1] = p[i]; p[i] = temp; } } 

Mas, eu quero escrever outra versão que recebe um ponteiro de char como um parâmetro.

   

A solução mais simples é alterar a declaração de str para

 char str[] = "abc"; 

Isso faz str uma matriz de char que é inicializada na string “abc”. Atualmente você tem str como um pointer-to-char inicializado para apontar para uma string descrita por um literal de string. Há uma diferença fundamental: literais de string são somente leitura para dar ao compilador flexibilidade máxima sobre onde armazená-los; é UB para modificá-los. Mas as matrizes de caracteres são mutáveis ​​e, portanto, não há problema em modificá-las.

PS. main() retorna um int .

Como você está estudando para um exame, detalharei meus comentários para explicar o que realmente está acontecendo:

 char *str = "abc"; 

str é um ponteiro armazenado na pilha. Ele é inicializado para apontar para a string literal "abc" . Essa cadeia literal será armazenada na seção de dados do executável compilado e carregada na memory quando o programa for carregado. Essa seção da memory é somente leitura, portanto, quando você tenta e modifica os dados apontados por str, você obtém uma violação de access.

 char* str = malloc(sizeof(char) * 4); strcpy(str, "abc"); 

Aqui, str é o mesmo ponteiro de pilha do primeiro exemplo. Desta vez, ele é inicializado para apontar para um bloco de 4 caracteres de memory no heap que você pode ler e gravar. A princípio, esse bloco de memory não é inicializado e pode conter qualquer coisa. strcpy lê o bloco de memory somente leitura onde “abc” é armazenado e o copia no bloco de memory de leitura / gravação para o qual str str aponta. Note que set str[3] = '\0' é redundante, já que o strcpy já faz isso.

Como um aparte, se você estiver trabalhando no visual studio, use strcpy_s para certificar-se de não sobrescrever seu buffer se a string que está sendo copiada for maior do que o esperado.

 char str[] = "abc"; 

Aqui str é agora uma matriz alocada na pilha. O compilador irá dimensioná-lo exatamente na string literal usada para inicializá-lo (incluindo o terminador NULL). A memory da pilha é de leitura / gravação, para que você possa modificar os valores da matriz como quiser.

 char str[4] = "abc"; 

Isto é efetivamente o mesmo que a versão anterior, apenas você está dizendo ao compilador que você sabe melhor do que quanto tempo a matriz deve ser. Você pode ter problemas se alterar a string e não o tamanho da matriz.

Porque esta é a lição de casa eu vou dar conselhos, mas não vou postar uma solução completa.

Eu estou supondo que você está recebendo uma violação de access em str [0] = ‘b’? Isso ocorre porque “abc” é um literal de string.

Copie os pontos str da string antes de chamar reverse ou obtenha reverse para alocar um buffer e coloque a string invertida nela.

Tenha em mente que você terá que desalocar toda a memory que você alocar.

Senhor, senhor. Para todos aqueles que sugerem formas de realmente realizar a troca, por favor, leia a questão com atenção; Não há nada pior do que ter que reiterar uma pergunta já perfeitamente articulada. Independentemente do método usado para implementar a troca (temp-swap, xor3-swap, etc), essa pessoa parece estar muito familiarizada com os intrínsecos fundamentais e elementares da function.

No entanto, como já explicado, o compilador / vinculador coloca genericamente todos os literais de string dentro do ‘segmento de dados const’ do executável de destino, que é subseqüentemente associado a um descritor não gravável de MMU durante a chamada apropriada ‘load / exec’. Todos os ciclos de gravação da CPU emitidos posteriormente por meio desse descritor são automaticamente interceptados pelo mecanismo de exceção da MMU, resultando no ‘segfault’ obrigatório ou equivalente específico da plataforma. Escusado será dizer, é claro, plataformas antigas não-MMU não exibiriam tal comportamento.

Embora isso efetivamente adquira suporte em tempo de execução para o idioma ‘constante / literal’ da linguagem de origem, várias plataformas historicamente facilitaram substituições explícitas de segmentos em tempo de compilation. No entanto, este nível de suporte diminuiu lentamente em favor de uma camada de abstração mais rígida / robusta, tornando assim muitas otimizações óbvias e muitas vezes úteis insustentáveis. À medida que o tempo e o atrito geram sua filosofia “MC / ASM”, que está constantemente envelhecendo, diante de uma geração “Microsoft” ansiosa demais, os programadores não são mais considerados conhecedores ou responsáveis ​​o suficiente para tomar esse tipo de decisão. Em vez das muitas implementações inventadas, para não dizer criativas, que testemunhei como líder de projeto, isso não é de forma alguma uma coisa ruim.

Embora este post esteja rapidamente se transformando em uma violação fora do tópico, sinto-me um tanto justificado pelo stream constante de questões relacionadas de cima para baixo que estão lentamente se tornando endêmicas dentro de nossa indústria. Como um iniciante programador C – uma linguagem originalmente projetada para complementar o desenvolvimento de baixo nível – meu conselho é adotar uma abordagem bottom-up e aumentar seus estudos com um pouco de desenvolvimento extra-curricular da linguagem assembly. Como a implementação algorítmica provavelmente constitui seu foco principal como engenheiro de aplicações, é importante lembrar que o design contemporâneo de CPU experimentou uma evolução homogênea nos últimos 30 anos; Os processadores Intel ultra-rápidos da atualidade não são mais do que refinamentos CMOS superescalares dos processadores bipolares de 4/8 bits que eu estava programando quando a Terra ainda era jovem.

Ao contrário da crença popular, a programação em linguagem assembly é relativamente fácil de aprender e absolutamente essencial quando se tenta reconciliar construções de alto nível com comportamento problemático ou esotérico. Uma vez que você considere as intermináveis ​​horas de experimentação, debugging, busca na web e spam em fóruns, não há dúvida de que uma abordagem de baixo para cima é certamente o caminho de menor resistência.

Boa sorte com seus estudos.

Até onde sei, strings constantes são implementadas como arrays de caracteres constantes (ou, em termos C, const char [length] ). Portanto, você não pode modificar seus caracteres.

Tente alocar dinamicamente a string.

 char* str = (char*)malloc(sizeof(char) * 4); strcpy(str, "abc"); str[3] = '\0'; 

Claro, não se esqueça de liberar a memory no final do seu programa.


Edit: Eu não vou postar nada relacionado a reverter a string, porque esse é o seu trabalho.