Prévia do material em texto
INTRODUÇÃO A FUNÇÕES 1. INTRODUÇÃO À FUNÇÕES Uma função é um bloco de código de programa que pode ser usado diversas vezes em sua execução. O uso de funções permite que o programa fique mais legível, mais bem estruturado. Um programa em C consiste, no fundo, de várias funções colocadas juntas. Veja abaixo o tipo mais simples de função: 1. #include 2. int mensagem() /* função mais simples: só imprime Olá! */ 3. { 4. printf ("Olá!\n"); 5. return 0; 6. } 7. int main () 8. { 9. mensagem(); 10. printf ("Eu estou vivo!\n"); 11. return 0; 12. } Este programa irá apresentar na tela a mensagem Olá! em uma linha e Eu estou vivo! em outra. O que ele faz é definir uma função mensagem() que coloca uma string na tela e retorna 0. Esta função é chamada a partir de main(), que, como já vimos, também é uma função. A diferença fundamental entre main e as demais funções do problema é que main é uma função especial, cujo diferencial é o fato de ser a primeira função a ser executada em um programa. 1.1. ARGUMENTOS E PARÂMETROS Vimos acima um exemplo de função que exibe uma mensagem na tela. As funções não são estáticas assim, e não fazem somente isso. Através de parâmetros e argumentos, pode-se enviar dados para as funções trabalharem e fazerem algo mais útil para nossos programas. Parâmetros são canais pelos quais se estabelece uma comunicação bidirecional entre uma função e o algoritmo chamador. Dados são passados pelo algoritmo, ou retornados por este ao primeiro por meio de parâmetros. Assim, parâmetros são variáveis que a função recebe. O número e tipo de parâmetros são pré-estabelecidos na declaração da função. E essa declaração, dos tipos e nomes das variáveis, acontece dentro dos parênteses. Por exemplo, se formos criar uma função que recebe e soma dois números, declaramos a função com os tipos de variáveis (inteiro ou float, por exemplo) e o nome dessas variáveis. void soma(int a, int b) { } Pronto, declaramos uma função com dois parâmetros. Agora, dentro dessa função, podemos usar a e b. É como se elas tivessem sido declaradas entre parênteses. E quais os valores desses parâmetros? São os que serão passados à função pelo algoritmo principal. Esses valores são os argumentos. Por exemplo, se a função soma(1,2) é invocada, os argumentos passados são 1 e 2. Dessa forma, os parâmetros a e b vão receber os valores 1 e 2, respectivamente. Ou seja, o valor que aparece primeiro é armazenado no primeiro parâmetro, o segundo valor é armazenado no segundo parâmetro e assim sucessivamente. Note agora que essas funções não são estáticas. Elas mudam de acordo com os valores que são passados à elas. Assim, argumentos são as entradas que a função recebe. É através dos argumentos que passamos parâmetros para a função. Já vimos funções com argumentos. As funções printf() e scanf() são funções que recebem argumentos. Observe abaixo um outro exemplo simples de função com argumentos: 1. #include 2. int square (int x) /* calcula o quadrado de x */ 3. { 4. printf ("O quadrado é %d",(x*x)); 5. return 0; 6. } 7. int main () 8. { 9. int num; 10. printf ("Entre com um número: "); 11. scanf ("%d",&num); 12. printf ("\n\n"); 13. square(num); 14. return 0; 15. } Na definição de square(), dizemos que a função receberá um argumento inteiro x. Quando fazemos a chamada à função, o inteiro num é passado como argumento. Há alguns pontos a serem observados. Em primeiro lugar, temos de satisfazer aos requisitos da função quanto ao tipo e à quantidade de argumentos quando a chamamos. Apesar de existirem algumas conversões de tipo, que o C faz automaticamente, é importante ficarmos atento. Em segundo lugar, não é importante o nome da variável que se passa como argumento, ou seja, a variável num, ao ser passada como argumento para square() é copiada para a variável x. Dentro de square() trabalha-se apenas com x. Se mudarmos o valor de x dentro de square(), o valor de num na função main() permanece inalterado. Vamos dar um exemplo de função de mais de uma variável. Repare que, neste caso, os argumentos são separados por vírgula e que deve-se explicitar o tipo de cada um dos argumentos, um a um. Note, também, que os argumentos passados para a função não necessitam ser todos variáveis porque mesmo sendo constantes serão copiados para a variável de entrada da função. 1. #include 2. int mult (float a, float b, float c) /* multiplica 3 números */ 3. { 4. printf ("%f",a*b*c); 5. return 0; 6. } 7. int main () 8. { 9. float x,y; 10. x=23.5; 11. y=12.9; 12. mult (x,y,3.87); 13. return 0; 14. } 1.2. RETORNANDO VALORES Muitas vezes é necessário fazer com que uma função retorne um valor. As funções que vimos até aqui estavam retornando o número 0. Podemos especificar um tipo de retorno indicando-o antes do nome da função. Mas para dizer ao C o que vamos retornar precisamos da palavra reservada return. Sabendo disto fica fácil fazer uma função para multiplicar dois inteiros e que retorna o resultado desta multiplicação. Observe: 1. #include 2. int prod (int x, int y) 3. { 4. return (x*y); 5. } 6. int main () 7. { 8. int saida; 9. saída = prod(12,7); 10. printf ("A saida é: %d\n",saida); 11. return(0); 12. } Observe que, como prod retorna o valor de 12 multiplicado por 7, este valor pode ser usado em uma expressão qualquer. No programa, fizemos a atribuição deste resultado à variável saida, que posteriormente foi impressa usando printf(). Uma observação adicional: se não especificarmos o tipo de retorno de uma função, o compilador C automaticamente irá supor que este tipo é inteiro. Porém, não é uma boa prática não se especificar o valor de retorno. Com relação à função main(), o retorno sempre será inteiro. Normalmente faremos a função main retornar um zero quando ela é executada sem qualquer tipo de erro. Observe um outro exemplo de função que recebe dois valores floats e também retorna um float. 1. #include 2. float prod (float x, float y) 3. { 4. return (x*y); 5. } 6. int main () 7. { 8. float saida; 9. saída = prod(45.2,0.0067); 10. printf ("A saida é: %f\n",saida); 11. return(0); 12. } 1.3. SINTAXE BÁSICA Apresentamos aqui a sintaxe básica de uma função: tipo_de_retorno nome_da_função (lista_de_parâmetros) { bloco_de_comandos; } 2. INSTRUÇÕES PRIMITIVAS Como o próprio nome diz, instruções primitivas são os comandos básicos que efetuam tarefas essenciais para a operação dos computadores, como entrada e saída de dados (comunicação com o usuário e com dispositivos periféricos), e movimentação dos mesmos na memória. Estes tipos de instrução estão presentes na absoluta maioria das linguagens de programação. Antes de passar à descrição das instruções primitiva, é necessária a definição de alguns termos que serão utilizados: ✓ dispositivo de entrada é o meio pelo qual as informações (mais especificamente os dados) são transferidos pelo usuário ou pelos níveis secundários de memória ao computador. Os exemplos mais comuns são o teclado, o mouse, leitora ótica, leitora de código de barras, as fitas e discos magnéticos. ✓ dispositivo de saída é o meio pelo qual as informações (geralmente os resultados da execução de um programa) são transferidos pelo computador ao usuário ou aos níveis secundários de memória. Os exemplos mais comuns são o monitor de vídeo, impressora, fitas e discos magnéticos. ✓ sintaxe é a forma como os comandos devem ser escritos, a fim de que possam ser entendidos pelo tradutor de programas. A violação das regras sintáticas é considerada um erro sujeito à pena do não reconhecimento por parte do tradutor ✓ semântica é o significado, ou seja, o conjuntocalcula o arco seno ✓ atan: calcula o arco tangente ✓ atan2: calcula o arco tangente com dois parâmetros Funções hiperbólicas ✓ cosh: calcula o cosseno hiperbólico de um ângulo em radianos ✓ sinh: calcula o seno hiperbólico de um ângulo em radianos ✓ tanh: calcula a tangente hiperbólica de um ângulo em radianos Funções exponenciais e logarítmicas ✓ exp: função exponencial ✓ log: logaritmo natural ✓ log10: logaritmo comum (base 10) ✓ modf: quebra um número em partes fracionárias e inteira Funções de potência ✓ pow: retorna a base elevada ao expoente ✓ sqrt: raiz quadrada de um número Funções de arredondamento, valor absoluto e outras ✓ ceil: arredonda para cima um número ✓ fabs: calcula o valor absoluto de um número ✓ floor: arredonda para baixo um número ✓ fmod: calcula o resto da divisão 4.4. FUNÇÕES DE TESTES DE TIPOS DE CARACTERES Arquivo-cabeçalho: ctype.h ✓ isalnum: verifica se o caractere é alfanumérico ✓ isalpha: verifica se o caractere é alfabético ✓ iscntrl: verifica se o caractere é um caractere de controle ✓ isdigit: verifica se o caractere é um dígito decimal ✓ islower: verifica se o caractere é letra minúscula ✓ isprint: verifica se caractere é imprimível ✓ ispunct: verifica se é um caractere de pontuação ✓ isspace: verifica se caractere é um espaço em branco ✓ isupper: verifica se o caractere é letra maiúscula ✓ isxdigit: verifica se o caractere é dígito hexadecimal ✓ tolower: converte letra maiúscula para minúscula ✓ toupper: converte letra minúscula para maiúscula 4.5. FUNÇÕES DE OPERAÇÕES COM STRINGS Arquivo-cabeçalho: string.h Cópia ✓ memcpy: cópia de bloco de memória ✓ memmove: move bloco de memória ✓ strcpy: cópia de string ✓ strncpy: cópia de caracteres da string Concatenação ✓ strcat: concatenação de strings ✓ strncat: adiciona “n” caracteres de uma string no final de outra string Comparação ✓ memcmp: compara dois blocos de mem´ oria ✓ strcmp: compara duas strings ✓ strncmp: compara os “n” caracteres de duas strings Busca ✓ memchr: localiza caractere em bloco de memória ✓ strchr: localiza primeira ocorrência de caractere em uma string ✓ strcspn: retorna o número de caracteres lidos de uma string antes da primeira ocorrência de uma segunda string ✓ strpbrk: retorna um ponteiro para a primeira ocorrência na string de qualquer um dos caracteres de uma segunda string ✓ strrchr: retorna um ponteiro para a última ocorrência do caratere na string ✓ strspn: retorna o comprimento da string que consiste só de caracteres que fazem parte de uma outra string ✓ strtok: divide uma string em sub-strings com base em um caractere Outras ✓ memset: preenche bloco de memória com valor especificado ✓ strerror: retorna o ponteiro para uma string de mensagem de erro ✓ strlen: comprimento da string 4.6. FUNÇÕES DE MANIPULAÇÃO DE INTERFACE Arquivo-cabeçalho: conio.h ✓ clrscr: limpa limpa a tela e move o cursor para a posição (1,1) ✓ gotoxy(int x, int y): posiciona o cursor na tela nas coordenadas x e y. Se as coordenadas são invalidas, a função gotoxy é ignorada ✓ getch:lê um caractere do teclado e não o mostra na tela ✓ getche: lê um caractere do teclado e o mostra na tela ✓ kbhit: testa se alguma tecla foi apertada ✓ delline: apaga a linha que contem o cursor e move todas as linhas abaixo dela uma linha para cima ✓ textcolor (int cor): muda a cor do texto ✓ textbackground (int cor): muda a cor do fundo 4.7. FUNÇÕES DE DATA E HORA Arquivo-cabeçalho: time.h Manipulação do tempo ✓ clock: retorna o número de pulsos de clock decorrido desde que o programa foi lançado ✓ difftime: retorna a diferença entre dois tempos ✓ mktime: converte uma estrutura tm para o tipo time_t ✓ time: retorna o tempo atual do calendário como um time_t Conversão ✓ asctime: converte uma estrutura tm para string ✓ ctime: converte um valor time_t para string ✓ gmtime: converte um valor time_t para estrutura tm como tempo UTC ✓ localtime: converte um valor time_t para estrutura tm como hora local ✓ strftime: formata tempo para string Tipos e macros ✓ clock_t: tipo capaz de representar as contagens clock e suportar operações aritméticas ✓ size_t: tipo inteiro sem sinal ✓ time_t: tipo capaz de representar os tempos e suportar operações aritméticas ✓ struct_tm: estrutura contendo uma data e hora dividida em seus componentes ✓ CLOCKS_PER_SEC: número de pulsos de clock em um segundode ações que serão exercidas pelo computador durante a execução do referido comando. Daqui em diante, todos os comandos novos serão apresentados por meio de sua sintaxe e sua semântica, isto é, a forma como devem ser escritos e as ações que executam. 2.1. COMANDO DE ATRIBUIÇÃO O comando de atribuição ou simplesmente atribuição, é a principal maneira de armazenar uma informação numa variável. Sua sintaxe é: nome_da_variável = expressão; Exemplos: nome = “Genoveva”; preco = 15.85; quant = 5; total = preco * quant; O modo de funcionamento (semântica) de uma atribuição consiste: 1. na avaliação da expressão 2. no armazenamento do valor resultante na variável que aparece à esquerda do comando. A seguir temos um exemplo de um algoritmo utilizando o comando de atribuição: 1. #include 2. #include 3. int main() 4. { 5. float preco_unit, preco_tot; 6. int quant; 7. preco_unit = 5.0; 8. quant = 10; 9. preco_tot = preco_unit * quant; 10. printf(“Preço total = %f\n”,preco_tot); 11. return 0; 12. } 2.2. COMANDOS DE SAÍDA DE DADOS Os comandos de saída de dados são o meio pelo qual informações contidas na memória dos computadores são colocadas nos dispositivos de saída, para que os usuários possam apreciá-las. Em linguagem de programação C, uma das funções responsáveis por essa operação é printf(). 2.2.1. PRINTF() A função printf() é uma das funções de saída/escrita de dados da linguagem C. Seu nome vem da expressão em inglês print formatted, ou seja, escrita formatada. Basicamente, a função printf() escreve na saída de vídeo (monitor) um conjunto de valores, caracteres e/ou sequência de caracteres de acordo com o formato especificado. A sintaxe básica da função é: printf(“texto”); ou printf(“expressão_de_controle”, lista_de_argumentos); A função printf() pode ser usada quando queremos escrever apenas um texto simples na tela, ou ainda pode receber dois parâmetros de entrada: ✓ “expressão de controle”: conjunto de caracteres que especifica o formato dos dados a serem escritos e/ou o texto a ser escrito; ✓ lista de argumentos: conjunto de nomes de variáveis, separados por vírgula, que serão escritos. Quando queremos escrever dados formatados na tela usamos a segunda sintaxe básica apresentada, a qual possui a expressão de controle. Ela especifica o formato de saída dos dados Saída: Preço total = 50.000000 que serão escritos pela função. Cada formato de saída é precedido por um sinal de % e um código de controle deve ser especificado para cada variável a ser escrita. Assim, se quiséssemos escrever uma única expressão com o comando printf(), a sintaxe correta seria: printf(“%código”, expressão); Se fossem duas as expressões a serem escritas, a sintaxe correta seria: printf(“%código1 %código2”, expressão1, expressão2); E assim por diante. Note que os formatos e as expressões a serem escritas com aquele formato devem ser especificados na mesma ordem, como mostrados pelas setas acima. Diferente do comando scanf(), o comando printf() não exige o símbolo & na frente do nome de uma variável que será escrita na tela. Se usado, ele possui outro significado e não exibe o conteúdo da variável. A função printf() pode ser usada para escrever virtualmente qualquer tipo de dado. A tabela abaixo mostra alguns dos tipos de saída suportados pela linguagem e seus respectivos códigos de controle: Código Tipo de argumento Descrição %d int valor inteiro decimal %i int valor inteiro decimal %o int valor inteiro octal %x int valor inteiro hexadecimal %X int valor inteiro hexadecimal %u int valor inteiro decimal sem sinal (unsigned int) %c char um caractere em formato ASCII (código binário correspondente) %s char uma cadeia de caracteres (string) terminada em “\0” %f float valor em ponto flutuante no formato [-]m.dddddd, onde o número de casas decimais é dado pela precisão (padrão é 6) %e float ou double valor em ponto flutuante em notação exponencial no formato [-]m.ddddd e±xx, onde o número de casas decimais é dado pela precisão %E float ou double valor em ponto flutuante em notação exponencial no formato [-]m.ddddd E±xx, onde o número de casas decimais é dado pela precisão %g float ou double valor em ponto flutuante no formato %e (quando o expoente for menor que -4 ou igual a precisão) ou %f (nos demais casos); zeros adicionais e um ponto decimal final não são impressos %G float ou double valor em ponto flutuante no formato %E (quando o expoente for menor que -4 ou igual a precisão) ou %f (nos demais casos); zeros adicionais e um ponto decimal final não são impressos %% - exibe o caracter “%” Observe abaixo alguns exemplos de escrita de dados utilizando o comando printf(). 1. #include 2. #include 3. int main() 4. { 5. int x = 10; 6. printf(“%d\n”,x); 7. float y = 5.0; 8. printf(“%d%f\n”,x,y); 9. printf(“%d %f\n”,x,y); 10. return 0; 11. } No exemplo acima, os comandos nas linhas 08 e 09 imprimem os mesmos dados, mas o segundo os separa com um espaço em branco, como pode ser observado na saída. Isso ocorre por que o comando printf() aceita textos junto aos códigos de controle. Pode-se adicionar texto antes, depois ou entre dois ou mais códigos de controle. Observe: printf(“texto %código texto”, expressão); Junto ao código de controle, pode-se adicionar texto e não apenas espaços em branco, conforme mostrado no exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. int x = 10; Saída: 10 105.000000 10 5.000000 Saída: Total = 10 10 caixas! Total de 10 caixas!!! 6. printf(“Total = %d\n”,x); 7. printf(“%d caixas!\n”,x); 8. printf(“Total de %d caixas!!!n”,x); 9. return 0; 10. } Isso permite que o comando printf() seja usado para escrever não apenas dados, mas sentenças que façam sentido para o usuário do programa. Isso é um requisito fundamental na construção e implementação de interfaces em um programa amigo do usuário. 2.2.2. PUTCHAR() A função putchar() – put character – permite escrever um único caractere na tela. A sintaxe geral dessa função é a seguine: putchar(variável); A função putchar() recebe como parâmetro de entrada um único valor inteiro. Esse valor será convertido para caractere e mostrado na tela. A função retorna, caso não ocorra nenhum erro, o próprio caractere que foi escrito e, caso ocorra algum erro, a constante EOF (definida no arquivo- cabeçalho stdio.h) é retornada. Observe o exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. char c = ‘a’; 6. int x = 65; 7. putchar(c); 8. putchar(‘\n’); 9. putchar(x); 10. putchar(‘\n’); 11. return 0; 12. } Perceba, no exemplo acima, que a conversão na linguagem C é direta no momento da impressão, ou seja, o valor 65 é convertido para o caractere ASCII correspondente, no caso, o caractere “A”. Além disso, o comando putchar() também aceita o uso de sequências de escape como o caractere ‘\n’ (nova linha). Saída: a A 2.2.3. PUTS() A função puts() – put string – apresenta na tela a string passada como argumento, seguida de uma nova linha (\n). Ela retorna um valor não negativo se houver sucesso no processo ou, caso contrário, retorna EOF. A sintaxe básica dessa função é a seguinte: puts(string); Esta função reconhece os mesmos caracteres especiais de escape que a função printf(). Entretanto, uma chamada à função puts() requer menos esforço de processamento que a mesma chamada para a função printf(), uma vez que a primeira pode enviar somente strings, enquanto que a segunda, além de strings, pode enviar outros tipos de dados, bem como fazer conversão de formatos.Portanto, a função puts() ocupa menos espaço de memória e é executada mais rapidamente que a função printf(). Observe abaixo um exemplo de sua utilização. 1. #include 2. void main(void) 3. { 4. char STRING[10]; 5. puts(“Exemplo de utilização da função puts.\n Entre com uma string:”); 6. gets(STRING); 7. puts(“\n A string digitada foi:”); 8. puts(STRING); 9. } 2.2.4. RECURSOS AVANÇADOS DA FUNÇÃO PRINTF() A função printf() é uma das funções de saída/escrita de dados da linguagem C. Sua funcionalidade básica é escrever na saída de vídeo (tela) um conjunto de valores, caracteres e/ou sequência de caracteres de acordo com o formato especificado. Porém, essa função permite uma variedade muito maior de formatações do que as vistas até então. Observe a definição geral da função. A função printf() possui o seguinte protótipo: int printf(“expressão_de_controle”, lista_de_argumentos) A função printf() recebe dois parâmetros de entrada: ➢ expressão_de_controle → conjunto de caracteres que especifica o formato dos dados a serem escritos e/ou o texto a ser escrito; ➢ lista_de_argumentos → conjunto de nomes de variáveis, separados por vírgula, que serão escritos; e retorna: ➢ um valor inteiro que representa o número total de caracteres escritos na tela, em caso de sucesso; ➢ um valor negativo, em caso de erro da função. O valor de retorno da função printf() permite identificar o funcionamento adequado da função. Foi visto que quando se quer escrever dados formatados na tela, usa-se a expressão_de_controle para especificar o formato de saída dos dados que serão escritos. E que cada expressão de controle é precedida por um sinal de % e um código de controle deve ser especificado para cada variável a ser escrita. A string da expressão_de_controle permite especificar mais características dos dados além do formato. Essas características são opcionais e são: flag, largura, precisão e comprimento. A ordem em que essas quatro características devem ser especificadas é a seguinte: %[flag][largura][.precisão][comprimento]código_de_controle Note que o campo precisão vem sempre começando com um caractere de ponto (.). Como a expressão_de_controle, cada uma dessas características possui um conjunto de valores pré- definidos e suportados pela linguagem. Observe nas seções seguintes, todos os valores suportados para cada uma das características de formatação possíveis. 2.2.4.1. Expressão de Controle A função printf() pode ser usada para escrever virtualmente qualquer tipo de dado. A tabela abaixo mostra todos os tipos de saída suportados pela linguagem C. Observe: Código Descrição %c um caractere %d ou %i números inteiros com sinal %u números inteiros sem sinal %f números reais (float e double) %s vários caracteres (string) %p endereço de memória (ponteiro) %e ou %E números reais em notação científica %x números inteiros sem sinal no formato hexadecinmal (minúsculo) %X números inteiros sem sinal no formato hexadecinmal (maiúsculo) %o números inteiros sem sinal no formato octal %g números reais; compilador decide se é melhor usar %f ou %e %G números reais; compilador decide se é melhor usar %f ou %E %% exibe o caracter “%” A seguir, são apresentados alguns exemplos de como cada expressão de controle pode ser utilizada para escrever determinado dado na tela. Exibindo os tipos básicos A linguagem C possui vários tipos de saída que podem ser utilizados com os tipos básicos, ou seja, char (“%c” e “%d”), int (“%d” e “%i”), float e double (“%f”), e por fim array de char ou string (“%s”). Note que o tipo char pode ser escrito na tela de saída por meio dos operadores “%c” e “%d”. Nesse caso, “%c” irá imprimir o caractere armazenado na variável, enquanto “%d” irá imprimir o seu valor na tabela ASCII. Abaixo, tem-se alguns exemplos de escrita dos tipos básicos: 1. #include 2. #include 3. int main() 4. { 5. int n=125; 6. float f=5.25; 7. double d=10.53; 8. char letra='a'; 9. char palavra[10]="programa"; 10. printf("Valor inteiro: %d\n", n); 11. printf("Valor inteiro: %i\n", n); 12. printf("Valor real: %f\n", f); 13. printf("Valor real: %f\n", d); 14. printf("Caractere: %c\n", letra); 15. printf("Valor numérico do caractere: %d\n", letra); 16. printf("Palavra: %s\n", palavra); 17. return 0; 18. } Exibindo valores no formato octal ou hexadecimal O exemplo abaixo mostra como exibir um valor inteiro nos formatos octal (base 8) ou hexadecimal (base 16). Para isso, usamos a expressão de controle “%o” (sinal de porcentagem mais a letra “o”, não o zero “0”) para que a função printf() exiba o valor em octal, e “%x” para hexadecimal com letras minúsculas e “%X” para hexadecimal com letras maiúsculas. Saída: Valor inteiro: 125 Valor inteiro: 125 Valor real: 5.250000 Valor real: 10.530000 Caractere: a Valor numérico do caractere: 97 Palavra: programa Observe: 1. #include 2. #include 3. int main() 4. { 5. int n=125; 6. printf("Valor de n: %d\n", n); 7. printf("Valor em octal: %o\n", n); 8. printf("Valor em hexadecimal: %x\n", n); 9. printf("Valor em hexadecimal: %X\n", n); 10. return 0; 11. } Exibindo valores como notação científica O exemplo abaixo mostra como exibir um valor real (também chamado ponto flutuante) no formato de notação científica. Para isso, usamos as expressões de controle “%e” ou “%E”, sendo que o primeiro usará a letra E minúscula enquanto o segundo usará ela maiúscula na saída. Temos também as expressões de controle “%g” e “%G”. Essas expressões de controle, quando utilizadas, deixam para o compilador decidir se é melhor usar “%f” ou “%e” (ou “%E”, se for utilizado “%G”). Nesse caso, o compilador usa “%e” (ou “%E”) para que números muito grandes ou muito pequenos sejam mostrados na forma de notação científica. Observe o exemplo abaixo. 1. #include 2. #include 3. int main() 4. { 5. float f=0.00000025; 6. double d=10.53; 7. printf("Valor real: %e\n", f); 8. printf("Valor real: %E\n", f); 9. printf("Valor real: %g\n", d); 10. printf("Valor real: %G\n", f); 11. return 0; 12. } Saída: Valor de n: 125 Valor em octal: 175 Valor em hexadecimal: 7d Valor em hexadecimal: 7D Saída: Valor real: 2.500000e-007 Valor real: 2.500000E-007 Valor real: 10.53 Valor real: 2.5E-007 Exibindo valores inteiros sem sinal e endereços Para imprimir valores inteiros sem sinal, devemos utilizar a expressão de controle “%u” e evitar o uso do código “%d”. Isso ocorre por que o tipo “%u” trata o número inteiro como unsigned (sem sinal), enquanto “%d” o trata como signed (com sinal). A primeira vista os dois códigos podem parecer iguais. Se o valor inteiro estiver entre 0 e INT_MAX (231 – 1, em sistemas de 32 bits), a saída será idêntica para os dois casos (“%d” e “%u”). Porém, se o valor inteiro for negativo (para entradas com sinal, signed) ou estiver entre INT_MAX e UINT_MAX (isto é, entre 231 – 1 e 232 – 1, em sistemas de 32 bits), os valores impressos pelos tipos “%d” e “%u” serão diferentes. Neste caso, o tipo “%d” irá imprimir um valor negativo, enquanto o tipo “%u” irá imprimir um valor positivo. Já para imprimir o endereço de memória de uma variável ou ponteiro, podemos utilizar o tipo de saída “%p”. Esse tipo de saída irá imprimir o endereço no formato hexadecimal, sendo que o valor impresso depende do compilador e da plataforma. O endereço de memória poderia ser também impresso por meio do tipo “%x” (ou “%X”), porém, esse tipo de saída pode gerar uma impressão incorreta do valor do endereço, principalmente em sistemas 64-bit. Observe o exemplo abaixo. 1. #include 2. #include 3.int main() 4. { 5. unsigned int n=2147483647; 6. printf("Valor real: %d\n", n); 7. printf("Valor real: %u\n", n); 8. n = n + 1; 9. printf("Valor real: %d\n", n); 10. printf("Valor real: %u\n", n); 11. printf("Endereço de n: %p\n", &n); 12. return 0; 13. } Exibindo o símbolo “%” O caractere “%” é normalmente utilizado dentro da função printf() para especificar o formato de saída em que um determinado dado será escrito. Porém, pode ser as vezes necessário imprimir o caractere “%” na tela de saída. Para realizar essa tarefa, basta colocar dois caracteres “%”, “%%”, para que ele seja impresso na tela de saída, como mostrado no exemplo abaixo. Saída: Valor real: 2147483647 Valor real: 2147483647 Valor real: -2147483647 Valor real: 2147483647 Endereço de n: 0029FF0C 1. #include 2. #include 3. int main() 4. { 5. printf("Juros de 25%%\n"); 6. return 0; 7. } 2.2.4.2. Flags As flags permitem adicionar características extras a um determinado formato de saída utilizado com a função printf(). Elas vem logo em seguida ao sinal de % e antes do código de controle. A tabela abaixo mostra todas as flags suportadas pela linguagem C. Observe: Flags Descrição - imprime o valor justificado à esquerda dentro da largura determinada pelo campo largura; por padrão, o valor é sempre justificado à direita + imprime o símbolo de sinal (+ ou -) antes do valor impresso, mesmo para números positivos; por padrão, apenas os números negativos são impressos com o sinal (espaço) imprime o valor com espaços em branco à esquerda dentro da largura determinada pelo campo largura # se usado com os tipos “%o”, “%x” ou “%X”, o valor impresso é precedido de “0”, “0x” ou “0X”, respectivamente, para valores diferentes de zero; se usado com valores do tipo float e double, imprime o ponto decimal mesmo se nenhum dígito vir em seguida; por padrão, se nenhum dígito for especificado, nenhum ponto decimal é escrito 0 imprime o valor com zeros (0) em vez de espaços à esquerda dentro da largura determinada pelo campo largura Justificando um valor à esquerda O exemplo abaixo mostra o uso das flags para justificar os dados na tela de saída. Note que para justificar um valor é preciso definir o valor da largura, isto é, a quantidade mínima de caracteres que se poderá utilizar durante a impressão na tela de saída. No caso, definimos que a largura são 5 caracteres. Saída: Juros de 25% Observe: 1. #include 2. #include 3. int main() 4. { 5. int n=5; 6. //justifica à direita 7. printf("N = %5d\n", n); 8. //justifica à esquerda 9. printf("N = %-5d\n", n); 10. return 0; 11. } Forçando a impressão do sinal do número Por padrão, a função printf() imprime apenas os números negativos com o sinal. No entanto, pode-se forçar a impressão do sinal de positivo, como mostrado no exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. int n=5; 6. //sem sinal 7. printf("N = %d\n", n); 8. //com sinal 9. printf("N = %+d\n", n); 10. return 0; 11. } Imprimindo espaços ou zeros antes de um número Quando definimos a largura do valor, estamos definindo a quantidade mínima de caracteres que será utilizada durante a impressão na tela de saída. Por padrão, a função printf() justifica os dados à direita e preenche o restante da largura com espaços. Porém, pode-se preencher o restante da largura com zeros, como mostrado no exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. int n=5; 6. //com espaços (padrão) 7. printf("N = % 5d\n", n); 8. //com zeros 9. printf("N = %05d\n", n); 10. return 0; 11. } Saída: N = 5 N = 5 Saída: N = 5 N = +5 Saída: N = 5 N = 00005 Imprimindo o prefixo hexadecimal e octal e o ponto Por padrão, a função printf() imprime valores no formato octal e hexadecimal sem os seus prefixo (0 e 0x, respectivamente). Já o ponto decimal dos valores em ponto flutuante é omitido caso não se tenha definido a precisão, apesar de ter sido incluído na sua formatação, o indicador de ponto (“.”). Felizmente, pode-se forçar a impressão do prefixo e do ponto, como mostrado no exemplo abaixo. 1. #include 2. #include 3. int main() 4. { 5. int n=125; 6. //octal e hexadecimal sem prefixo 7. printf("N = %o\n", n); 8. printf("N = %X\n", n); 9. //octal e hexadecimal com prefixo 10. printf("N = %#o\n", n); 11. printf("N = %#X\n", n); 12. float x = 5.00; 13. //float padrão 14. printf("X = %f\n", x); 15. //float sem ponto 16. printf("X = %.f\n", x); 17. //float com ponto 18. printf("X = %#.f\n", x); 19. return 0; 20. } 2.2.4.3. Largura O campo largura é comumente usado com outros campos (como visto com as flags). Ele na verdade especifica o número mínimo de caracteres a serem impressos na tela de saída. Ele pode ser definido de duas maneiras, como mostrado na tabela abaixo: Largura Descrição “número” número mínimo de caracteres a serem impressos; se a largura do valor a ser impresso é inferior a este número, espaços em branco serão acrescentados a esquerda * informa que a largura vai ser especificada por um valor inteiro passado como parâmetro para a função printf() Saída: N = 175 N = 7D N = 0175 N = 0x7D X = 5.000000 X = 5 X = 5. Observe abaixo um exemplo de uso do campo largura. 1. #include 2. #include 3. int main() 4. { 5. int n=125; 6. int largura=10; 7. //largura definida dentro do campo 8. printf("N = %10d\n", n); 9. //largura definida por uma variável inteira 10. printf("N = %*d\n", largura,n); 11. return 0; 12. } 2.2.4.4. Precisão O campo precisão é comumente usado com valores de ponto flutuante (tipos float e double). De modo geral, esse campo especifica o número de caracteres a serem impressos na tela de saída após o ponto decimal. Porém, o campo precisão pode ser utilizado com outros tipos, como mostrado na tabela abaixo. Precisão Descrição .número ➢ para os tipos “%d”, “%i”, “%u”, “%o”, “%x” e “%X”: número mínimo de caracteres a serem impressos; se a largura do valor a ser impresso é inferior a este número, zeros serão acrescentados a esquerda ➢ para os tipos “%f”, “%e” e “%E”: número de dígitos a serem impressos após o ponto decimal; ➢ para os tipos “%g” e “%G”: número máximo de dígitos significativos a serem impressos ➢ para o tipo “%s”: número máximo de caracteres a serem impressos; por padrão, todos os caracteres são impressos até que o caractere “\0” seja encontrado ➢ para o tipo “%c”: sem efeito ➢ se nenhum valor for especificado para a precisão, a precisão é considerada 0 (padrão) .* informa que a largura vai ser especificada por um valor inteiro passado como parâmetro para a função printf() Note que o campo precisão vem sempre começando com um caractere de ponto (.). Saída: N = 125 N = 125 O campo precisão para valores inteiros O campo precisão, quando usado com valores inteiros (pode ser também no formato octal ou hexadecimal), funciona de modo semelhante à largura do campo, ou seja, especifica o número mínimo de caracteres a ser impressos, com a vantagem de já preencher o restante dessa largura com zeros, como mostrado no exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. int n=125; 6. printf("N = %.8d (decimal)\n", n); 7. printf("N = %.8o (octal)\n", n); 8. printf("N = %.8X (hexadecimal)\n", n); 9. return 0; 10. } O campo precisão para valores reais O campo precisão, quando usado com valores de ponto flutuante (tipos float e double), especifica o númerode caracteres a serem impressos na tela de saída após o ponto decimal. A única exceção é com as expressões de controle “%g” e “%G”. Nesse caso, o campo precisão especifica o número máximo de caracteres a serem impressos. Observe abaixo um exemplo. 1. #include 2. #include 3. int main() 4. { 5. float n=123.45678; 6. printf("N = %.3f\n", n); 7. printf("N = %.5f\n", n); 8. printf("N = %.5e\n", n); 9. printf("N = %.5g\n", n); 10. return 0; 11. } O campo precisão usado com strings O campo precisão também permite especificar o número máximo de caracteres a serem impressos de uma string. Por padrão, todos os caracteres da string são impressos até que o caractere “\0” seja encontrado, como mostrado no exemplo abaixo. Saída: N = 00000125 (decimal) N = 00000175 (octal) N = 0000007D (hexadecimal) Saída: N = 123.457 N = 123.45678 N = 1.23457e+002 N = 123.46 1. #include 2. #include 3. int main() 4. { 5. char texto[20]="Meu Programa C"; 6. printf("%s\n", texto); 7. printf("%.3s\n", texto); 8. printf("%.12s\n", texto); 9. return 0; 10. } O campo precisão definido por uma variável inteira Por fim, podemos informar que a precisão será especificada por um valor inteiro passado como parâmetro para a função printf(). Observe o exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. float n=123.45678; 6. int precisao=3; 7. printf("N = %.*f\n", precisao, n); 8. precisao=10; 9. printf("N = %.*f\n", precisao, n); 10. return 0; 11. } 2.2.4.5. Comprimento O campo comprimento é utilizado para imprimir valores que sejam do tipo short int, long int e long double, como mostrado na tabela abaixo. Comprimento Descrição h para os tipos “%d”, “%i”, “%u”, “%o”, “%x” e “%X”: o valor é interpretado como short int ou unsigned short int l para os tipos “%d”, “%i”, “%u”, “%o”, “%x” e “%X”: o valor é interpretado como long int ou unsigned long int para os tipos “%c” e “%s”: permite imprimir caracteres e sequências de caracteres onde cada caractere possui mais do que 8-bits para os tipos “%f”, “%e”, “%E”, “%g” e “%G”: o valor é interpretado como long double L para os tipos “%f”, “%e”, “%E”, “%g” e “%G”: o valor é interpretado como long double Saída: Meu programa C Meu Meu programa Saída: N = 123.457 N = 123.4567794800 Deve-se tomar cuidado com o campo comprimento, pois ele não funciona corretamente dependendo do compilador e da plataforma utilizada. Observe o exemplo abaixo. 1. #include 2. #include 3. int main() 4. { 5. int n=10; 6. float f=2.5; 7. char c='a'; 8. printf("N = %hd\n", n); 9. printf("N = %ld\n", n); 10. printf("C = %lc\n", c); 11. printf("F = %Lf\n", f); 12. return 0; 13. } 2.4.6. Resumo dos especificadores de formato Vimos que, entre o caractere “%” e o caractere especificador do tipo de dado pode-se utilizar, em resumo, as seguintes alternativas: ✓ Um sinal de menos que determina o ajustamento/alinhamento à esquerda do argumento convertido; ✓ Um número que especifica a largura (tamanho) mínima do campo que receberá o argumento convertido. Se necessário, ele será preenchido com espaço à esquerda (ou à direita, se o ajustamento à esquerda for solicitado) para compor a largura do campo; ✓ Um ponto que separa a largura do campo da sua precisão (número de casas decimais); ✓ Um número ou a precisão, que especificam o número máximo de caracteres a ser impresso em uma string, ou o número de dígitos após o ponto decimal de um valor real, ou o número mínimo de dígitos para um inteiro; ✓ Um “h” ou “l” se o número inteiro tiver que ser impresso como short ou long, respectivamente. Exemplos: 7 4 2 %4d 2 2 %7.2f 2 . 2 2 %-4d 2 2 %-7.2f 2 . 2 2 Saída: N = 10 N = 10 C = a F = 2.500000 Observe abaixo, um exemplo ilustrando o uso destes especificadores de formato na função printf(). 1. #include 2. void main(void) 3. { 4. short int CH = 47; 5. printf(“%-10.2f %-10.2f %-10.2f \n”, 8.0, 15.253, 584.13); 6. printf(“%04d \n”, 21); 7. printf(“%6d \n”, 21); 8. printf(“%10.3f \n”, 3456.78); 9. printf(“%3.1f \n”, 3456.78); 10. printf(“%hd %c \n”, CH,CH); 11. } 2.2.4.7. Mais de uma linha na função printf() Por fim, pode ocorrer de a linha que queiramos escrever na tela de saída seja muito grande. Isso faz com que a string dentro da função printf() não possa ser visualizada toda de uma vez. Felizmente, a função permite que coloquemos um caractere de barra invertida “\” apenas para indicar que a string que estamos digitando continua na próxima linha. Observe o exemplo abaixo. 1. #include 2. #include 3. int main() 4. { 5. printf("Esse texto que estou querendo escrever \ 6. na tela de saída é muito grande. Por isso eu \ 7. resolvi quebrar ele em várias linhas. \n"); 8. return 0; 9. } 2.3. COMANDOS DE ENTRADA DE DADOS Os comandos de entrada de dados são o meio pelo qual as informações dos usuários são transferidas para a memória dos computadores, para que possam ser usadas nos programas. Em linguagem de programação C, uma das funções responsáveis por essa operação é scanf(). Saída: 8.00 15.25 584.13 0021 21 3456.780 3456.7 47 / 2.3.1. SCANF() A função scanf() é uma das funções de entrada/leitura de dados da linguagem C. Seu nome vem da expressão em inglês scan formatted, ou seja, leitura formatada. Basicamente, a função scanf() lê do teclado um conjunto de valores, caracteres e/ou sequência de caracteres de acordo com o formato especificado. A sintaxe básica da função é: scanf(“expressão_de_controle”, lista_de_argumentos); A função scanf()recebe dois parâmetros de entrada: ✓ “expressão de controle”: conjunto de caracteres que especifica o formato dos dados a serem lidos; ✓ lista de argumentos: conjunto de nomes de variáveis que serão lidos, separados por vírgula, onde cada variável é precedido pelo operador &. A expressão de controle especifica o formato de entrada dos dados que serão lidos pela função. Cada formato é precedido por um sinal de % e um código de controle deve ser especificado para cada variável a ser lida. Assim, se quiséssemos ler uma única variável com o camando scanf(), a sintaxe correta seria: scanf(“%código”, &variável); Se fossem duas as variáveis a serem lidas, a sintaxe correta seria: scanf(“%código1 %código2”, &variável1, &variável2); E assim por diante. Note que os formatos e as variáveis que armazenarão o dado com aquele formato devem ser especificados na mesma ordem, como mostrado pelas setas acima. Na linguagem C, é necessário colocar o símbolo de & antes do nome de cada variável a ser lida pelo comando scanf(). Trata-se de uma exigência da linguagem C. Todas as variáveis que receberão valores do teclado por meio da scanf() deverão ser passadas pelos seus endereços. Isso se faz colocando o operador de endereço “&” antes do nome da variável. A função scanf() pode ser usada para ler virtualmente qualquer tipo de dado. A tabela abaixo mostra alguns dos tipos de entrada suportados pela linguagem e seus respectivos códigos de controle: Código Tipo de argumento Descrição %d int valor inteiro decimal %i int valor inteiro decimal (podendo estar na base decimal, octal com inicial 0 ou hexadecimal com inicial 0x) %o int valor inteiro octal (com ou sem 0 inicial) %x %X int valor inteiro hexadecimal (com ou sem 0x inicial) %u int valor inteiro decimal sem sinal (unsigned int) %c char um caractere em formato ASCII %s char uma cadeia de caracteres (string) terminadaem “\0” %f %e %g float valor em ponto flutuante de precisão simples %lf %le %lg double valor em ponto flutuante de precisão dupla Observe abaixo alguns exemplos de leitura de dados utilizando o comando scanf(). 1. #include 2. #include 3. int main() 4. { 5. int x, z; 6. float y; 7. scanf(“%d”,&x); 8. scanf(“%f”,&y); 9. scanf(“%d%f”,&x,&y); 10. scanf(“%d%d”,&x,&z); 11. scanf(“%d %d”,&x,&z); 12. return 0; 13. } No exemplo acima, os comandos nas linhas 10 e 11 são equivalentes. Isso ocorre por que a função scanf() ignora os espaços em branco entre os tipos de entrada. Além disso, quando a função scanf() é usada para ler dois ou mais valores, pode-se optar por duas formas de digitar os dados no teclado: ✓ Digitar um valor e, em seguida, pressionar a tecla ENTER para cada valor digitado; ✓ Digitar todos os valores separados por espaço e, por último, pressionar a tecla ENTER. 2.3.2. GETCHAR() A função getchar() – get character – permite ler um único caractere do teclado. A sintaxe geral dessa função é a seguinte: variável = getchar(); A função getchar() não recebe parâmetros de entrada. A função retorna, caso não ocorra nenhum erro, o código ASCII do caractere lido e, caso ocorra algum erro, a constante EOF (definida no arquivo-cabeçalho stdio.h) é retornada. Observe o exemplo abaixo, supondo que o usuário entre com o dado “a”: 1. #include 2. #include 3. int main() 4. { 5. char c; 6. c= getchar(); 7. printf(“Caractere: %c\n”, c); 8. printf(“Código ASCII: %d\n”, c); 9. system(“pause”); 10. return 0; 11. } Note que, no exemplo acima, a saída depende da tecla que foi pressionada pelo usuário na entrada do dado. Caso o usuário digite a tecla “a” (minúscula), a saída será como apresentado acima. Caso digite outra tecla, a saída será, obviamente, diferente. Perceba ainda que a conversão na linguagem C é direta no momento da leitura, ou seja, embora a função retorne um valor do tipo int, pode-se atribuir para uma variável do tipo char devido à conversão automática da linguagem C. 2.3.3. GETCH() E GETCHE() Muitas vezes queremos ler um caractere fornecido pelo usuário. Para isto as funções mais usadas, quando se está trabalhando em ambiente Windows, são getch() e getche(). Ambas retornam o caractere pressionado. A função getche() imprime o caractere na tela antes de retorná-lo e a função getch() apenas retorna o caractere pressionado sem imprimi-lo na tela. Ambas as funções podem ser encontradas no arquivo de cabeçalho conio.h. Geralmente estas funções não estão disponíveis em ambiente Unix (compiladores cc e gcc), pois não fazem parte do padrão ANSI. Entretanto, elas podem ser substituídas pela função scanf(), porém sem as mesmas funcionalidades. Observe o exemplo abaixo, utilizando a função getch(). Saída: Caracatere: a Código ASCII: 97 file:///C:/Meus%20documentos/Redcell/Programacao%20C/Tutorial%20UFMG/aulas/c240.html%23c244.html%23c244.html #include #include int main () { char Ch; Ch=getch(); printf ("Você pressionou a tecla %c",Ch); return(0); } Agora, observe o mesmo, utilizando a função scanf(). #include int main () { char Ch; scanf("%c", &Ch); printf ("Você pressionou a tecla %c",Ch); return(0); } A principal diferença da versão que utiliza getch() para a versão que não utiliza getch() é que no primeiro caso o usuário simplesmente aperta a tecla e o sistema lê diretamente a tecla pressionada. No segundo caso, é necessário apertar também a tecla . Mas lembre-se que, se você quiser manter a portabilidade de seus programas, não deve utilizar as funções getch() e getche(), pois estas não fazem parte do padrão ANSI C. 2.3.4. GETS() Como já vimos, em linguagem C, uma string é um vetor de caracteres terminado com um caractere nulo. O caractere nulo é um caractere com valor inteiro igual a zero (código ASCII igual a 0). O terminador nulo também pode ser escrito usando a convenção de barra invertida do C como sendo '\0'. Considere a string abaixo de 7 posições, que armazena a palavra João nela. J o a o \0 ... ... No exemplo acima, as duas células não usadas têm valores indeterminados. Isto acontece porque o C não inicializa variáveis, cabendo ao programador esta tarefa. Portanto as únicas células que são inicializadas são as que contêm os caracteres 'J', 'o', 'a', 'o' e '\0' . Se quisermos ler uma string fornecida pelo usuário podemos usar a função gets() – get string. A função gets() lê uma string e coloca-a no endereço apontado pelo seu argumento ponteiro para caractere. Para efeito prático, fará parte da string tudo o que for digitado até o retorno do carro (tecla ENTER), sendo este substituído pelo terminador nulo “\0”. A sintaxe geral da função gets() é: gets(nome_da_variavel); Vale ressaltar que se for ultrapassado o espaço reservado para a string, esta função sobrepõe os valores na memória, podendo ocasionar um erro grave. Observe abaixo um exemplo do uso desta função. 1. #include 2. int main () 3. { 4. char str[100]; 5. printf ("Digite uma string: "); 6. gets (str); 7. printf ("\n\nVocê digitou %s",str); 8. return(0); 9. } Neste programa, o tamanho máximo da string que você pode entrar é uma string de 99 caracteres. Se você entrar com uma string de comprimento maior, o programa irá aceitar, mas os resultados podem ser desastrosos. 2.3.5. RECURSOS AVANÇADOS DA FUNÇÃO SCANF() A função scanf() é uma das funções de entrada/leitura de dados da linguagem C. Sua funcionalidade básica é ler no dispositivo de entrada de dados (teclado) um conjunto de valores, caracteres e/ou sequência de caracteres de acordo com o formato especificado. Porém, essa função permite uma variedade muito maior de formatações do que as vistas até então. Observe a definição geral da função. A função scanf() possui o seguinte protótipo: int scanf(“expressão_de_controle”, lista_de_argumentos) A função scanf() recebe dois parâmetros de entrada: ➢ expressão_de_controle → conjunto de caracteres que especifica o formato dos dados a serem lidos do teclado; ➢ lista_de_argumentos → conjunto de nomes de variáveis, separados por vírgula, que serão lidos, onde cada nome de variável é precedido pelo operador &; e retorna: ➢ um valor inteiro que representa o número total de caracteres lidos, em caso de sucesso – esse número pode ser igual ou menor que o número esperado de itens a serem lidos; ➢ a contante EOF, em caso de erro da função. O valor de retorno da função scanf() permite identificar o funcionamento adequado da função. Foi visto que quando se quer ler dados formatados do teclado, usa-se a expressão_de_controle para especificar o formato de entrada dos dados que serão lidos. E que cada expressão de controle é precedida por um sinal de % e um código de controle deve ser especificado para cada variável a ser lida. A string da expressão_de_controle permite especificar mais características dos dados lidos além do formato. Essas características são opcionais e são: *, largura e modificadores. A ordem em que essas quatro características devem ser especificadas é a seguinte: %[*][largura][modificadores]código_de_controle Como a expressão_de_controle, cada uma dessas características possui um conjunto de valores pré-definidos e suportados pela linguagem. Observe nas seções seguintes, todos os valores suportados para cada uma das características de formatação possíveis. 2.3.5.1. Expressão de Controle A função scanf() pode ser usada para ler virtualmente qualquer tipo de dado. A tabela abaixo mostra todos os tipos de entrada suportados pela linguagem C. Observe: Código Descrição %c leitura de um caractere(char) – se uma largura diferente do valor 1 é especificada, a função lê o número de caracteres especificado na largura e os armazena em posições sucessivas de memória (array) do ponteiro para char passado como parâmetro; o caractere “\0” não é acrescentado no final %d leitura de um número inteiro (int) – o valor pode ser precedido pelo símbolo de sinal (+ ou -) %u leitura de um número inteiro sem sinal (unsigned int) %i leitura de um número inteiro (int) – o valor pode estar precedido de 0x ou 0X, se for hexadecimal, ou pode ser precedido de zero (0), se for octal %f, %e, %E, %g, %G leitura de um número real (float e double) – o valor pode ser precedido pelo símbolo de sinal (+ ou -), e/ou seguido pelos caracteres “e” ou “E” (notação científica) e/ou possuir o separador de ponto decimal %o leitura de um número inteiro (int) no formato octal (base 8) – o valor pode ou não estar precedido de zero (0) %x, %X leitura de um número inteiro (int) no formato hexadecimal (base 16) – o valor pode ou não estar precedido de 0x ou 0X %s leitura de uma sequência de caracteres (string) até um caractere de nova linha “\n” ou espaço em branco seja encontrado A seguir, são apresentados alguns exemplos de como cada expressão de controle pode ser utilizada para ler determinado dado do teclado. Lendo os tipos básicos A linguagem C possui vários tipos de entrada que podem ser utilizados com os tipos básicos, ou seja, char (“%c” e “%d”), int (“%d” e “%i”), float e double (“%f”), e por fim array de char ou string (“%s”). Note que o tipo char pode ser lido do teclado por meio dos operadores “%c” e “%d”. Nesse caso, “%c” irá ler um caractere e armazená-lo na variável, enquanto “%d” irá ler um valor numérico e armazenar na variável o caractere correspondente da tabela ASCII. Abaixo, tem-se alguns exemplos de leitura dos tipos básicos: 1. #include 2. #include 3. int main() 4. { 5. int n 6. float f; 7. double d; 8. char letra; 9. scanf("%d", &n); //leitura de int 10. scanf("%i", &n); //leitura de int 11. scanf("%d", &letra); //leitura de char 12. scanf("%c", &letra); //leitura de char 13. scanf("%f", &f); //leitura de float 14. scanf("%f", &d); //leitura de double 15. return 0; 16. } Lendo valores no formato octal ou hexadecimal O exemplo abaixo mostra como ler um valor inteiro nos formatos octal (base 8) ou hexadecimal (base 16). Para isso, usamos a expressão de controle “%o” (sinal de porcentagem mais a letra “o”, não o zero “0”) para que a função scanf() leia o valor em octal, e “%x” para hexadecimal com letras minúsculas e “%X” para hexadecimal com letras maiúsculas. Observe: 12. #include 13. #include 14. int main() 15. { 16. int n; 17. scanf("%o\n", &n); //leitura no formato octal 18. scanf("%x\n", &n); //leitura no formato hexadecimal 19. scanf("%X\n", &n); //leitura no formato hexadecimal 20. return 0; 21. } Lendo valores como notação científica De modo geral, podemos ler um valor em notação científica com qualquer um dos tipos de entrada habilitados para lerem valores de ponto flutuante (float e double): “%f”, “%e”, “%E”, “%g” e “%G”. Na verdade, esses tipos de entrada não fazem distinção na forma como o valor em ponto flutuante é escrito, desde que seja ponto flutuante, como mostrado no exemplo abaixo. Observe: 1. #include 2. #include 3. int main() 4. { 5. float x; 6. scanf(“%f”, &x); 7. scanf(“%e”, &x); 8. scanf(“%E”, &x); 9. scanf(“%g”, &x); 10. scanf(“%G”, &x); 11. return 0; 12. } Lendo uma string do teclado O exemplo abaixo mostra como ler uma string (ou array de caracteres) do teclado. Para isso, usamos o tipo de entrada “%s”. Note que quando usamos a função scanf() para ler uma string, o símbolo de & antes do nome da variável não é utilizado. Além disso, a função scanf() lê apenas strings digitadas sem espaços, ou seja, apenas palavras. No caso de ter sido digitada uma frase (uma sequência de caracteres contendo espaços em branco) apenas os caracteres digitados antes do primeiro espaço encontrado serão armazenados na string. Observe o exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. char texto[20]; 6. printf(“Digite uma palavra: “); 7. scanf(“%s”, texto); 8. return 0; 9. } 2.3.5.2. O Campo Asterisco (*) A função scanf() ignora apenas os espaços em branco entre os tipos de entrada. Qualquer outro caractere inserido entre os tipos de dados deverá ser digitado pelo usuário, mas será descartado pelo programa. Isso faz com que as duas chamadas da função abaixo possuam o mesmo efeito: ler dois valores de inteiro. int x, y; scanf(“%d%d”,&x,&y); scanf(“%d %d”,&x,&y); Porém, qualquer caractere que não seja um espaço em branco que for digitado junto ao tipo de entrada faz com que a função scanf() exija a leitura desse caractere e o descarte em seguida. Isso é interessante quando queremos que seja feita a entrada de dados em uma formatação pré- determinada, como uma data. Por exemplo, “%d / %d / %d” faz com que a função scanf() leia um inteiro, uma barra (que será descartada), outro valor inteiro, outra barra (que também será descartada) e , por fim, o terceiro último inteiro. Entretanto, se o caractere a ser lido e descartado não é encontrado, a função scanf() irá terminar, sendo os dados lidos de maneira incorreta. Observe o exemplo abaixo: 1. #include 2. #include 3. int main() 4. { 5. int dia,mes,ano; 6. printf(“Digite uma data no formato dd/mm/aaaa: “); 7. scanf(“%d/%d/%d”, &dia,&mes,&ano); 8. printf(“A data que você digitou foi: %d/%d/%d.\n”, dia,mes,ano); 9. system(“pause”); 10. return 0; 11. } Isso permite que a função scanf() seja utilizada para receber dados formatados como, por exemplo, uma data. No exemplo acima, a função scanf() é usada para a entrada de três valores inteiros separados por uma barra “/” cada. Quando o usuário for digitar os três valores, ele será obrigado a digitar os três valores separados por barra (as barras serão descartadas e não interferem nos dados). Do contrário, a função scanf() não irá ler corretamente os dados digitados. A expressão de controle pode conter códigos de controle precedidos por um sinal de %, ou ainda pelo caractere * colocado após o % e antes do código de controle. O caractere * avisa à função que deve ser lido um valor do tipo indicado pela especificação, mas não deve ser atribuído a nenhuma variável (não deve ter parâmetros na lista de argumentos para essas especificações). Observe o exemplo abaixo: /* Programa que mostra o uso do caractere * com scanf() */ 1. #include 2. #include 3. int main() 4. { 5. int dia,mes,ano; 6. printf(“Digite uma data no formato dd/mm/aaaa: “); 7. scanf(“%d%*c%d%*c%d”, &dia,&mes,&ano); 8. printf(“A data que você digitou foi: %d/%d/%d.\n”, dia,mes,ano); 9. system(“pause”); 10. return 0; 11. } Assim, o uso de um asterisco “*” após o símbolo de % indica que os dados formatados devem ser lidos do teclado mas ignorados, ou seja, não devem ser armazenados em nenhuma variável. Observe abaixo um outro exemplo desse uso. 1. #include 2. #include 3. int main() 4. { 5. int x,y; 6. printf(“Digite três números inteiros: “); 7. scanf(“%d %*d %d”, &x,&y); 8. printf(“Números lidos: %d e %d.\n”, x,y); 9. return 0; 10. } 2.3.5.3. O Campo Largura Basicamente, o campo largura é um valor inteiro que especifica o número máximo de caracteres que poderá ser lido em uma operação de leitura para um determinado tipo de entrada. Isso é muito útil quando queremos limitar a quantidade de caracteres que serão lidos em uma string de modo anão ultrapassar o tamanho máximo de armazenamento dela, ou quando queremos limitar a quantidade de dígitos de um valor como, por exemplo, no caso do valor de um dia do mês (dois dígitos). Os caracteres que ultrapassam o tamanho da largura determinada são descartados pela função scanf(), mas continuam no buffer do teclado. Uma outra chamada da função scanf() irá considerar esses caracteres já contidos no buffer como parte do que será lido. Assim, para evitar confusões, é conveniente esvaziar o buffer do teclado com a função fflush(stdin) a cada nova leitura. Observe abaixo um exemplo de utilização do campo largura. 1. #include 2. #include 3. int main() 4. { 5. int n; 6. printf("Digite um número (2 dígitos): "); 7. scanf("%2d", &n); 8. printf("Número lido: %d\n", n); 9. fflush(stdin); 10. char texto[11]; 11. printf("Digite uma palavra (máximo de 10 caracteres): "); 12. scanf("%10s", texto); 13. printf("Palavra lida: %s\n", texto); 14. return 0; 15. } 2.3.5.4. O Campo Modificadores Os “modificadores” da exprtessão de controle se assemelham ao campo “comprimento” da função printf(). Eles são utilizados para ler valores que sejam do tipo short int, long int e long double, como mostrado na tabela abaixo. Observe: Modificadores Descrição h para os tipos “%d” ou “%i”: o valor é interpretado como short int para os tipos “%u”, “%o”, “%x” ou “%X”: o valor é interpretado como unsigned short int l para os tipos “%d” ou “%i”: o valor é interpretado como long int para os tipos “%u”, “%o”, “%x” ou “%X”: o valor é interpretado como unsigned long int para os tipos “%f”, “%e”, “%E”, “%g” e “%G”: o valor é interpretado como long double L para os tipos “%f”, “%e”, “%E”, “%g” e “%G”: o valor é interpretado como long double Deve-se tomar cuidado com o campo modificadores, pois ele não funciona corretamente dependendo do compilador e da plataforma utilizada. 2.3.5.5. Lendo apenas caracteres pré-determinados A função scanf() permite também que se defina uma lista de caracteres pré- determinados, chamada de scanset, que poderá ser lida do teclado e armazenada em uma string. Essa lista é definida substituindo a expressão de controle %s, normalmente utilizado para a leitura de uma string, por %[], onde, dentro dos colchetes, é definida a lista de caracteres que poderá ser lida pela função scanf(). Assim, se quiséssemos ler uma string contendo apenas vogais, a função scanf() seria usada como mostrado no exemplo abaixo. 1. #include 2. #include 3. int main() 4. { 5. char texto[20]; 6. printf("Digite algumas vogais: "); 7. scanf("%[aeiou]", texto); 8. printf("Vogais lidas: %s\n", texto); 9. return 0; 10. } Note que dentro da lista de caracteres pré-determinados foram digitadas as vogais minúsculas. A linguagem de programação C considera diferente letras maiúsculas e minúsculas. Além disso, se um dos caracteres digitados não fizer parte da lista de caracteres pré-determinados (scanset), a leitura da string é terminada e a função scanf() passa para o próximo tipo de entrada, se houver. Usando um intervalo de caracteres pré-determinados Ao invés de definir uma lista de caracteres, pode-se definir um intervalo de caracteres, como por exemplo, todas as letras minúsculas, ou todos os dígitos numéricos. Para fazer isso, basta colocar o primeiro e o último caracteres do intervalo separados por um hífen. Assim, se quiséssemos ler apenas os caracteres de A a Z, a função scanf() ficaria como mostrado no exemplo abaixo. Observe: 1. #include 2. #include 3. int main() 4. { 5. char texto[20]; 6. printf("Digite algumas letras: "); 7. scanf("%[A-Z]", texto); 8. printf("Letras lidas: %s\n", texto); 9. return 0; 10. } Pode-se ainda especificar mais de um intervalo de caracteres pré-determinados. Para fazer isso, basta colocar o primeiro e o último caracteres do segundo intervalo, separados por um hífen, logo após definir o primeiro intervalo. Assim, se quiséssemos ler apenas os caracteres de A a Z e os dígitos de 0 a 9, a função scanf() ficaria como mostrado no exemplo abaixo. Observe: 1. #include 2. #include 3. int main() 4. { 5. char texto[20]; 6. printf("Digite algumas letras e números: "); 7. scanf("%[A-Z0-9]", texto); 8. printf("Letras e números lidos: %s\n", texto); 9. return 0; 10. } 3. INTERFACE COM O USUÁRIO Uma preocupação constante de um bom programador deve ser a de conceber um programa “amigo do usuário”. Esta preocupação é traduzida no planejamento de uma interface com o usuário (meio pelo qual um programa e o usuário “conversam”) bastante amigável. Em termos práticos, isto se resume à aplicação de duas regras básicas: ✓ toda vez que um programa estiver esperando que o usuário forneça a ele um determinado dado (operação de leitura), ele deve antes enviar uma mensagem dizendo ao usuário o que ele deve digitar, por meio de uma instrução de saída de dados; ✓ antes de enviar qualquer resultado ao usuário, um programa deve escrever uma mensagem explicando o significado do mesmo. Estas medidas tornam o diálogo entre o usuário e o programador muito mais fácil. Observe abaixo um exemplo de um programa simples utilizando as regras de construção de uma interface amigável: 1. #include 2. int main () 3. { 4. char nome[80]; 5. float n1, n2, n3, media; 6. printf("MÉDIA DO ALUNO\n\n"); 7. printf("Digite o nome do aluno: "); 8. gets (nome); 9. printf("Digite a primeira nota do aluno: "); 10. scanf("%f", &n1); 11. printf("Digite a segunda nota do aluno: "); 12. scanf("%f", &n2); 13. printf("Digite a terceira nota do aluno: "); 14. scanf("%f", &n3); 15. media = (n1+n2+n3)/3; 16. printf("\n"); 17. printf("Nome do aluno: %s\n", nome); 18. printf("Média final do aluno: %.2f\n\n", media); 19. system("pause"); 20. return 0; 21. } Entretanto, como o idioma padrão da linguagem C é o inglês, caracteres especiais como ç ou acentuação não serão apresentados de forma correta na tela. Para resolver esse problema, pode- se utilizar o arquivo-cabeçalho locale.h para implementar a localização de programas. Chamamos de “localizar” um programa quando fazemos a adaptação deste às características de uma determinado idioma ou de uma região. Observe abaixo um exemplo que permite suporte a língua portuguesa. A utilização do arquivo locale.h e da função setlocale() configurada adequadamente vai garantir que caracteres como “ç” e acentuação sejam exibidos normalmente no programa. Dessa forma, se você estiver usando um sistema operacional em português o suporte ao idioma padrão do sistema será configurado para o programa escrito em C através da função setlocale(). 1. #include 2. #include 3. #include 4. int main() 5. { 6. printf("\n** Verificando a localidade corrente **\n\n"); 7. printf ("Localidade corrente: %s\n", setlocale(LC_ALL,NULL) ); 8. printf("Não é possível usar acentuação ou ç corretamente.\n\n"); 9. printf("\n** Alterando para a localidade do sistema **\n\n"); 10. printf("A localidade corrente agora é %s \n",setlocale(LC_ALL,"")); 11. printf("Agora não tem mais problema algum!\n"); 12. printf("Já posso usar acentuação e também o caractere ç...\n\n\n"); 13. system("pause"); 14. return 0; 15. } Também é possível configurar o idioma português utilizado a função da seguinte forma: setlocale(LC_ALL, “Portuguese”);. Observe o exemplo abaixo: 1. #include 2. #include 3. #include 4. int main() 5. { 6. setlocale(LC_ALL,"Portuguese")); 7. printf("Utilizando caracteres e acentuação da língua portuguesa!\n\n"); 8. system("pause");9. return 0; 10. } A função setlocale() é utilizada para fazer a adaptação do programa ao idioma desejado. Esta adaptação trata de informações sobre a apresentação de alguns dados, tais como: ✓ Caracteres e acentuação específicos do idioma. ✓ Formato de números e valores monetários ✓ Formatação de data e hora Um programa escrito em C é iniciado com a localização-padrão “C” de acordo com o padrão ISO. Esta localização é uma localização “neutra” e contém informações mínimas a fim de proporcionar uma execução consistente independente do ambiente. Em alguns casos é necessário alterar a localização-padrão “C” para adequar-se ao formato do idioma ou representações específicas de datas e horas. A função setlocale() pode ser usada para modificar essa localização para outra desejada e que seja adequada ao idioma usado no programa. A sintaxe básica dessa função é a seguinte: setlocale(int categoria, const char local) Nessa sintaxe: • categoria → categoria a ser modificada ou consultada • local → string que vai corresponder a uma localidade que será atribuída a uma categoria representada pelo argumento categoria • a string “C” corresponde à localidade padrão • a string “ ” corresponde a localidade de uso corrente do sistema operacional • NULL faz a consulta do valor atual da localidade estabelecida para a categoria do primeiro argumento da função Observe agora o exemplo anterior com a correção da localidade: 1. #include 2. #include 3. int main () 4. { 5. setlocale(LC_ALL,””); 6. char nome[80]; 7. float n1, n2, n3, media; 8. printf("MÉDIA DO ALUNO\n\n"); 9. printf("Digite o nome do aluno: "); 10. gets (nome); 11. printf("Digite a primeira nota do aluno: "); 12. scanf("%f", &n1); 13. printf("Digite a segunda nota do aluno: "); 14. scanf("%f", &n2); 15. printf("Digite a terceira nota do aluno: "); 16. scanf("%f", &n3); 17. media = (n1+n2+n3)/3; 18. printf("\n"); 19. printf("Nome do aluno: %s\n", nome); 20. printf("Média final do aluno: %.2f\n\n", media); 21. system("pause"); 22. return 0; 23. } 4. FUNÇÕES PRÉ-DEFINIDAS Toda linguagem de programação já vem com um grupo de funções que facilitam a vida do programador. Estas funções realizam os cálculos aritméticos, trigonométricos e de manipulação e conversão de dados mais comuns. Assim, o programador não tem que reinventar a roda a cada programa que faz. Este grupo de funções pré-definidas encontra-se presente em arquivos- cabeçalhos da linguagem C. Um arquivo-cabeçalho é um arquivo contendo um conjunto de funções (pedaços de código) já implementados e que podem ser utilizados pelo programador em seu programa. Para inserir arquivos-cabeçalhos que serão utilizados pelo programa, usamos a diretiva #include. Esse comando diz ao pré-processador para tratar o conteúdo de um arquivo especificado como se o seu conteúdo houvesse sido digitado no programa no ponto em que a diretiva #include aparece. A diretiva #include permite duas sintaxes básicas: #include Nesse caso, o pré-processador procurará pelo arquivo nos caminhos de procura pré- especificados do compilador. Usa-se essa sintaxe quando estamos incluindo um arquivo que é próprio do sistema, como stdio.h e stdlib.h. #include “nome do arquivo” Nesse caso, o pré-processador procurará pelo arquivo no mesmo diretório onde se encontra o nosso programa. Podemos ainda optar por informar o nome do arquivo com o caminho completo, ou seja, em qual diretório ele se encontra e como chegar até lá. De modo geral, os arquivos-cabeçalhos na linguagem C são terminados com a extensão .h. Observe os exemplos abaixo: #include #include “D:\Programas\soma.h” Na primeira linha, a diretiva #include é utilizada para adicionar um arquivo-cabeçalho do sistema: stdio.h (que contém as funções básicas de leitura do teclado e escrita em tela). Já na segunda linha, o comando é utilizado para adicionar um arquivo de nome soma.h, localizado no diretório “D:\Programas\”. 4.1. FUNÇÕES DE ENTRADA E SAÍDA Arquivo-cabeçalho: stdio.h Operações em arquivos ✓ remove: apaga o arquivo ✓ rename: renomeia o arquivo Acesso a arquivos ✓ fclose: fecha o arquivo ✓ fflush: limpa o buffer; quaisquer dados não escritos no buffer são gravados no arquivo ✓ fopen: abre o arquivo ✓ setbuf: controla o fluxo de armazenamento em buffer Entrada/saída formatadas ✓ fprintf: grava uma saída formatada em arquivo ✓ fscanf: lê dados formatados a partir de arquivo ✓ printf: imprime dados formatados na saída padrão (monitor) ✓ scanf: lê dados formatados da entrada padrão (teclado) ✓ sprintf: grava dados formatados em uma string ✓ sscanf: lê dados formatados a partir de uma string Entrada/saída de caracteres ✓ fgetc: lê um caractere do arquivo ✓ fgets: lê uma string do arquivo ✓ fputc: escreve um caractere em arquivo ✓ fputs: escreve uma string em arquivo ✓ getc: lê um caractere do arquivo ✓ getchar: lê um caractere da entrada padrão (teclado) ✓ gets: lê uma string da entrada padrão (teclado) ✓ putc: escreve um caractere na saída padrão (monitor) ✓ putchar: escreve um caractere na saída padrão (monitor) ✓ puts: escreve uma string na saída padrão (monitor) ✓ ungetc: retorna um caractere lido para o arquivo dele Entrada/saída direta ✓ fread: lê um bloco de dados do arquivo ✓ fwrite: escreve um bloco de dados no arquivo Posicionamento no arquivo ✓ fgetpos: retorna a posição atual no arquivo ✓ fseek: reposiciona o indicador de posição do arquivo ✓ fsetpos: configura o indicador de posição do arquivo ✓ ftell: retorna a posição atual no arquivo ✓ rewind: reposiciona o indicador de posição do arquivo para o início do arquivo Tratamento de erros ✓ clearerr: limpa os indicadores de erro ✓ feof: indicador de fim-de-arquivo ✓ ferror: indicador de checagem de erro ✓ perror: impressão de mensagem de erro Tipos e macros ✓ FILE: tipo que contém as informações para controlar um arquivo ✓ EOF: constante que indica o fim-de-arquivo ✓ NULL: ponteiro nulo 4.2. FUNÇÕES DE UTILIDADE PADRÃO Arquivo-cabeçalho: stdlib.h Conversão de strings ✓ atof: converte string para double ✓ atoi: converte string para inteiro ✓ atol: converte string para inteiro longo ✓ strtod: converte string para double e devolve um ponteiro para o próximo double contido na string ✓ strtol: converte string para inteiro longo e devolve um ponteiro para o próximo inteiro longo contido na string ✓ strtoul: converte string para inteiro longo sem sinal e devolve um ponteiro para o próximo inteiro longo sem sinal contido na string Geração de sequências pseudo-aleatórias ✓ rand: gera número aleatório ✓ srand: inicializa o gerador de números aleatórios Gerenciamento de memória dinâmica ✓ malloc: aloca espaço para um array na memória ✓ calloc: aloca espaço para um array na memória e inicializa com zeros ✓ free: libera o espaço alocado na memória ✓ realloc: modifica o tamanho do espaço alocado na memória Ambiente do programa ✓ abort: abortar o processo atual ✓ atexit: define uma função a ser executada no término normal do programa ✓ exit: finaliza o programa ✓ getenv: retorna uma variável de ambiente ✓ system: executa um comando do sistema Pesquisa e ordenação ✓ bsearch: pesquisa binária em um array ✓ qsort: ordena os elementos do array Aritmética de inteiro ✓ abs: valor absoluto ✓ div: divisão inteira ✓ labs: valor absoluto de um inteiro longo ✓ ldiv: divisão inteira de um inteiro longo 4.3. FUNÇÕES MATEMÁTICAS Arquivo-cabeçalho: math.h Funções trigonométricas ✓ cos: calcula o cosseno de um ângulo em radianos ✓ sin: calcula o seno de um ângulo em radianos ✓ tan: calcula a tangente de um ângulo em radianos ✓ acos: calcula o arco cosseno ✓ asin: