paulo1205
(usa Ubuntu)
Enviado em 09/04/2017 - 00:42h
SarusKant escreveu:
vetor de carácteres com limite de 4 carácteres.
char arr[4];
arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';
arr[3] = '\0'; //Indica o fim do vetor.
Falso. O byte nulo indica apenas o fim da string.
vetor de carácteres dinâmico.
char *arr;
arr = (char*) malloc(sizeof(char)*1+1); //Alocando somente para 1 carácter.
Não. Você aloca espaço para dois caracteres (um que vai conter a letra, e outro que vai indicar o fim da string).
E o faz, aliás, com uma redundância e uma inconsistência. A redundância é que “
sizeof(char)” é sempre, por definição, igual a 1. E a inconsistência é que, se você está preocupado com “
sizeof(char)”, deveria ter feito “sizeof(char)*(1+1)”.
Outro problema é que você assume que a alocação vai sempre ter sucesso. Um programa preocupado com robustez deveria considerar a possibilidade de
malloc() falhar.
arr=malloc(2);
if(arr==NULL){
// Trata o erro de alocação. No caso, eu aborto o programa.
fprintf(stderr, "Erro de alocação de memória.\n");
exit(1);
}
Mais ainda: em C, a conversão de tipo do valor retornado por
malloc() para
char * é desnecessária e indesejável. Em C++, ela teria de ser feita, mas a forma de a fazer em C++ seria com um operador de conversão de tipo nativo do C++, pois a conversão ao estilo de C é considerada insegura (ela converte na marra mesmo algumas coisas que seriam absurdas). Veja como seria a conversão em C++.
arr=static_cast<char *>(malloc(2));
Contudo, isso também seria considerado mau uso de C++. C++ oferece o operador
new [] para alocação de memória, que é totalmente seguro quanto ao tipo de ponteiro. A forma que alguém em C++ usaria para fazer a alocação de dados seria a seguinte.
arr=new char[2];
Uma desvantagem disso, porém, seria o fato de que não existe realocação de dados alocados com
new. No entanto, existem classes que cuidam de fazer esse tipo de coisa. A mais comum delas é
std::vector. Nesse caso, você deixaria de declarar
arr como um ponteiro, e o declararia como
std::vector<char>.
std::vector arr;
/* ... */
arr.resize(2);
Se o objetivo, no entanto, for usar strings, melhor seria usar
std::string para sua variável.
arr[0] = 'a';
arr[1] = '\0';
arr = (char*) realloc(arr,sizeof(char)*4); //Realocando para 4 carácteres.
Aqui, além de repetir alguns dos erros apontados acima com o uso de
malloc(), você cometeu mais um, que infelizmente é um erro muito comum: usar o mesmo ponteiro que está sendo redimensionado como destino da atribuição do valor de retorno.
O motivo para que isso seja considerado um erro é que a realocação pode falhar. Se a realocação falhar, a função
realloc() garante a preservação da alocação e do conteúdo anterior referenciado pelo ponteiro, e sinaliza a falha através do valor de retorno da função, devolvendo um ponteiro nulo. Só que, como você usou a mesma variável ponteiro como destino da atribuição do valor retornado, se esse valor indicar uma falha de alocação, você vai sobrescrever o ponteiro com o valor de sinalização de erro, perdendo a referência original ao dado que
realloc() teve o cuidado de preservar.
A maneira correta de fazer o que você tentou fazer seria a seguinte (em C, não em C++; trato de C++ mais a diante):
char *ptr=realloc(arr, 4);
if(ptr!=NULL){
// Realocação bem sucedida: sobrescrevo ‘arr’ com novo valor de ponteiro.
arr=ptr;
// Modifico a string "a\0" para "abc\0".
strcat(arr, "bc");
}
// Se realocação tiver falhado, a string original é preservada.
// Em todo caso, neste ponto, ‘arr’ aponta para uma string válida.
Em C++, se você tiver usado
std::vector<char> ou
std::string, basta fazer o seguinte.
arr.resize(4);
arr[1] = 'b';
arr[2] = 'c';
arr[3] = '\0';
Obs. Quando se usa * se deve liberar memória ao fim do uso da variável.
free(arr);
Outra vantagem de usar
std::vector ou
std::string é não ter de se preocupar com isso.
Por outro lado, se se preferir a alocação com
new [], deve-se fazer a desalocação com
delete[].
delete[] arr;