Departamento de Ciência da Computação IME/USP MAC2166 Introdução a Computação 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: #define MAX 100 #include <stdio.h> #include <stdlib.h> int main () { 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"); return 0; } 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): #include <stdio.h> #include <stdlib.h> #define MAX 100 int main () { /* 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); system ( "pause" ); return 0; } 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++; } printf("\n"); ou ainda, usando um comando for : 2 for (i=0; texto[i] != ’\0’; i++) printf("%c", texto[i]); printf("\n"); 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: #include <stdio.h> #include <stdlib.h> #define MAX 100 int main () { /* Declarações */ int i,n; 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]); printf("\n"); system ( "pause" ); return 0; } 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: #include <stdio.h> #include <stdlib.h> #define MAX 100 int main () { int i,n; 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"); return 0; } 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: #include <stdio.h> #include <stdlib.h> #define MAX 100 int main () { int i,n; 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); system ( "pause" ); return 0; } 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: pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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: pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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: pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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