8

Arrays de Caracteres (Strings)

Strings: Manipulação de Textos8.1

Este capítulo tem como objetivo fundamental apresentar o conceito de string na linguagem C, explorando como essa estrutura é essencial para a manipulação de palavras e textos dentro de um programa. Ao final deste estudo, você será capaz de compreender a natureza técnica das strings, além de dominar as técnicas para sua criação, inicialização e acesso aos seus elementos individuais. Adicionalmente, você aprenderá a realizar operações de entrada e saída de textos via teclado e tela, bem como a utilizar as funções bibliotecárias básicas para o processamento de cadeias de caracteres.

Objetivos de Aprendizado
  • Compreender a definição de string como um caso especial de array.
  • Aprender a declarar e estruturar cadeias de caracteres.
  • Dominar os diferentes métodos de inicialização de strings.
  • Conhecer as formas de acessar e modificar caracteres específicos em um texto.
  • Praticar a leitura e a escrita de strings utilizando funções de entrada e saída.
  • Utilizar funções fundamentais para manipulação e análise de textos.

Definição e declaração de uma string8.2

Uma string é o termo técnico utilizado para definir uma sequência de caracteres posicionados de forma adjacente na memória do computador. Na linguagem C, essa estrutura, que pode representar uma palavra ou uma frase completa, é implementada fisicamente através de um array do tipo char.

Declarando uma string8.2.1

Como a string é, essencialmente, um array de caracteres, sua declaração respeita as mesmas normas sintáticas de um array convencional:

char str[6];

Esta instrução reserva um espaço na memória para uma string de nome str com capacidade para 6 elementos. No entanto, você deve ter atenção redobrada a uma característica vital: as strings utilizam obrigatoriamente o caractere \0 (caractere nulo) logo após a última letra da palavra ou frase armazenada.

O caractere \0 serve para indicar o fim da sequência de caracteres.

A importância do terminador nulo8.2.1.1

A necessidade do \0 surge porque você pode declarar uma string com um tamanho significativamente maior do que o texto que ela efetivamente armazena. Imagine que você definiu uma string com 50 posições, mas a utilizou apenas para guardar a palavra "oi". As 48 posições restantes conterão "lixo de memória" (valores aleatórios residuais).

Para evitar que esse conteúdo irrelevante seja exibido na tela, o sistema utiliza o \0 como uma marca de interrupção. Ele sinaliza que a sequência útil de texto terminou e que as posições seguintes devem ser ignoradas:

o | i | \0 | ? | ã | # | ...
Cálculo do Tamanho

Ao definir o tamanho de uma string, você deve sempre contabilizar o espaço extra para o caractere \0. Isso significa que, em uma string declarada com tamanho 50, você terá apenas 49 posições disponíveis para o texto propriamente dito, pois a última vaga deve ser reservada para o sinalizador de encerramento.

Inicializando uma string8.2.2

Uma string pode ter seu conteúdo capturado via teclado ou ser definida com um valor inicial logo no momento de sua criação. Para a inicialização direta no código, você pode adotar o mesmo princípio utilizado para vetores e matrizes, atribuindo cada caractere individualmente:

char str[10] = { 'J', 'o', 'a', 'o', '\0' };

Contudo, como você pode notar, essa abordagem manual não é prática para textos longos. Por esse motivo, a linguagem C oferece uma forma muito mais eficiente e legível de inicialização utilizando aspas duplas:

char str[10] = "Joao";

Além de facilitar a escrita, essa forma de inicialização possui a vantagem técnica de inserir automaticamente o caractere terminador \0 ao final da sequência de caracteres, garantindo a integridade da estrutura do texto na memória.

Praticidade das Aspas

Sempre que você souber o valor inicial de um texto, prefira o uso das aspas duplas. Elas tornam o seu código mais limpo e evitam que você esqueça de incluir manualmente o caractere de fechamento \0.

Acessando um elemento da string8.2.3

Um aspecto fundamental na manipulação de strings é que, devido à sua natureza de array, cada caractere individual pode ser acessado de forma independente por meio de indexação, exatamente como você faria com qualquer outro vetor ou matriz.

Considere o exemplo abaixo, onde uma string é inicialmente definida e, posteriormente, tem seu primeiro caractere alterado:

char str[6] = "Teste"; 
// Memória inicial: T | e | s | t | e | \0

str[0] = 'L';
// Memória após alteração: L | e | s | t | e | \0

Ao realizar essas operações, você deve estar atento à diferenciação sintática exigida pela linguagem C:

  • Aspas duplas (" "): São utilizadas exclusivamente para a atribuição de strings completas (cadeias de caracteres).
  • Aspas simples (' '): São utilizadas obrigatoriamente para a atribuição de um único caractere em uma posição específica do array.
Lógica de Indexação

Lembre-se de que o primeiro caractere de uma string está sempre no índice 0. Modificar um caractere individualmente não altera a posição do terminador nulo \0, a menos que você sobrescreva manualmente o próprio terminador.

Lendo uma string do teclado8.2.4

A leitura de cadeias de caracteres em C pode ser realizada de diversas maneiras, cada uma com comportamentos específicos em relação a espaços e limites de memória.

Usando a função scanf()8.2.4.1

Você pode utilizar a função scanf() com o formatador %s para capturar uma string. É importante notar que, ao ler strings com esta função, você não deve utilizar o símbolo & antes do nome da variável, nem os colchetes, pois o objetivo é capturar a sequência inteira e não apenas um caractere.

char str[20];
scanf("%s", str); // Lê uma string até o primeiro espaço

No entanto, a função scanf() possui uma limitação crítica: ela interrompe a leitura ao encontrar o primeiro caractere de espaço. Isso a torna inadequada para ler frases, capturando apenas palavras isoladas.

Usando a função gets()8.2.4.2

Uma alternativa para capturar frases completas é a função gets(). Ela lê todos os caracteres digitados, incluindo espaços, até que a tecla Enter seja pressionada.

char str[20];
gets(str); // Lê a frase completa incluindo espaços

Usando a função fgets()8.2.4.3

A função fgets() é considerada uma opção mais robusta e segura para a leitura de textos. Ela exige três parâmetros: a string de destino, o tamanho máximo de caracteres e a origem da leitura (ponteiro para arquivo).

Para ler dados do teclado, você deve substituir o ponteiro de arquivo pela constante stdin, que representa a entrada padrão.

#include <stdio.h>
#include <stdlib.h>

int main(){
   char nome[30];
   printf("Digite um nome: ");
   fgets(nome, 30, stdin); // Lê do teclado com limite de 30 caracteres
   printf("O nome digitado foi: %s", nome);
   system("pause");
   return 0;
}

A função fgets() apresenta vantagens importantes sobre a gets():

  • Segurança: Ela limita a leitura ao tamanho especificado (ou "tamanho-1"), evitando o estouro de buffer caso você digite um texto maior do que o espaço reservado.
  • Preservação do Enter: Diferente da gets(), o caractere de nova linha (\n) gerado pelo Enter é armazenado dentro da string final.

Limpando o buffer do teclado8.2.4.4

Em certas situações, resíduos de leituras anteriores no teclado podem causar falhas na captura de novas strings ou caracteres. Para evitar esses erros, você pode "limpar" a entrada padrão utilizando a função setbuf(stdin, NULL) antes de realizar a leitura.

Na linguagem C, a constante NULL representa um valor nulo. Ao associá-la ao dispositivo stdin, você garante que o buffer de entrada esteja vazio para a próxima operação.


// Limpando para caracteres
char ch;
setbuf(stdin, NULL);
scanf("%c", &ch);

// Limpando para strings
char str[10];
setbuf(stdin, NULL);
gets(str);

Escrevendo uma string na tela8.2.5

A exibição de cadeias de caracteres para o usuário pode ser realizada de forma simples através de funções de saída formatada ou funções específicas de escrita de strings.

Usando a função printf()8.2.5.1

A maneira mais comum de exibir uma string é utilizando a função printf() com o especificador de formato %s. Ao contrário da exibição de caracteres individuais, você deve referenciar apenas o nome do array, sem o uso de colchetes ou índices, para que o sistema processe a sequência completa até encontrar o terminador nulo.

char str[20] = "Hello World";
printf("%s", str); // Exibe a string completa na tela

Usando a função fputs()8.2.5.2

A função fputs() é uma alternativa eficiente para a escrita de textos. Ela foi projetada para enviar uma string para um fluxo de saída específico, recebendo dois parâmetros: a string de origem e um ponteiro para o destino (arquivo ou dispositivo).

Para direcionar o texto diretamente para o monitor, você deve utilizar a constante stdout, que representa a saída padrão do sistema.

#include <stdio.h>
#include <stdlib.h>

int main(){
   char texto[30] = "Hello World\n";
   
   // Escreve a string no dispositivo de saída padrão (tela)
   fputs(texto, stdout); 

   system("pause");
   return 0;
}

A função fputs() retorna um valor diferente de zero caso a escrita seja bem-sucedida ou a constante EOF (geralmente $-1$) em caso de erro. Uma característica importante a ser lembrada é que, ao contrário de outras funções de saída de strings como a puts(), a fputs() não adiciona automaticamente uma quebra de linha ao final do texto; se você precisar saltar uma linha, deverá incluir o caractere \n dentro da própria string.

Escolha da Função

Enquanto o printf() oferece maior flexibilidade para formatar textos junto com outras variáveis, o fputs() é mais direto e performático para exibir mensagens de texto puras que já estão armazenadas em memória.

Funções para manipulação de strings8.3

A linguagem C disponibiliza na biblioteca padrão <string.h> uma série de funções desenvolvidas especificamente para facilitar o processamento e a manipulação de cadeias de caracteres. Abaixo, você conhecerá as ferramentas mais fundamentais para gerenciar textos em seus programas.

Tamanho de uma string8.3.1

Para descobrir o comprimento real de um texto, você deve utilizar a função strlen(). É vital não confundir o tamanho total do array com a quantidade de caracteres que ele armazena no momento.

  • Funcionamento: A função strlen() conta e retorna apenas o número de caracteres existentes antes do caractere terminador \0.
  • Exemplo: Se você declarar char str[15] = "teste";, a função retornará 5 (as letras da palavra "teste") e não 15 (o tamanho reservado na memória).

Copiando uma string8.3.2

Como você já aprendeu, a linguagem C não permite a atribuição direta entre arrays utilizando o operador =. Para transferir o conteúdo de um texto para outro, é necessário realizar uma cópia elemento por elemento, tarefa que a função strcpy() executa automaticamente.

A sintaxe da função segue este padrão:

strcpy(char *destino, char *origem);
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // Necessário para usar strcpy()

int main(){
   char str1[100], str2[100];
   printf("Entre com uma string: ");
   gets(str1);

   // Copia o conteúdo de str1 para str2
   strcpy(str2, str1); 

   printf("String 1: %s\n", str1);
   printf("String 2: %s\n", str2);
   system("pause");
   return 0;
}
Segurança de Memória

Ao utilizar o strcpy(), você deve garantir que o array de destino seja grande o suficiente para suportar todos os caracteres da origem, incluindo o terminador nulo, para evitar o estouro de buffer.

Concatenando strings8.3.3

A operação de concatenação consiste em anexar o conteúdo de uma string ao final de outra já existente. Para isso, utiliza-se a função strcat().

O funcionamento técnico é preciso: a função strcat() localiza o caractere \0 da string de destino e começa a gravar a string de origem exatamente a partir daquela posição.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
   char str1[15] = "bom ";
   char str2[15] = "dia";

   // Resultará em "bom dia" dentro de str1
   strcat(str1, str2); 

   printf("%s", str1);
   system("pause");
   return 0;
}

Assim como na cópia, você deve certificar-se de que o array de destino tenha espaço livre suficiente para comportar a soma das duas cadeias de caracteres.

Comparando duas strings8.3.4

Para verificar a igualdade entre textos, você não deve usar operadores relacionais como ==. A ferramenta correta é a função strcmp().

int strcmp(char *str1, char *str2);

A função analisa as duas strings posição por posição e retorna um valor inteiro:

  • Valor ZERO (0): Significa que as strings são rigorosamente iguais.
  • Valor diferente de ZERO: Significa que as strings são diferentes.
Sensibilidade a Maiúsculas

A função strcmp() é case-sensitive. Isso significa que letras maiúsculas e minúsculas são tratadas como caracteres distintos, fazendo com que "Teste" e "teste" sejam consideradas diferentes pelo programa.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
   char str1[100], str2[100];
   printf("Entre com uma string: ");
   gets(str1);
   printf("Entre com outra string: ");
   gets(str2);

   if(strcmp(str1, str2) == 0)
       printf("Strings iguais\n");
   else
       printf("Strings diferentes\n");

   system("pause");
   return 0;
}

Questões8.4

1. Escreva um programa em C que declare uma string com capacidade para 20 caracteres. Inicialize-a com a palavra "Teste" diretamente no código e, em seguida, imprima a string na tela.

  • Entrada: Nenhuma.
  • Saída Esperada: Teste.

2. Crie um programa que leia o primeiro nome do usuário (sem espaços) utilizando a função scanf e, em seguida, cumprimente-o imprimindo "Ola, [Nome]!".

  • Entrada: Maria.
  • Saída Esperada: Ola, Maria!.

3. Desenvolva um programa que leia uma frase completa (que pode conter espaços) digitada pelo usuário, utilizando a função fgets. Imprima a frase lida na tela.

  • Entrada: Aprendendo a programar em C.
  • Saída Esperada: Aprendendo a programar em C.

4. Escreva um programa que leia uma palavra do usuário e imprima o tamanho dessa palavra (número de caracteres), utilizando a função strlen.

  • Entrada: Computador.
  • Saída Esperada: Tamanho: 10.

5. Crie um programa que leia duas palavras separadamente e utilize a função strcat para concatená-las em uma única string, separadas por um espaço (você pode precisar adicionar o espaço manualmente ou concatenar " " entre elas). Imprima o resultado final.

  • Entrada: Bom, Dia.
  • Saída Esperada: Bom Dia.

6. Escreva um programa que leia uma palavra e a armazene na variável str1. Utilize a função strcpy para copiar o conteúdo de str1 para uma segunda variável str2. Imprima ambas as strings para confirmar a cópia.

  • Entrada: Copia.
  • Saída Esperada: String 1: Copia, String 2: Copia.

7. Desenvolva um programa que leia duas strings e verifique se elas são iguais ou diferentes utilizando a função strcmp. O programa deve imprimir "Iguais" ou "Diferentes".

  • Entrada: Casa, casa.
  • Saída Esperada: Diferentes.

8. (Sem usar strlen) Crie um programa que leia uma string do usuário e conte manualmente quantos caracteres ela possui (percorrendo o array até encontrar o terminador \0). Imprima a contagem.

  • Entrada: Teste.
  • Saída Esperada: 5.

9. Escreva um programa que leia uma string e imprima as 4 primeiras letras dessa string.

  • Entrada: Paralelepipedo.
  • Saída Esperada: Para.

10. Crie um programa que leia uma string e substitua todas as vogais 'a' pelo caractere '*'. Imprima a string modificada.

  • Entrada: Arara.
  • Saída Esperada: Ar*r*. (Note que a maiúscula 'A' não deve ser alterada).

11. Escreva um programa que leia uma palavra e verifique se ela é um palíndromo (se pode ser lida da mesma forma de trás para frente, como "ANA" ou "RADAR"). O programa deve imprimir "Eh palindromo" ou "Nao eh palindromo".

  • Entrada: RADAR.
  • Saída Esperada: Eh palindromo.

12. Crie um programa que leia uma string e a imprima de trás para frente (invertida), sem utilizar funções prontas de inversão.

  • Entrada: ABC.
  • Saída Esperada: CBA.

Próximos passos8.5

No próximo capítulo, Funções, estudaremos como criar e utilizar funções em C para organizar melhor o código, torná-lo mais modular e reutilizável, além de compreender a passagem de parâmetros, o uso de ponteiros e o acesso à memória, fundamentos essenciais para programas mais eficientes e bem estruturados.