Departamento de Ciência da Computação MAC2166 Introdução a Computação IME/USP Strings e vetores de caracteres 1 Resumo: O uso de strings facilita a manipulação de palavras e textos. Strings são basicamente vetores do tipo char, porém diferentemente de simples vetores, strings são terminados por um caractere \0. Utilize %s para ler e imprimir strings nas funções scanf e printf. Você pode utilizar strings constantes para carregar vetores de caracteres na sua declaração. Uma constante do tipo string é definida por uma seqüência de caracteres entre aspas (lembre-se que uma constante do tipo char é um caractere entre apóstrofes). 2 Descrição: Nessa lição vamos estudar como palavras (seqüências de caracteres) são tratadas no C. Primeiro, vamos analisar um programa que carrega um vetor com n caracteres e os imprime logo em seguida: int i; char vet[max]; printf("digite o tamanho do vetor: "); scanf("%d", &n); prinft("digite a seqüência de caracteres: "); for ( i=0 ; i<n ; i++ ) scanf("%c", &vet[i]); prinft("a palavra que você digitou foi: "); for ( i=0 ; i<n ; i++ ) printf("%c", vet[i]); system("pause"); Imagine um usuário precisando digitar seu nome para um formulário, e o computador pedindo para que ele, primeiramante, digite o número de caracteres a serem lidos, como no exemplo acima. Isso complica muito uma atividade que, a princípio, é bastante simples. Uma forma de contornar esse problema seria utilizar um caractere especial como marcador, como por exemplo, um ponto (. ). Nesse caso, o computador poderia imprimir uma mensagem como: Digite seu nome terminado
por um ponto. Obviamente, nenhuma pessoa poderia ter um. em seu nome, e essa solução provavelmente não seria apropriada para entrar frases, ou textos com pontuação. Strings são vetores de caracteres terminados por um caractere especial, o \0 (barra zero). Esse caractere indica o final da palavra ou texto e é normalmente tratado pelo próprio computador, facilitando assim a manipulação de palavras. 3 Entrada e saída Em C utiliza-se a seqüência %s para ler (usando scanf ) e imprimir (usando printf ) strings. 4 Exemplos Na linguagem C, podemos inicializar strings colocando a seqüência de caracteres entre aspas, como mostra o exemplo abaixo (tente descobrir a saída desse programa antes de continuar): /* Declarações */ int i; char texto[max] = "apenas um exemplo."; printf("%s\n", texto); for (i=0; i<5; i++) texto[i] = i + i; printf("%s\n", texto); 4.1 Descrição do programa O vetor texto de caracteres, quando carregado, recebe automaticamente pelo compilador um caractere \0, como mostrado abaixo (as posições com? não foram inicializadas, ou seja, seu conteúdo é desconhecido): texto: a p e n a s u m e x e m p l o. \0?? posição: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 O primeiro printf imprime o string apenas um exemplo., ou seja, percorre o vetor texto e imprime os seus caracteres um a um, até encontrar um caractere \0. Um trecho de código equivalente a printf("%s\n", texto) seria: i = 0; while (texto[i]!= \0 ) { printf("%c", texto[i]); i++; ou ainda, usando um comando for : 2
for (i=0; texto[i]!= \0 ; i++) printf("%c", texto[i]); Observe que, sem o uso de strings, precisamos conhecer o número de caracteres a serem impressos, e que o uso de %s simplifica bastante a impressão de strings. Além do código de terminação ( \0 ), não há diferença entre strings e vetores de caracteres, ou seja, strings podem ser considerados vetores de caracteres terminados por um caractere \0, como ilustrado pelo primeiro for do programa, que coloca nas posições 0 a 4 do vetor texto os caracteres i, j, k, l, m ), ou seja, o vetor texto ficaria assim: texto: i j k l m s u m e x e m p l o. \0?? posição: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 e o string impresso pelo último printf seria ijklms um exemplo.. OBSERVAÇÃO: quando dizemos que o string é terminado por um \0, significa que a parte válida dos dados está antes desse caractere especial. As posições após o \0, permanecem vazias, e podem ser utilizadas quando o vetor é utilizado, por exemplo, para armazenar um outro string de maior comprimento. 4.2 Um outro exemplo Vamos ver agora um programa que lê uma palavra e imprime os caracteres na ordem inversa a de leitura sem o uso de strings, apenas para realçar a dificuldade de tratar palavras quando os caracteres são lidos um a um: /* Declarações */ char frase[max]; printf("digite o numero de caracteres de seu texto: "); scanf ("%d", &n); printf("digite o seu texto:\n"); for (i=0; i<n; i++) scanf(" %c", &frase[i]); /* importante ter um espaco antes de %c */ printf("o seu texto na ordem inversa: \n"); for (i=n-1; i>=0; i--) printf("%c", frase[i]); Observe que o programa precisa saber o número de caracteres a serem lidos, para carregar o vetor texto. Para a palavra socorram-me, que possui 11 caracteres, a saída seria em-marrocos. Outra observação importante, é que como o scanf lê TODOS os caracteres que vem do teclado (inclusive o enter), é necessário colocar um espaço (branco) antes do %c do scanf, para que sejam eliminados os possíveis separadores (branco, tabs, 3
enters, etc). Caso contrário, o enter dado após a leitura do tamanho da palavra se torna parte dos caracteres lidos, e portanto faria parte da palavra (há muitos detalhes do C que precisam ser considerados quando se lê caracteres um a um). Experimente rodar esse programa usando esse mesmo exemplo, mas sem o espaço antes do %c no scanf. 4.3 Leitura de strings usando scanf Em exemplos anteriores, os strings foram carregados como constantes, e o compilador sabe quando o string começa e termina devido às aspas. A leitura de strings usando scanf exige um pouco mais de cuidado, pois é necessário saber como o scanf separa a entrada a partir do teclado em strings. Por convenção, os strings são delimitados por caracteres separadores, como o branco, tabulação, enter, etc (mas não de pontuação, como vírgula, dois pontos, ou ponto final). Por exemplo, no programa abaixo: char frase[max]; printf("digite o numero de palavras: "); scanf ("%d", &n); printf("digite todas as palavras e ao final tecle ENTER:\n"); for (i=0; i<n; i++) { scanf("%s", frase); printf(":%s:\n", frase); system("pause"); para a entrada 3 (como número de palavras) e as palavras um, dois, tres., imprimirá na saída o seguinte: :um,: :dois,: :tres.: Uma nova versão para o programa que lê uma palavra e a imprime em ordem inversa usando strings é dada a seguir: char pal[max], inv[max]; printf("digite sua palavra:\n"); scanf("%s", pal ); 4
/* acha fim do string em pal */ for (n=0; pal[n]!= \0 ; n++); /* monta um string inverso */ for (i=0; i<n; i++) inv[i] = pal[n-1-i]; inv[n] = \0 ; /* coloca o terminador no string inv */ /* imprime o string em na ordem inversa */ printf("o seu texto na ordem inversa: \n"); printf("%s\n", inv); Vamos simular esse último programa com a frase socorram-me. Após a declaração, os vetores pal e inv possuem conteúdo incerto (ou seja, estão vazios), como mostra a figura abaixo: frase:??????????????? inv:??????????????? Após o scanf, o vetor pal é carregado com socorram-me, e o string é automaticamente terminado por \0, como mostra a figura abaixo: frase: s o c o r r a m - m e \0??? inv:??????????????? O for após o scanf procura pela terminação do string, ou seja, procura pelo caractere \0, e o encontra na posição 11 do vetor, ou seja, n = 11, quando termina o for. A seguir, os caracteres de 10 a 0 são copiados do vetor pal para as posições 0 a 10 do vetor inv (ou seja, quando i = 0 por exemplo, inv[0] recebe o elemento n 1 i = 11 1 0 = 10 do vetor pal, ou inv[0] = frase[10]). Ao final do for, o caractere \0 é colocado ao final do string em inv para terminá-lo, de forma que teríamos a seguinte situação: frase: s o c o r r a m - m e \0??? inv: e m - m a r r o c o s \0??? e o último printf apenas imprime o string em inv. 5 Exercícios recomendados - Exercício 6.6 do caderno: Dados dois strings (um contendo uma frase e outro contendo uma palavra), determine o número de vezes que a palavra ocorre na frase. Exemplo: Para a palavra ANA e a frase: ANA E MARIANA GOSTAM DE BANANA --- --- --- --- temos que a palavra ocorre 4 vezes na frase. - Exercício 8.17 (usa vetores de caracteres e não strings ). 5