Projeto de Algoritmos

Cadeias de caracteres (strings)

Na linguagem C, uma ou string (ou cadeia de caracteres) é um vetor de caracteres em que o caractere nulo ('\0') é interpretado como fim da parte relevante do vetor.  Exemplo:

    char *s;
    s = malloc (10 * sizeof (char));
    s[0] = 'A';
    s[1] = 'B';
    s[2] = 'C';
    s[3] = '\0';
    s[4] = 'D';

Depois da execução desse fragmento de código, o vetor s[0..3] contém a cadeia de caracteres ABC. O caractere nulo marca o fim dessa cadeia. A porção s[4..9] do vetor é ignorada.

Comprimento e endereço

O comprimento (= length) de uma string é o seu número de caracteres, sem contar o caractere nulo final.

O endereço de uma string é o endereço do seu primeiro caractere, da mesma forma que o endereço de um vetor é o endereço de seu primeiro elemento. Em discussões informais, é usual confundir uma string com o seu endereço. Assim, a expressão "considere a string s" deve ser entendida como "considere a string cujo endereço é s".

Strings constantes

Para especificar uma string constante, basta embrulhar uma sequência de caracteres num par de aspas duplas. O caractere nulo final fica subentendido. Por exemplo, "ABC" é uma string constante e o fragmento de código

   char *s;
   s = "ABC";

é equivalente ao que aparece na introdução desta página (exceto pelo fato de que a string "ABC" ocupa apenas 4 bytes na memória). O primeiro argumento das funções printf e scanf, é quase sempre uma string constante. Por exemplo,

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

Exemplo: contagem de vogais

A função abaixo conta o número de vogais em uma string.  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.

int contaVogais (char s[]) {
   int numVogais, i;
   char *vogais;
   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 "A" e 'A'?
  2. Qual a diferença entre "mno" e "m\no"?  Qual a diferença entre "MNOP" e "MN0P"?  Qual a diferença entre "MN\0P" e "MN0P"?
  3. Escreva uma função que receba um caractere c e devolva uma string cujo único caractere é c.
  4. Escreva uma função que receba uma string e imprima uma tabela com o número de ocorrências de cada caractere na string. Escreva um programa para testar a função.
  5. 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.60]  Escreva uma função que receba uma string e substitua cada segmento de dois ou mais espaços por um só caractere ' '.
  8. 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 strings. Para usar essas funções, o seu programa deve incluir o arquivo-interface string.h:

#include <string.h>

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

typedef char *string;

1.  A função strlen (abreviatura de string length) recebe uma string e devolve o seu comprimento.  O código dessa função poderia ser escrito assim:

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

2.  A função strcpy (abreviatura de string copy) recebe duas strings e copia a segunda (inclusive o caractere 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 para primeira string é suficiente para acomodar a cópia da segunda.  [Buffer overflow é uma das mais comuns origens de bugs de segurança!]  O código dessa função poderia ser escrito assim:

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

(Na verdade, o código acima está ligeiramente incorreto, pois a função strcpy da biblioteca string 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.)

A função strcpy pode ser usada para obter um efeito semelhante ao do exemplo que abriu esta página:

   char s[10];
   strcpy (s, "ABC");

3.  A função strcmp (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.

Embora os parâmetros da função sejam do tipo char *, a função se comporta como se eles fossem do tipo unsigned char *. Assim, por exemplo, "bb" é considerada lexicograficamente menor que "bbã" e "ba" é considerada lexicograficamente menor que "bã".  O código da função poderia ser escrito assim:

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

Convém lembrar que o valor da expressão  usi - uti  é calculado em aritmética int (e não módulo 256).

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.  Se k não está definido então s e t são idênticas ou uma é prefixo próprio da outra; nesse caso, a string mais curta é lexicograficamente menor que a mais longa.

Exercícios

  1. Discuta as diferenças entre os três fragmentos de código a seguir:
    char a[8], b[8];
    strcpy (a, "abacate");
    strcpy (b, "banana");
    
    char *a, *b; 
    a = malloc (8); strcpy (a, "abacate");
    b = malloc (8); strcpy (b, "banana");
    
    char *a, *b; 
    a = "abacate";
    b = "banana";
    
  2. O que há de errado com o seguinte trecho de código?
    char b[8], a[8];
    strcpy (a, "abacate");
    strcpy (b, "banana");
    if (a < b)
       printf ("%s vem antes de %s no dicionário", a, b);
    else
       printf ("%s vem depois de %s no dicionário", a, b);
    
  3. O que há de errado com o seguinte trecho de código?
    char *b, *a;
    a = "abacate";
    b = "banana";
    if (a < b)
       printf ("%s vem antes de %s no dicionário", a, b);
    else
       printf ("%s vem depois de %s no dicionário", a, b);
    
  4. O que há de errado com o seguinte trecho de código?
    char *a, *b;
    a = "abacate";
    b = "amora";
    if (*a < *b)
       printf ("%s vem antes de %s no dicionário", a, b);
    else
       printf ("%s vem depois de %s no dicionário", a, b);
    
  5. Escreva uma função que receba uma string s e um inteiro não negativo i e devolva o i-1-ésimo caractere de s, ou seja, o caractere s[i].
  6. 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.
  7. Escreva uma função que receba uma string s, um caractere 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.
  8. 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.
  9. 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: Fri Aug 5 13:12:16 BRT 2011
Paulo Feofiloff
IME-USP

Valid HTML 4.01 Transitional    Valid CSS!