Por que esse código para modificar uma string não funcionar?
-
09-09-2019 - |
Pergunta
Com cordas c-estilo, como você atribuir um char para um endereço de memória que o ponteiro aponta personagem? Por exemplo, no exemplo abaixo, eu quero mudar num para "123456", então eu tentei conjunto p para o dígito onde '0' está localizado e tento substituí-lo com '4'. Obrigado.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* num = (char*)malloc(100);
char* p = num;
num = "123056";
p = p+3; //set pointer to where '4' should be
p = '4';
printf("%s\n", num );
return 0;
}
Solução
Esse código não vai funcionar, simplesmente porque a linha:
num = "123056";
muda num
a ponto de distância da memória alocada (e restos p
apontando para o que a memória para que eles não o mesmo local está) à memória o que é mais provável somente leitura. Você não tem permissão para alterar a memória pertencente ao strings literais, é um comportamento indefinido.
Você precisa do seguinte:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *num = malloc (100); // do not cast malloc return value.
char *p = num;
strcpy (num, "123056"); // populate existing block with string.
p = p + 3; // set pointer to where '0' is.
*p = '4'; // and change it to '4'.
printf ("%s\n", num ); // output it.
return 0;
}
Outras dicas
Em primeiro lugar, quando você faz:
num = "123056";
Você não está copiando a string "123056" para a área de pilha alocada por malloc()
. Em C, a atribuição de um ponteiro char *
um valor literal de cadeia é equivalente a defini-lo como uma constante - isto é, idêntico ao:
char str[] = "123056";
Então, o que você acabou realizado lá é que você abandonou a sua única referência para a área de pilha a 100 bytes alocados por malloc()
, razão pela qual o seu código posterior não imprime o valor correto; 'p
' ainda aponta para a área de pilha alocada por malloc()
(desde num
apontou para ele no momento da atribuição), mas num
não faz mais.
Eu suponho que você realmente pretende fazer era cópia a string "123056" para essa área heap. Veja como fazer isso:
strcpy(num, "123056");
Embora, isso é melhor prática para uma variedade de razões:
strncpy(num, "123056", 100 - 1); /* leave room for \0 (null) terminator */
Se você tinha acabado de fazer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *num = malloc(100);
char *p = num;
strncpy(num, "123056", 100 - 1);
p = p + 3;
*p = '4';
printf("%s\n", num);
return 0;
}
Você teria conseguido o resultado correto:
123456
Você pode contrair esta operação:
p = p + 3;
*p = '4';
... e evitar a iteração do ponteiro, por deferencing da seguinte forma:
*(p + 3) = '4';
Algumas outras notas:
-
Embora a prática estilística comum, lançando o valor de retorno de
malloc()
para(char *)
é desnecessário. Conversão e alinhamento do tipovoid *
é garantida pela linguagem C. -
Sempre verifique o valor de retorno de
malloc()
. Será NULL se a alocação de pilha falhou (ou seja, você está fora de memória), e nesse ponto seu programa deve sair. -
Dependendo da implementação, a área de memória alocada por
malloc()
pode conter lixo obsoleto em determinadas situações. É sempre uma boa idéia para zero-lo após a alocação:memset(num, 0, 100);
-
Nunca se esqueça de
free()
sua pilha! Neste caso, o programa vai sair e o sistema operacional irá limpar o seu lixo, mas se você não adquirir o hábito, você terá vazamentos de memória em nenhum momento.
Então, aqui está a "melhor prática" versão:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *num, *p;
/*
* Don't take 1-byte chars for granted - good habit to get into.
*/
num = malloc(sizeof(char) * 100);
if(num == NULL)
exit(1);
memset(num, 0, sizeof(char) * 100);
p = num;
strncpy(num, "123056", 100 - 1);
*(p + 3) = '4';
printf("%s\n", num);
free(num);
return 0;
}
Além dos p emitir outros * apontaram, você também tem problemas de uso de memória. Você tem um buffer de 100 bytes, com conteúdo desconhecido. Tem um outro tampão de bytes 7, contendo a sequência "123056" e um terminador nulo. Você está fazendo isso:
- num é definido como ponto para o buffer de bytes 100
- p é definido para apontar para num; ou seja, que aponta para o 100 byte buffer
- repuser num para apontar para o buffer de 7 byte; p ainda está a apontar para o tampão de byte 100
- Você usar p para modificar o buffer de 100 bytes
- então você usa num imprimir o tampão 7 byte
Então você não está imprimindo o mesmo tampão que você está modificando.
Bem, você sabe p é tipo de ponteiro. Ele armazena o endereço do char '0'. Se você atribuir p o valor de '4'. Levará '4' como o endereço. No entanto, o endereço de '4' é ilegal. Você pode usar '*' operador para obter o valor do endereço que está armazenado em p armazenado.
Apenas uso *p = '4';
...!