Projeto de Algoritmos

Cadeias de caracteres (strings)

Uma cadeia de caracteres é uma seqüência finita de caracteres.  Na linguagem C, uma cadeia de caracteres, ou string, é um vetor (= array) de caracteres em que o caracter nulo ('\0') é interpretado como marca de fim-de-cadeia.  Exemplo:

    char s[20];
    s[0] = 'E';
    s[1] = 'X';
    s[2] = 'E';
    s[3] = 'M';
    s[4] = 'P';
    s[5] = 'L';
    s[6] = 'O';
    s[7] = '\0';
    s[8] = 'S';

Depois da execução desse fragmento de código, o vetor s contém a cadeia de caracteres "EXEMPLO". O caracter nulo marca o fim dessa cadeia. A porção s[8..19] do vetor é ignorada.

Eis um exemplo familiar: o primeiro argumento das funções printf e scanf é uma string constante:

   scanf ("%d", &n);
   printf ("O valor de n é %d", n);

O mesmo efeito do exemplo que abriu esta seção é produzido pelo fragmento de código

   char s[20];
   strcpy (s, "EXEMPLO");

onde strcpy é uma função que será discutida na próxima seção. O segundo argumento de strcpy no exemplo é uma string constante. Note que strings constantes são indicadas por aspas duplas (e o caracter nulo final é subentendido).

Toda string é representada pelo endereço do seu primeiro caracter, como acontece com qualquer vetor. Assim, a variável s no exemplo acima é do tipo   char *   (mas dizemos, informalmente, que  s é uma string).

Um efeito semelhante ao do exemplo que abriu esta seção é produzido por

   char *s;
   s = "EXEMPLO";

[Mas   char s[20]; s = "EXEMPLO";   não está correto, por razões que não quero explicar agora.]

Exemplo: contagem de vogais

A função abaixo conta o número de vogais em uma string. [Inspirada na aula 12 da edição 2003 de MAC0110.]  A função conta apenas as vogais não-acentuadas, mas é muito fácil modificar o código para que todas as vogais sejam contadas.

/* Devolve o número de vogais na string s. */

int contaVogais (char s[]) {
   char *vogais;
   int numVogais, i;

   vogais = "aeiouAEIOU";
   numVogais = 0;
   for (i = 0; s[i] != '\0'; i++) {
      char ch; 
      int j;
      ch = s[i]; 
      for (j = 0; vogais[j] != '\0'; j++) {
         if (vogais[j] == ch) {
            numVogais += 1;
            break;
         }
      }
   }
   return numVogais;
}

Exercícios

  1. Qual a diferença entre "mno" e "m\no"?  Qual a diferença entre "MNOP" e "MN0P"?  Qual a diferença entre "ABC\0abc" e "ABC0abc"?

  2. Qual a diferença entre "A" e 'A'?

  3. Escreva uma função que receba um caracter c e devolve uma string cujo único caracter é c.

  4. [Sedg 3.56]  Escreva uma função que receba uma string e imprima uma tabela com o número de ocorrências de cada caracter na string. Escreva um programa para testar a função.

  5. [Sedg 3.57]  Escreva uma função que decida se uma string é ou não um palíndromo (ou seja, se o inverso da string é igual a ela). Escreva um programa para testar a função.

  6. Escreva uma função que receba strings s e t e decida se s é segmento de t  (ou seja, se s pode ser obtida apagando um número arbitrário de elementos do início de t e um número arbitrário de elementos no fim de t).  Escreva um programa que use a função para contar o número de ocorrências de uma string s em uma string t.

  7. [Sedg 3.62]  Escreva uma função que calcule o comprimento da mais longa seqüência de espaços em branco em uma string. Escreva uma função que faça o serviço examinando o menor número possível caracteres. Escreva um programa para testar sua função.

  8. [Sedg 3.60]  Escreva uma função que receba uma string e substitua cada segmento de dois ou mais espaços em branco por um só caracter ' '.

  9. Escreva uma função que receba uma string de 0s e 1s, interprete essa string como um número em notação binária e devolva o valor desse número.

A biblioteca string

A biblioteca-padrão string da linguagem C contém várias funções de manipulação de cadeias de caracteres. Para usar essas funções, o seu programa deve incluir o arquivo-interface string.h:

#include <string.h>

No que segue, as cadeia de caracteres serão tratadas como um novo tipo-de-dados:

typedef char *string;

1. A função strlen, cujo nome é uma abreviatura de string length, recebe uma string e devolve o seu comprimento.  O comprimento (= length) de uma string é o seu número de caracteres, sem contar o caracter nulo final.  O código dessa função poderia ser escrito assim:

int strlen (string s) {
   int i;
   for (i = 0; s[i] != '\0'; i++) ;
   return i;
}

(Na verdade, o código acima está ligeiramente incorreto, pois strlen devolve um  unsigned int.)

2. A função strcpy, cujo nome é uma abreviatura de string copy, recebe duas strings e copia a segunda (inclusive o caracter nulo final) para o espaço ocupado para a primeira. O conteúdo original da primeira string é perdido. Antes de chamar a função, o programador deve certificar-se de que o espaço alocado à primeira string é suficiente para acomodar a cópia da segunda string.  O código dessa função poderia ser escrito assim:

void strcpy (string s, string t) {
   int i;
   i = 0;
   while (t[i] != '\0') {
      s[i] = t[i];
      i += 1;
   }
   s[i] = '\0';
}

(Na verdade, o código acima está ligeiramente incorreto, pois a função devolve o endereço da primeira string. Mas os usuários da função usualmente só estão interessados no efeito da função e não n'o que ela devolve.)

3. A função strcmp, cujo nome é uma abreviatura de string compare, recebe duas strings e compara as duas lexicograficamente. Ela devolve um número negativo se a primeira string for lexicograficamente menor que a segunda, devolve 0 se as duas strings são iguais e devolve um número positivo se a primeira string for lexicograficamente maior que a segunda. O código dessa função poderia ser escrito assim:

int strcmp (string s, string t) {
   int i;
   for (i = 0; s[i] == t[i]; i++)
      if (s[i] == '\0') return 0;
   return s[i] - t[i];
}

Convém lembrar que o valor da expressão  s[i] - t[i]  é calculado como se ela fosse
(int) (unsigned char) s[i] - (int) (unsigned char) t[i].

A ordem lexicográfica entre strings é análoga à ordem das palavras em um dicionário. Ela se baseia na ordenação dos caracteres estabelecida na tabela ISO8859-1, da mesma forma que a ordem das palavras em um dicionário se baseia na ordenação das letras no alfabeto. Para comparar duas strings s e t, procura-se a primeira posição, digamos k, em que as duas strings diferem. Se s[k] vem antes de t[k] na tabela ISO então s é lexicograficamente menor que t.

Exercícios

  1. O que há de errado com o seguinte trecho de código?
       char a[], b[];
       strcpy (a, "cenoura");
       strcpy (b, "cereja");
       if (a < b)
          printf ("%s precede %s no dicionário", a, b);
    

  2. Escreva uma função que receba uma string s e um inteiro não-negativo i e devolva o i-1-ésimo caracter de s, ou seja, o caracter s[i].

  3. Escreva uma função que receba uma string s e inteiros não-negativos i e j e devolve o segmento s[i..j]. Sua função não deve alocar novo espaço e pode destruir a string s que recebeu.

  4. Escreva uma função que receba uma string s, um caracter c e devolva o índice da primeira posição de s que é igual a c.  Agora faça uma versão mais completa da função, que procura c a partir de uma dada posição i.

  5. Escreva uma função que receba strings x e s e devolve o índice da posição a partir da qual x ocorre em s.

  6. Escreva uma função que receba strings s e t e decida se s é um segmento de t.  Escreva um programa que use a função para contar o número de ocorrências de uma string s em uma string t.

 

 


URL of this site: www.ime.usp.br/~pf/algoritmos/
1998 | Last modified: Mon Nov 13 07:52:45 BRST 2006
Paulo Feofiloff
IME-USP