Computadores Digitais 2 Linguagens de Programação DEL-Poli/UFRJ Prof. Miguel Campista
Aula de Hoje Cadeias de caracteres (strings) Caracteres Definição e manipulação de strings Vetor de strings Parâmetros da função main
ATENÇÃO Esta apresentação foi baseada nos seguinte trabalhos: Notas de aula do Prof. Marco Casanova da PUC-Rio http://www.inf.puc-rio.br/~inf1620/material.html Waldemar Celes, Renato Cerqueira, José Lucas Rangel, Introdução a Estruturas de Dados, Editora Campus, 2004 Herbert Schildt, C Completo e Total, Makron Books, 3 ª edição, 1997
Parte 1 Programação (linguagem C) Cadeias de Caracteres (Strings)
Caracteres Um texto é representado por uma sequência (ou cadeia) de caracteres Tipo char Caracteres são representados internamente na memória do computador por códigos numéricos 1 byte -> 256 valores distintos Tabela de códigos define a correspondência entre caracteres e códigos numéricos Ex: Tabela ASCII Caractere a -> Código 97 Caractere A -> Código 65
Tabela ASCII para alguns caracteres Normal (32 a 127), Caracteres de Controle (0 a 31) e Estendida (128 a 255) 0 1 2 3 4 5 6 7 8 9 30 us rs sp! # $ % & 40 ( ) * +, -. / 0 1 50 2 3 4 5 6 7 8 9 : ; 60 < = >? @ A B C D E 70 F G H I J K L M N O 80 P Q R S T U V W X Y 90 Z [ \ ] ^ _ ` a b c 100 d e f g h i j k l m 110 n o p q r s t u v w 120 x y z { ~ del Ç ü 130 é â ä à å ç ê ë è ï
Exemplo Primeiro printf imprime UERJ Segundo printf imprime 85698274 char a=85,b=69,c=82,d=74;... printf( %c%c%c%c \n,a,b,c,d); printf( %d%d%d%d \n,a,b,c,d);... Imprime cada variável no formato do tipo char Imprime cada variável no formato do tipo int
Caracteres Constante de caractere Caractere envolvido com aspas simples Evita a utilização de número para identificar caracteres Não é necessário consultar a tabela ASCII Reescrevendo o exemplo anterior Primeiro printf imprime UERJ Segundo printf imprime 85698274 char a= U,b= E,c= R,d= J ;... printf( %c%c%c%c \n,a,b,c,d); printf( %d%d%d%d \n,a,b,c,d);...
Exercício Crie uma função que retorne 1 se o caractere for um dígito (um dos caracteres entre 0 e 9), e 0 em caso contrário int digito(char c);
Exercício Crie uma função que retorne 1 se o caractere for um dígito (um dos caracteres entre 0 e 9), e 0 em caso contrário int digito(char c){ if ((c>= 0 ) && (c<= 9 )) return 1; else return 0; int digito(char c){ if ((c>=48) && (c<=57)) return 1; else return 0; Tiramos proveito da codificação sequencial da tabela ASCII 0 1 2 3 4 5 6 7 8 9 40 ( ) * +, -. / 0 1 50 2 3 4 5 6 7 8 9 : ;
Exercício Crie uma função que receba uma letra e retorne seu corresponde maiúsculo Caractere retornado é o mesmo do recebido se esse não for letra ou já for maiúsculo char maiuscula(char c);
Exercício char maiuscula(char c){ if ((c>= a ) && (c<= z )) c = c a + A ; return c; Deslocamento do caractere c em relação à letra a 0 1 2 3 4 5 6 7 8 9 60 A B C D E 70 F G H I J K L M N O 80 P Q R S T U V W X Y 90 Z a b c 100 d e f g h i j k l m 110 n o p q r s t u v w 120 x y z Ex. com letra e : E = e a + A 69 = 101 97 + 65
Cadeias de Caracteres (strings) Conjunto de caracteres Representação de palavras, mensagens, textos, etc. Não possuem um tipo específico em c Então, como podemos representá-las?
Cadeias de Caracteres Conjunto de caracteres (strings) Representação de palavras, mensagens, textos, etc. Não possuem um tipo específico em c Representadas por um vetor de elementos do tipo char Vetor terminado pelo caractere nulo ( \0 ) Tamanho alocado para o vetor é o número de caracteres mais o um elemento para o caractere \0 Funções de manipulação de strings Recebem como parâmetro vetor de char Processam caractere por caractere até encontrarem o valor \0
Exemplos Atribuição de cada elemento char int main(void) { char cidade[4]; cidade[0] = R ; cidade[1] = i ; cidade[2] = o ; cidade[3] = \0 ; printf( %s \n,cidade); Declaração de vetor de char Essencial para caracterizar o vetor como uma string return 0; printf com identificador de formato para strings
Exemplos Código Equivalente: Cadeia de caracteres int main(void) { char cidade[] = { R, i, o, \0 ; printf( %s \n,cidade); return 0; Como em qualquer vetor, não é necessário especificar a dimensão se todos seu elementos são inicializados
Exemplos Código Equivalente: Cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) int main(void) { char cidade[] = Rio ; printf( %s \n,cidade); return 0;
Exemplos Código Equivalente: Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) int main(void) { char cidade[4]; cidade = Rio ; Constante de cadeia de caracteres não pode ser atribuída a um vetor dessa forma!!!!! printf( %s \n,cidade); return 0;
Exemplos Alguns exemplos de declarações Conteúdo delimitado por aspas duplas ( ) char s1[] = ; string vazia, com apenas um elemento (caractere \0 ) char s2[] = Rio de Janeiro ; char s3[81]; char s4[81] = Rio ; Vetor com 15 elementos Permite strings com até 80 caracteres Apenas os 4 primeiros elementos foram inicializados
Strings Leitura de caracteres e strings Através de scanf Especificadores de formato definem o comportamento da scanf
Strings scanf com especificador de formato %c Lê o valor de um único caractere fornecido via teclado Diferente dos especificadores %d e %f, a função não ignora caracteres em branco (espaço, tabulação, nova linha) char a;... scanf( %c,&a);...
Strings scanf com especificador de formato %c Lê o valor de um único caractere fornecido via teclado Diferente dos especificadores %d e %f, a função não ignora caracteres em branco (espaço, tabulação, nova linha) char a;... scanf( %c,&a);... Se inserirmos um espaço em branco, a função ignora os caracteres em branco que antecedem a entrada do caractere
Strings scanf com especificador de formato %s Captura strings Uso muito limitado Lê somente uma sequência de caracteres não brancos char cidade[81];... scanf( %s,cidade);... Se o usuário digitasse Rio de Janeiro, apenas a string Rio seria armazenada no vetor
Strings scanf com especificador de formato %s Captura strings Uso muito limitado Lê somente uma sequência de caracteres não brancos char cidade[81];... scanf( %s,cidade);... Repare que não é necessário utilizar o especificador &, já que cidade é um vetor, possuindo um valor de endereço
Strings scanf com especificador de formato %[...] Solução mais adequada para leitura de strings Listagem entre colchetes de todos os caracteres que aceitaremos na leitura %[aeiou] -> lê sequência de vogais Leitura prossegue até se encontra um caractere que não seja vogal %[^aeiou] -> inverso do anterior Permite capturar nomes compostos char cidade[81];... scanf( %[^\n],cidade);...
Strings scanf com especificador de formato %[...] Solução mais adequada para leitura de strings Listagem entre colchetes de todos os caracteres que aceitaremos na leitura %[aeiou] -> lê sequência de vogais Leitura prossegue até se encontra um caractere que não seja vogal %[^aeiou] -> inverso do anterior Permite capturar nomes compostos char cidade[81];... scanf( %[^\n],cidade);... Procede a leitura até receber um Enter de entrada
Strings scanf com especificador de formato %[...] Solução mais adequada para leitura de strings Listagem entre colchetes de todos os caracteres que aceitaremos na leitura char cidade[81];... scanf( %[^\n],cidade);... Qual é o perigo dessa utilização??
Strings scanf com especificador de formato %[...] Solução mais adequada para leitura de strings Listagem entre colchetes de todos os caracteres que aceitaremos na leitura char cidade[81];... scanf( %[^\n],cidade);... Se o usuário digitar mais de 80 caracteres, um espaço de memória não reservado será invadido!
Strings scanf com especificador de formato %[...] Solução mais adequada para leitura de strings Listagem entre colchetes de todos os caracteres que aceitaremos na leitura char cidade[81];... scanf( %80[^\n],cidade);... Para resolver esse problema, é necessário especificar o número máximo de caracteres que serão capturados
Strings Manipulação de strings Função que retorna o comprimento de uma string int comprimento(char* s) { int i; int n = 0; /*contador*/ for (i=0; s[i]!= \0 ; i++) n++; Laço percorre caractere return n; por caractere até o final da string
Strings Utilização da função de comprimento int comprimento(char* s) { int i; int n = 0; /*contador*/ for (i=0; s[i]!= \0 ; i++) n++; return n; int main(void){ int tam; char cidade[] = Rio de Janeiro ; tam = comprimento(cidade); printf( A string \ %s\ tem %d caracteres,cidade,tam); return 0;
Strings Manipulação de strings (exercício) Faça uma função que concatene (junte) duas strings void concatena(char* dest, char* orig); dest vai receber concatenação de dest com orig Supomos que o vetor dest tem espaço suficiente para receber o vetor orig
Strings Manipulação de strings (exercício) Faça uma função que concatene (junte) duas strings void concatena(char* dest, char* orig) { int i = 0; int j; i = 0; while ( dest[i]!= \0 ) i++; for (j=0; orig[j]!= \0 ; j++){ dest[i] = orig[j]; i++; dest[i] = \0 ; Como dest pode já ter algum caractere, esse trecho verifica qual é o próximo índice disponível (concatenação irá sobrescrever o \0 original)
Strings Manipulação de strings (exercício) Faça uma função que concatene (junte) duas strings void concatena(char* dest, char* orig) { int i = 0; int j; i = 0; while ( dest[i]!= \0 ) i++; Copia os elementos a partir do elemento i for (j=0; orig[j]!= \0 ; j++){ dest[i] = orig[j]; i++; dest[i] = \0 ;
Strings Manipulação de strings (exercício) Faça uma função que concatene (junte) duas strings void concatena(char* dest, char* orig) { int i = 0; int j; i = 0; while ( dest[i]!= \0 ) i++; for (j=0; orig[j]!= \0 ; j++){ dest[i] = orig[j]; i++; dest[i] = \0 ; Finaliza a string
Manipulação de strings Strings Comparação de duas strings String s1 é maior que s2 quando O primeiro caractere no qual s1 difere de s2 possuir código ASCII maior em s1» Ex: s1 = abcde e s2= abcde s2 possuir n caracteres e os n primeiro caracteres de s1 são idênticos aos de s2, mas s1 possui mais que n caracteres» Ex: s1 = abcdef e s2= abcd Retorna 1 se s1 > s2 Retorna -1 se s1 < s2 Retorna 0 se forem iguais int compara(char* s1, char* s2) ;
Strings int compara(char* s1, char* s2) { int i; for (i=0; s1[i]!= \0 && s2[i]!= \0 ; i++){ if ( s1[i] < s2[i]) return -1; else if ( s1[i] > s2[i]) return 1; if ( s1[i]==s2[i]) return 0; else if ( s2[i]!= \0 ) return -1; else return 1; Compara caractere por caractere até o término de uma das strings São iguais pois as duas terminaram no for anterior s2 ainda não terminou, sendo assim maior que s1 s1 ainda não terminou, sendo assim maior que s2
Biblioteca Padrão do C Funções de manipulação de string #include <string.h> Algumas funções size_t strlen(const char *str) Comportamento análogo ao da função comprimento char *strcpy(char *dest, const char *src) Comportamento análogo ao da função copia Retorna o endereço da string de destino char *strcat(char *dest, const char *src) Comportamento análogo ao da função concatena Retorna o endereço da string de destino int strcmp(const char *str1, const char *str2) Comportamento análogo ao da função compara
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char cidade[4]; strcpy(cidade, Rio ); printf( %s \n,cidade); return 0; Rio é um ponteiro para posição de memória que possui a sequência de caracteres R, i, o, \0
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char *cidade; cidade = Rio ; printf( %s \n,cidade); Também é possível copiar a string dessa forma. Isso é possível pois a string Rio é um espaço alocado em memória return 0;
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char *cidade; cidade = Rio ; printf( %s \n,cidade); return 0; Como Rio é uma constante, não é possível modificar o conteúdo dos elementos de cidade. Exemplo: Não é possível fazer cidade[1] = a ;
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char *cidade = Rio ; printf( %s \n,cidade); return 0; Mesmo caso para inicialização de um ponteiro para char com a constante de string. Não é possível modificar seu conteúdo!
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char cidade[4]; cidade = Rio ; printf( %s \n,cidade); Relembrando: Se a variável for inicializada como vetor, isso não é permitido! return 0;
Strings Constante de cadeia de caracteres Conteúdo delimitado por aspas duplas ( ) Com exceção da inicialização de strings char cidade[] = Rio ; int main(void) { char cidade[4] = Rio ; cidade[1] = t ; printf( %s \n,cidade); Entretanto, vetores inicializados com uma string podem ser modificados! return 0;
Strings Cuidado!!! int main(void) { char cidade[4] = Rio ; cidade[1] = t ; printf( %s \n,cidade); return 0; Aspas duplas representam strings. Nesse exemplo t equivale a um vetor constante com os elementos t e \0. Assim, a atribuição está errada pois cidade[1] é um char
Strings Como em qualquer tipo é possível alocar dinamicamente vetores de caracteres O Código abaixo copia a string Rio para outra posição e modifica seu conteúdo int main(void) { char *cop; int n; Resultado de strlen não considera \0 n = strlen( Rio ); cop = (char*) malloc((n+1)*sizeof(char)); strcpy(cop, Rio ); Podemos modificar o vetor cop[1] = t ; cop, já que ele recebe apenas uma cópia do valor printf( %s \n,cop); constante Rio return 0;
Vetor de Strings Exemplo para armazenar os nomes dos alunos de uma turma 50 possíveis alunos Nome do aluno com até 80 caracteres #define MAX_ALUNOS 50 #define MAX_NOME 80 char alunos[max_alunos][max_nome + 1];
Vetor de Strings Função para imprimir os nomes dos alunos void imprime(int n, char alunos[][max_nome +1]) { int i; for (i=0; i<n ; i++){ printf( %s \n,alunos[i]);
Vetor de Strings Temos um desperdício de memória muito grande nessa utilização! Raramente alunos tem nomes com 80 caracteres. Mas precisamos garantir que o programa funcionará mesmo nesses casos. #define MAX_ALUNOS 50 #define MAX_NOME 80 char alunos[max_alunos][max_nome + 1]; Como fazer uma forma mais eficiente? Em cada registro de nome devemos alocar apenas a quantidade de memória necessária para ele!!
Vetor de Strings Utilização de um vetor com 81 elementos para receber o nome Alocação dinâmica de cada linha a partir do comprimento do nome Apenas uma string com tamanho máximo permitido e demais strings com o tamanho necessário!!
#include <stdio.h> #include <stlib.h> #include <string.h> #define MAX_ALUNOS 50 #define MAX_NOME 80 int main(void) { char aluno[max_nome + 1] ; char *listalunos[max_alunos]; int i; int n; int num; do{ printf( Digite o numero de Alunos \n ); scanf( %d \n,&n); while (n > MAX_ALUNOS); Variável que recebe o nome a ser alocado no vetor Vetor de ponteiros para char. Armazena cada registro dos alunos for (i=0; i<n; i++){ printf( Digite o nome do aluno %d \n,i); scanf( %MAX_NOME[^\n],aluno); num = strlen(aluno); listalunos[i] = (char*) malloc((num+1)*sizeof(char)); strcpy(listalunos[i],aluno);...
#include <stdio.h> #include <stlib.h> #include <string.h> #define MAX_ALUNOS 50 #define MAX_NOME 80 int main(void) { char aluno[max_nome + 1] ; char *listalunos[max_alunos]; int i; int n; int num; do{ printf( Digite o numero de Alunos \n ); scanf( %d \n,&n); while (n > MAX_ALUNOS); for (i=0; i<n; i++){ printf( Digite o nome do aluno %d \n,i); scanf( %MAX_NOME[^\n],aluno); Lê nome num = strlen(aluno);... listalunos[i] = (char*) malloc((num+1)*sizeof(char)); strcpy(listalunos[i],aluno);
#include <stdio.h> #include <stlib.h> #include <string.h> #define MAX_ALUNOS 50 #define MAX_NOME 80 int main(void) { char aluno[max_nome + 1] ; char *listalunos[max_alunos]; int i; int n; int num; do{ printf( Digite o numero de Alunos \n ); scanf( %d \n,&n); while (n > MAX_ALUNOS); for (i=0; i<n; i++){ printf( Digite o nome do aluno %d \n,i); scanf( %MAX_NOME[^\n],aluno);... num = strlen(aluno); Verifica o tamanho listalunos[i] = (char*) malloc((num+1)*sizeof(char)); strcpy(listalunos[i],aluno);
#include <stdio.h> #include <stlib.h> #include <string.h> #define MAX_ALUNOS 50 #define MAX_NOME 80 int main(void) { char aluno[max_nome + 1] ; char *listalunos[max_alunos]; int i; int n; int num; do{ printf( Digite o numero de Alunos \n ); scanf( %d \n,&n); while (n > MAX_ALUNOS); for (i=0; i<n; i++){ printf( Digite o nome do aluno %d \n,i); scanf( %MAX_NOME[^\n],aluno); num = strlen(aluno); listalunos[i] = (char*) malloc((num+1)*sizeof(char)); strcpy(listalunos[i],aluno);... Aloca o vetor com o número mínimo suficiente de caracteres
#include <stdio.h> #include <stlib.h> #include <string.h> #define MAX_ALUNOS 50 #define MAX_NOME 80 int main(void) { char aluno[max_nome + 1] ; char *listalunos[max_alunos]; int i; int n; int num; do{ printf( Digite o numero de Alunos \n ); scanf( %d \n,&n); while (n > MAX_ALUNOS); for (i=0; i<n; i++){ printf( Digite o nome do aluno %d \n,i); scanf( % MAX_NOME[^\n],aluno); num = strlen(aluno); listalunos[i] = (char*) malloc((num+1)*sizeof(char)); strcpy(listalunos[i],aluno);... Copia o nome para o vetor
Parâmetros da função main Muitas Vezes é útil passar parâmetros para programas Evita a necessidade de pedir para os usuários digitarem Facilita a automatização da execução do programa Exemplo: Comando ping: envia sondas para algum servidor na Internet Verificação de alcançabilidade, atraso e perda de pacotes
Parâmetros da função main Indica o número de parâmetros passados int main(int argc ; char** argv) { int i; for (i=0; i<argc; i++) printf( %s \n,argv[i]); return 0;
Parâmetros da função main Vetor de strings. Cada string é um argumento. int main(int argc ; char** argv) { int i; argv[0] é sempre o nome do programa for (i=0; i<argc; i++) printf( %s \n,argv[i]); return 0;
Parâmetros da função main int main(int argc ; char** argv) { int i; Programa desse exemplo imprime todos os for (i=0; i<argc; i++) argumentos printf( %s \n,argv[i]); return 0;
Parâmetros da função main Algumas funções auxiliares int atoi(const char *str) Converte o valor da string str para inteiro double atof(const char *str) Converte o valor da string str para double