====== 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!