Prévia do material em texto
AULA 13 CADEIAS DE CARACTERES Veremos nesta aula uma estrutura que possui tratamento especial na linguagem C: a ca- deia de caracteres. Esta estrutura é similar a um vetor de caracteres, que vimos na aula 12, diferenciando-se apenas por conter um caractere especial no final, após o último caractere vá- lido. Essa característica evita, em muitos casos, que tenhamos de manter uma variável que contenha o comprimento do vetor para saber o número de caracteres contidos nele. Outras características e diferenças importantes serão vistas nesta aula. Diversas funções que manipulam cadeias de caracteres estão disponíveis na biblioteca string da linguagem C. Mencionaremos algumas delas nesta aula e as restantes e os detalhes serão vistos na aula ??. Esta aula é inspirada nas referências [6, 10]. 13.1 Literais Vimos tomando contato com cadeias de caracteres desde quando escrevemos nosso pri- meiro programa na linguagem C. Por exemplo, na sentença abaixo: printf("Programar é bacana!\n"); o único argumento passado para a função printf é a cadeia de caracteres (de formatação) "Programar é bacana!\n" . As aspas duplas são usadas para delimitar uma constante do tipo cadeia de caracteres, que pode conter qualquer combinação de letras, números ou caracte- res especiais que não sejam as aspas duplas. Mesmo assim, é possível inserir as aspas duplas no interior de uma constante cadeia de caracteres, inserindo a sequência \" nessa cadeia. Na linguagem C, uma constante do tipo cadeia de caractere é chamada de literal. Quando estudamos o tipo de dados char , aprendemos que uma variável deste tipo pode conter apenas um único caractere. Para atribuir um caractere a uma variável, o caractere deve ser envolvido por aspas simples. Dessa forma, o trecho de código a seguir: char sinal; sinal = ’+’; 138 13 CADEIAS DE CARACTERES 139 tem o efeito de atribuir o caractere cuja constante é ’+’ para a variável sinal , previamente declarada como um caractere com sinal. Além disso, aprendemos que existe uma distinção entre as aspas simples e as aspas duplas, sendo que no primeiro caso elas servem para definir constantes do tipo caractere e no segundo para definir constantes do tipo cadeia de caracteres. Dessa forma, o seguinte trecho de código: char sinal; sinal = "+"; não está correto, já que que a variável sinal foi declarada do tipo char , podendo conter um único caractere. Observe que a constante exige exatos dois compotamentos para armaze- namento: o caractere cuja constante é ’+’ mais o caractere cuja constante é ’\0’ . Dessa forma, é impossível armazenar esses dois caracteres em um único compartimento de memória. Lembre-se finalmente que na linguagem C as aspas simples e as aspas duplas são usadas para definir dois tipos de constantes diferentes. Usamos literais especialmente quando chamamos as funções printf e scanf em um programa, ou seja, quando descrevemos cadeias de caracteres de formatação. Essencialmente, a linguagem C trata as literais como cadeias de caracteres. Quando o compilador da linguagem C encontra uma literal com n caracteres em um programa, ele reserva n+1 compartimentos de memória para armazenar a cadeia de caracteres correspondente. Essa área na memória conterá os caracteres da cadeia mais um caractere extra – o caractere nulo – que é um registro do final da cadeia. O caractere nulo é um byte cujos bits são todos 0 (zeros) e é representado pela sequência ’\0’ . É importante destacar a diferença entre o caractere nulo e o caractere zero: o primeiro é um caractere não-imprimível, tem valor decimal 0 e constante ’\0’ ; o segundo é um caractere imprimível, tem valor 48, símbolo gráfico 0 e constante ’0’ . Ou seja, esses caracteres são muito diferentes! A literal "abc" é armazenada como um vetor de quatro caracteres na memória, como mostra a figura 13.1. a b c \0 Figura 13.1: Armazenamento de uma literal na memória. Por outro lado, uma literal também pode ser vazia. A literal "" é uma literal vazia, repre- sentada na memória como na figura 13.2. \0 Figura 13.2: Literal vazia na memória. FACOM UFMS 13 CADEIAS DE CARACTERES 140 13.2 Vetores de caracteres Se queremos trabalhar com variáveis que comportam mais que um único caractere, não nos sobram alternativas a não ser trabalhar com vetores de caracteres. Recorde que no exer- cício 13.6, precisamos definir dois vetores palavra e frase do tipo caractere, da seguinte forma: char palavra[MAX+1], frase[MAX+1]; Para solicitar que o usuário informe, por exemplo, o conteúdo da variável palavra , produzi- mos o seguinte trecho de programa: printf("Informe a palavra: "); i = 0; do { scanf("%c", &palavra[i]); i++; } while (palavra[i-1] != ’\n’); m = i-1; Para imprimir o conteúdo dessa mesma variável palavra , devemos escrever um trecho de programa da seguinte forma: printf("Palavra: "); for (i = 0; i < m; i++) printf("%c", palavra[i]); printf("\n"); Note que sempre necessitamos de uma variável adicional para controlar o comprimento de um vetor de caracteres quando da sua leitura. A variável m faz esse papel no primeiro trecho de programa acima. Além disso, tanto para leitura como para escrita de um vetor de caracteres, precisamos de uma estrutura de repetição para processar os caracteres um a um. Com as cadeias de caracteres, evitamos esta sobrecarga de trabalho para o programador, como veremos daqui por diante. 13.3 Cadeias de caracteres Algumas linguagens de programação de alto nível oferecem ao(à) programador(a) um tipo de dados especial para que variáveis do tipo cadeia de caracteres possam ser declaradas. Por outro lado, na linguagem C não há um tipo de dados como esse e, assim, qualquer vetor de FACOM UFMS 13 CADEIAS DE CARACTERES 141 caracteres pode ser usado para armazenar uma cadeia de caracteres. A diferença, nesse caso, é que uma cadeia de caracteres é sempre terminada por um caractere nulo. Uma vantagem dessa estratégia é que não há necessidade de se manter o comprimento da cadeia de caracteres asso- ciado a ela. Por outro lado, esse mesmo comprimento, se necessário, só pode ser encontrado através de uma varredura no vetor. Suponha que necessitamos de uma variável capaz de armazenar uma cadeia de caracteres de até 50 caracteres. Como a cadeia de caracteres necessitará de um caractere nulo no final, então a cadeia de caracteres têm de ser declarada com 51 compartimentos para armazenar valores do tipo char , como mostrado a seguir: #define MAX 50 int main(void) { ... char cadeia[MAX+1]; Na declaração de uma variável que pode armazenar uma cadeia de caracteres, sempre de- vemos reservar um compartimento a mais para que o caractere nulo possa ser armazenado. Como diversas funções da linguagem C supõem que as cadeias de caracteres são terminadas com o caractere nulo, se isso não ocorre em algum caso, o comportamento do programa passa a ser imprevisível. A declaração de um vetor de caracteres com dimensão MAX+1 não quer dizer que ele sem- pre conterá uma cadeia de caracteres com MAX caracteres. O comprimento de uma cadeia de caracteres depende da posição do caractere nulo na cadeia, não do comprimento do vetor onde a cadeia está armazenada. Como em qualquer vetor, uma cadeia de caracteres também pode ser declarada e iniciali- zada simultaneamente. Por exemplo, char cidade[13] = "Campo Grande"; faz com que o compilador insira sequencialmente os caracteres da cadeia de caracteres "Campo Grande" no vetor cidade e então adicione o caractere nulo ao final da cadeia. Ape- sar de "Campo Grande" parecer uma literal, na realidade, a linguagem C a enxerga como uma abreviação para um inicializador de um vetor, que poderia ter sido escrito equivalentemente como abaixo: char cidade[13] = {’C’,’a’,’m’,’p’,’o’,’ ’,’G’,’r’,’a’,’n’,’d’,’e’,’\0’}; Se um inicializador tem menor comprimento que o comprimento do vetor, o compilador preencherá oscaracteres restantes do vetor com o caractere nulo. Se, por outro lado, o inicia- FACOM UFMS 13 CADEIAS DE CARACTERES 142 lizador tem comprimento maior que a capacidade de armazenamento do vetor associado, os caracteres iniciais do inicializador serão armazenados no vetor, sem que o último deles seja o caractere nulo, impedindo assim que essa variável seja usada como uma legítima cadeia de caracteres. Vejamos agora o programa 13.1 que determina o comprimento de uma variável que é uma cadeia de caracteres. Qual será a saída deste programa? Programa 13.1: Determina o comprimento de uma cadeia de caracteres. #include <stdio.h> int main(void) { char palavra[10] = "Ola!"; int n; n = 0; while (palavra[n] != ’\0’) n++; printf("O comprimento da palavra é %d\n", n); return 0; } Há uma forma de ler e escrever cadeias de caracteres na linguagem C que facilita o trabalho de um(a) programador(a), evitando que sempre lance mão de uma estrutura de repetição para realizar uma dessas duas tarefas. O especificador de conversão %s no interior de uma cadeia de caracteres de formatação de entrada pode ser usado para mostrar um vetor de caracteres que é terminado por um caractere nulo, isto é, uma cadeia de caracteres. Assim se palavra é um vetor de caracteres terminado com o caractere nulo, a chamada da função abaixo: printf("%s\n", palavra); pode ser usada para mostrar o conteúdo completo da cadeia de caracteres palavra na saída padrão. Quando a função printf encontra o especificador de conversão %s , supõe que o argumento correspondente é uma cadeia de caracteres, isto é, um vetor de caracteres terminado por um caractere nulo. Podemos também usar a mesma cadeia de caracteres de formatação "%s" para leitura de uma cadeia de caracteres. A função scanf pode ser usada com o especificador de conversão %s para ler uma cadeia de caracteres até que a leitura de um branco seja realizada. Assim, a chamada da função scanf abaixo: scanf("%s", palavra); tem o efeito de ler uma cadeia de caracteres digitada pelo usuário e de armazená-la no vetor de caracteres palavra . FACOM UFMS 13 CADEIAS DE CARACTERES 143 É muito importante ressaltar que, ao contrário das chamadas anteriores da função scanf , no caso de leitura de cadeias de caracteres, o símbolo & não é adicionado como prefixo do identificador da variável. Veremos o porquê disto quando estudarmos apontadores. Se na execução da função scanf anterior um(a) usuário(a) digita os caracteres abcdefg , a cadeia de caracteres "abcdefg" é armazenada no vetor palavra . Se, diferentemente, um(a) usuário(a) digita os caracteres Campo Grande , então apenas a cadeia de caracteres "Campo" é armazenada no vetor palavra , devido ao branco ( ). Os caracteres restantes da cadeia di- gitada ficarão disponíveis no buffer de entrada até que uma próxima chamada à função scanf seja realizada. Para evitar os brancos na leitura de uma cadeia de caracteres, usamos o especificador de conversão %[...] , que também é usado na leitura de cadeias de caracteres, delimitando, den- tro dos colchetes, quais são os caracteres permitidos em uma leitura. Qualquer outro caractere diferente dos especificados dentro dos colchetes finalizam a leitura. Além disso, podemos in- verter essas permissões, indicando o caractere ^ como o primeiro caractere dentro dos colche- tes. Por exemplo, scanf("%[^\n]", palavra); realiza a leitura de uma cadeia de caracteres, armazenando seu conteúdo no vetor de caracteres palavra . O caractere que finaliza a leitura é o \n . Qualquer outro caractere será lido e armazenado no vetor palavra . É muito importante destacar que a função scanf termina automaticamente uma cadeia de caracteres que é lida com o especificador de conversão "%s" ou "%[...]" com um caractere nulo, fazendo assim que o vetor de caracteres se torne de fato uma cadeia de caracteres após sua leitura. Veja um exemplo simples sobre entrada e saída de cadeias de caracteres no programa 13.2. Programa 13.2: Entrada e saída de uma cadeia de caracteres. #include <stdio.h> #define MAX 20 /* Recebe uma palavra com até MAX caracteres e imprime seu comprimento */ int main(void) { char palavra[MAX+1]; int n; printf("Informe uma palavra (com até %d caracteres): ", MAX); scanf("%s", palavra); n = 0; while (palavra[n] != ’\0’) n++; printf("A palavra [%s] tem %d caracteres\n", palavra, n); return 0; } FACOM UFMS 13 CADEIAS DE CARACTERES 144 Exercícios Faça a simulação passo a passo da execução dos programas que construir para solucionar os exercícios abaixo. 13.1 Dada uma frase com no máximo 100 caracteres, determinar quantos caracteres espaço a frase contém. Programa 13.3: Solução do exercício 13.1. #include <stdio.h> #define MAX 100 /* Dada uma frase, determina quantos espaços ela possui */ int main(void) { char frase[MAX+1]; int esp, i; printf("Informe uma frase: "); scanf(" %[^\n]", frase); esp = 0; for (i = 0; frase[i] != ’\0’; i++) if (frase[i] == ’ ’) esp++; printf("Frase tem %d espaços\n", esp); return 0; } 13.2 Dada uma cadeia de caracteres com no máximo 100 caracteres, contar a quantidade de letras minúsculas, letras maiúsculas, dígitos, espaços e símbolos de pontuação que essa cadeia possui. 13.3 Dadas duas cadeias de caracteres cadeia1 e cadeia2 , concatenar cadeia2 no final de cadeia1 , colocando o caractere nulo no final da cadeia resultante. A cadeia resultante a ser mostrada deve estar armazenada em cadeia1 . Suponha que as cadeias sejam informadas com no máximo 100 caracteres. Exemplo: Se a primeira cadeia de caracteres contém tamandua- e a segunda contém bandeira a cadeia de caracteres resultante é tamandua-bandeira e deve ser armazenada na cadeia1 . 13.4 Dada uma cadeia de caractere cadeia com no máximo 100 caracteres e um caractere c , buscar a primeira ocorrência do caractere c na cadeia . Se c ocorre em cadeia , mostrar a posição da primeira ocorrência; caso contrário, mostrar o valor -1 . FACOM UFMS 13 CADEIAS DE CARACTERES 145 Exemplo: Se a cadeia de caracteres é aaabaaacbabccbaabggcgcgag e o caractere é g então a resposta é 17. 13.5 Dadas duas cadeias de caracteres cadeia1 e cadeia2 , cada uma com no máximo 100 caracteres, compará-las e devolver um valor menor que zero se cadeia1 é lexicografica- mente menor que cadeia2 , o valor zero se cadeia1 é igual (ou tem o mesmo conteúdo que) a cadeia2 , ou um valor maior que zero se cadeia1 é lexicograficamente maior que cadeia2 . Exemplo: Se a primeira cadeia de caracteres é abcdefgh e a segunda é abcddd então a resposta é 1. 13.6 Solucione o exercício 12.14 considerando que a palavra e a frase são cadeais de caracteres. FACOM UFMS Cadeias de caracteres Literais Vetores de caracteres Cadeias de caracteres Referências bibliográficas