Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

1. Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 07/04/2017 - 13:39h

Como uso vetores em variáveis tipo char? E como elas vão funcionar com vetores?



  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/04/2017 - 17:25h

Palashnikova escreveu:

Como uso vetores em variáveis tipo char? E como elas vão funcionar com vetores?


Depende de o que você quer fazer.

Um dos usos possíveis é tratar cada elemento do vetor como se fosse um caráter individual, sem relação semântica com os demais elementos -- a única relação fica sendo física, uma vez que os elementos de um vetor são dispostos em posições consecutivas na memória.

Outro jeito de usar é semelhante ao anterior (i.e. elementos individuais), mas com sentido numérico, já que, em C e C++, char é um tipo de valor inteiro, normalmente de oito bits, indo de -128 at 127 se for um char com sinal (default na plataforma Intel) ou de 0 a 255 se for sem sinal.

Um terceiro uso é para armazenar strings do C. Strings do C são sequências de caracteres com valor semântico único, que fisicamente são dispostos em posições contíguas de memória *e* têm a sequência terminada com um byte nulo. É possível ter acesso a caracteres individuais dentro da string, mas normalmente se pensa no dado string como o conjunto formado por toda a sequência.

Embora os três tipos de dados acima possam ser armazenados em arrays com declarações semelhantes, esses tipos não podem ser confundidos, e cada um deles tem seus próprios cuidados, principalmente em C++.

Strings normalmente são tratadas como um bloco, em vez de cada um dos caracteres que a compõem. Nesses casos, você geralmente entrega a funções de tratamento de strings apenas o endereço do primeiro elemento, que é indicado simplesmente pelo nome do array. Você pode manipular um caráter de cada vez, mas tem de lembrar que é necessário terminar a string com um byte nulo, que tem de caber dentro do espaço reservado para o array.

Já se você estiver trabalhando com um array de um dos dois primeiros tipos, não deve cair na tentação de querer imprimir todos os seus elementos de uma só vez passando o nome do array para uma função de impressão genérica (por exemplo, fazendo algo como “std::cout << array_int8bits”), pois a função pode confundir esse array com uma string, com resultado imprevisível (pode imprimir lixo, mas pode também fazer o programa capotar).

Ainda, se você estiver tratando os elementos como inteiros de oito bits, tem de lembrar de convertê-los para inteiros antes de os imprimir, para que o sistema não confunda aquele elemento com um elemento representando um caráter. Por exemplo:

unsigned char arr_8bits[10]={0, 10, 20, 30, 40, 50, 60, 70, 80, 90};

std::cout << arr_8bits[7] << '\n'; /// Imprime “J”, não 70.
std::cout << static_cast<unsigned int>(arr_8bits[7]) << '\n'; // Agora imprime “70”.



Como você falou de C++, seria melhor você usar classes, sobretudo para representar strings. A classe std::string tem uma implementação muito melhor de strings do que o velho modelo de strings do C (inclusive com a capacidade de guardar bytes nulos como parte da string).

Você também pode criar classes para melhorar o tratamento de inteiros de 8 bits. Um exemplo de esqueleto de classe assim foi dado aqui no fórum, em https://www.vivaolinux.com.br/topico/C-C++/Inteiro-de-8-bits.

3. Re: Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Bruno Thomaz
SarusKant

(usa CentOS)

Enviado em 08/04/2017 - 09:54h

Modo de uso do char.
somente um carácter.

char a = 'a';

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.

vetor de carácteres dinâmico.

char *arr;
arr = (char*) malloc(sizeof(char)*1+1); //Alocando somente para 1 carácter.
arr[0] = 'a';
arr[1] = '\0';
arr = (char*) realloc(arr,sizeof(char)*4); //Realocando para 4 carácteres.
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);


Espero ter ajudado, boa sorte.
--
Bruno Thomaz


4. Re: Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 08/04/2017 - 12:19h

SarusKant escreveu:

Modo de uso do char.
somente um carácter.

char a = 'a';

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.

vetor de carácteres dinâmico.

char *arr;
arr = (char*) malloc(sizeof(char)*1+1); //Alocando somente para 1 carácter.
arr[0] = 'a';
arr[1] = '\0';
arr = (char*) realloc(arr,sizeof(char)*4); //Realocando para 4 carácteres.
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);


Espero ter ajudado, boa sorte.
--
Bruno Thomaz


Hm, muito bom não sabia que '\0' significava fim do vetor.




5. Re: Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 08/04/2017 - 23:44h

Palashnikova escreveu:

Hm, muito bom não sabia que '\0' significava fim do vetor.


E não significa!

O byte nulo (ou caráter '\0') indica (não “significa”) o fim de uma string, que é meramente armazenada em um vetor de caracteres (não devendo ser confundida com o vetor que a armazena). Não é o fim do vetor em si.


6. Re: Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Bruno Thomaz
SarusKant

(usa CentOS)

Enviado em 09/04/2017 - 00:09h

De modo correto seria um delimitador, em varios momentos significando o fim, do objeto, vetor, ponteiro.
--
Bruno Thomaz


7. Re: Duvidas sobre a variável do tipo char do c++ [RESOLVIDO]

Paulo
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; 







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts