====== Strings ======
{{ progc_strings.mkv |Video desta aula}}
Uma string é uma sequência de caracteres que permite representar nomes, endereços e outras informações textuais.
===== Declaração =====
Em C, strings são implementadas como vetores de caracteres (tipo ''char'') terminados pelo caractere especial '''\0%%'%%'' (caractere cujo código numérico é zero). Esse caractere terminal é considerado no tamanho do vetor. As aspas duplas ("...") são usadas para declarar strings constantes.
Exemplos:
// declara string variável com até 99 caracteres (mais o \0)
char nome[100] ;
// declara string constante (com o \0 no final)
char *profissao = "estudante" ;
// declara ponteiro para uma string (não aloca espaço para ela)
char *endereco ;
// ou
char endereco[] ;
// ponteiro aponta para string constante
endereco = "Rua da Batata, 1000" ;
Deve-se observar que uma string é um **vetor de caracteres**, portanto as duas declarações abaixo são equivalentes:
char codigo[] = "XT07A" ;
char codigo[] = { 'X', 'T', '0', '7', 'A', '\0' } ;
A visão da string como vetor permite o acesso aos seus caracteres individuais. O código abaixo converte uma string em maiúsculas, usando os códigos ASCII dos caracteres:
i = 0 ;
while (str[i] != '\0') // varre todos os caracteres
{
if (str[i] >= 'a' && str[i] <= 'z') // se for letra minúscula
str[i] -= 32 ; // converte em letra maiúscula
i++ ;
}
// ou, usando strlen()
for (i = 0; i < strlen (str); i++) // varre todos os caracteres
if (str[i] >= 'a' && str[i] <= 'z') // se for letra minúscula
str[i] -= 32 ; // converte em letra maiúscula
Strings declaradas usando ''char[]'' são normalmente usadas para armazenar texto codificado no padrão ASCII (texto simples, sem letras acentuadas). Para armazenar textos com caracteres não-ASCII (acentos, cedilha emojis, etc) devem ser usadas outras [[codificação de caracteres|codificações]], como UTF8, e [[strings multibyte]].
===== Leitura e escrita =====
A escrita de strings pode ser feita com ''printf'' (usando o formato ''%s'' ou ''%NNNs''), ''puts'' ou ainda ''putchar'' (para escrever caractere por caractere):
char nome[] = "Homer Simpson" ;
printf ("Nome: %s\n", nome) ; // escrita com printf
puts (nome) ; // escrita com puts
for (i = 0; i < strlen(nome); i++) // escrita com putchar
putchar (nome[i]) ;
Por sua vez, a leitura de strings pode ser feita usando a função ''scanf'':
#define SIZE 100
char nome[SIZE+1] ; // não esquecer do '\0' no final da string
printf ("Digite seu nome: ") ;
// lê até encontrar espaço, tabulação, nova linha ou fim de arquivo
scanf ("%s", nome) ;
// idem, no máximo 20 caracteres
scanf ("%20s", nome) ;
// lê somente letras e dígitos (até encontrar outro caractere)
scanf("%[A-Za-z0-9]", nome);
// lê até encontrar um fim de linha (\n), ou seja
// lê enquanto não encontrar um caractere '\n'
scanf("%[^\n]", nome);
getchar() ; // para ler o "\n" no fim da linha
Observe que a leitura de uma string deve ser feita em uma variável com **espaço suficiente** para recebê-la (incluindo o '\0'), para não gerar um estouro de buffer ([[https://en.wikipedia.org/wiki/Buffer_overflow|buffer overflow]]).
Pode-se também usar a função ''fgets'':
// lê da entrada padrão até encontrar \n ou SIZE caracteres
fgets (nome, SIZE, stdin) ;
// a string lida por fgets pode incluir o \n do fim de linha,
// se ele foi encontrado; ele pode ser retirado assim:
nome[strcspn (nome, "\n")] = '\0' ;
Para mais informações sobre as funções acima, deve ser consultada a respectiva página de manual Unix.
Existe uma função de leitura ''gets()'' que não limita o número de bytes lidos e pode provocar **estouro de buffer** e problemas de segurança, por isso **não deve ser usada**! Use a função ''fgets()'' em seu lugar.
===== Manipulação =====
A manipulação de strings é geralmente efetuada através de funções disponíveis na biblioteca padrão C, que podem ser acessadas através dos arquivos de cabeçalho ''string.h'' e ''strings.h''.
Algumas das funções mais usuais são:
|< - 35% >|
^ função ^ operação realizada ^
| ''int strlen (s)'' | informa o número de caracteres da string ''s'' (sem considerar o '\0' no final) |
| ''char ∗ strcpy (b, a)'' | copia a string ''a'' no local indicado por ''b''; a área de memória de destino deve ter sido previamente alocada (como variável normal ou dinâmica) |
| ''char ∗ strdup (s)'' | Aloca uma área de memória dinâmica, copia a string ''s'' nela e devolve um ponteiro para a mesma |
| ''char ∗ strncpy (b, a, n)'' | Copia ''n'' caracteres da string ''a'' no local indicado por ''b'' |
| ''int strcmp (a, b)'' | Compara as duas strings indicadas, retornando 0 se forem iguais, um valor negativo se ab, considerando a ordem alfabética |
| ''int strncmp (a, b ,n)'' | Idem, mas só considera os ''n'' primeiros caracteres |
| ''char ∗ strcat (a, b)'' | Concatena a string ''b'' ao final da string ''a'' (deve haver espaço disponível previamente alocado) |
| ''char ∗ strncat (a, b, n)'' | Idem, mas só concatena os ''n'' primeiros caracteres |
| ''char ∗ strchr (s, c)'' | Retorna um ponteiro para a primeira ocorrência do caractere ''c'' na string ''s'', ou NULL se não encontrar |
| ''char ∗ strrchr (s, c)'' | Idem, mas retorna um ponteiro para a **última** ocorrência do caractere |
Várias outras funções para manipulação de strings estão disponíveis na [[http://man7.org/linux/man-pages/man3/string.3.html|página de manual]] (comando ''man string'') ;
===== Exercícios =====
Escrever programas em C para:
- Ler uma string da entrada padrão e escrevê-la na saída padrão ao contrário (do final para o início), de forma similar ao comando ''rev'' do //shell// UNIX.
- Calcular o tamanho de uma string (sem usar ''strlen'').
- Converter as letras de uma string em minúsculas (dica: estude a estrutura da tabela ASCII antes de implementar).
- Ler linhas da entrada padrão e escrevê-las na saída padrão em ordem alfabética crescente, de forma similar ao comando ''sort'' do //shell// UNIX.
- Remover de uma string os caracteres que não sejam letras, números ou espaço, sem usar string auxiliar.
- Remover de uma string caracteres repetidos em sequência (rr, ss, ee, etc), sem usar string auxiliar.
- Colocar entre colchetes ([ ]) os caracteres de uma string que não sejam letras, números ou espaço; as alterações devem ser feitas na própria string, sem usar string auxiliar.
- Escrever uma função ''int busca(agulha, palheiro)'', que busca a string ''agulha'' dentro da string ''palheiro'', sem usar funções prontas da biblioteca C. A função deve retornar o índice onde ''agulha'' começa em ''palheiro'', -1 se não for encontrada ou -2 em caso de erro (uma ou ambas as strings são nulas).
- Escrever sua própria versão das funções de manipulação de strings ''strlen'', ''strcpy'' e ''strcat''. Depois, comparar o desempenho de sua implementação em relação às funções originais da LibC (sugestão: meça o tempo necessário para ativar cada função um milhão de vezes).
- Escrever uma função ''palindromo(s)'' que testa [[https://pt.wikipedia.org/wiki/Pal%C3%ADndromo|palíndromos]]: ela recebe uma string ''s'' de caracteres sem acentos e retorna 1 se a string é um palíndromo ou 0 senão. Acentos, espaços em branco e maiúsculas/minúsculas devem ser ignorados. Exemplos de palíndromos:
* A cara rajada da jararaca
* O poeta ama até o pó
* Socorram-me, subi no ônibus em Marrocos!