Professional Documents
Culture Documents
Este trabalho est licenciado sob uma Licena Creative Commons Atribuio-Uso No-Comercial-Compartilhamento.
ndice
I Estrutura dos programas em C ...................................................................................1 1 Componentes de um programa em C............................................................................1 1.1 A funo main() .......................................................................................................1 1.2 A directiva #include .............................................................................................2 1.3 A definio de variveis ..........................................................................................2 1.4 Prottipos das funes............................................................................................2 1.5 Instrues do programa ..........................................................................................2 1.6 Implementao de funes .....................................................................................3 1.7 Comentrios............................................................................................................3 1.8 Blocos de instrues ...............................................................................................3 1.9 Exemplo ..................................................................................................................3 1.10 Exerccios..............................................................................................................5 II Armazenamento de Dados..........................................................................................7 2. Variveis e Constantes ....................................................................................................7 2.1 Variveis .................................................................................................................7 2.1.1 Variveis numricas .........................................................................................7 2.1.2 Declarao de variveis ...................................................................................8 2.2 A keyword typedef...................................................................................................8 2.3 Inicializao de variveis.........................................................................................9 2.4 Constantes ..............................................................................................................9 2.5 Exerccios..............................................................................................................10 3. Inputs e Outputs ............................................................................................................12 3.1 Mostrar informao no cran.................................................................................12 3.1.1 Strings de formatao do printf()..............................................................12 3.1.2 Resumo da funo printf() .......................................................................15 3.2 Mostrar mensagens com a funo puts(). .........................................................15 3.3 Outras funes de sadas de dados......................................................................16 3.4 Leitura de valores com a funo scanf() ...........................................................17 3.4.1 Resumo da funo scanf()..........................................................................18 3.4.2 Outras funes de leitura de dados ................................................................19 3.5 Outros exemplos com as funes printf() e scanf(). ...................................19 3.6 Exerccios..............................................................................................................23 4. Instrues, Expresses e Operadores...........................................................................24 4.1 Instrues..............................................................................................................24 4.1.1 Instrues compostas.....................................................................................25 4.2 Expresses ...........................................................................................................25 4.3 Operadores ...........................................................................................................25 4.3.1 Precedncias e parntesis..............................................................................28 4.3.2 Ordem de evoluo em subexpresses .........................................................28 4.3.3 Operadores relacionais...................................................................................28 4.3.4 Precedncia dos operadores relacionais........................................................29 4.3.5 Operadores lgicos.........................................................................................29 4.4 Exerccios..............................................................................................................30 III Programao Estruturada........................................................................................31 5. Estruturas de controlo: Instrues de seleco .............................................................31 5.1 Instruo if ..........................................................................................................31 5.1.1 Outros exemplos da intruo if.....................................................................34 5.1.2 Consideraes sobre os valores TRUE e FALSE...........................................36 5.2 Instrues de afectao compostas ......................................................................37
INETE Instituto de Educao Tcnica
ii 5.3 Operador condicional ?: ........................................................................................37 5.4 Operador "," (vrgula). ...........................................................................................38 5.5 Instruo switch..................................................................................................38 5.6 Exerccios..............................................................................................................43
iii
Nota inicial: Os exemplos que ilustram este manual foram testados no compilador Microsoft Visual Studio 2010. Esta ferramenta providncia uma maior diversidade de funes em relao a outros compiladores, mas para garantir a maior compatibilidade possvel s foram usadas funes standard. Um exemplo disso neste manual utilizar-se a funo scanf para ler dados em vez da funo mais segura scanf_s. Caso encontre incompatibilidades entre o cdigo apresentado e o compilador usado envie um e-mail para jcarvalho@inete.net indicado qual a listagem em causa e que tipo de erro encontrou.
Nesta chamada funo, so tambm passados os argumentos a e b. Aps a ltima instruo da funo Product() devolvido um valor funo main(), que armazenado na varivel c. A instruo return serve para devolver um valor ao mdulo chamador. No caso da funo Product(), devolve o resultado da multiplicao funo main(). No caso da main(), devolve um valor ao sistema operativo. O valor 0 indica que tudo correu sem erros.
1.7 Comentrios
Todos os caracteres contidos entre /* e */ so ignorados pelo compilador, e a forma de comentar um programa em C. indiferente a quantidade de caracteres ou linhas que este tipo de comentrio abranja. Nos compiladores de C++ tambm possvel usar // para indicar o incio de um comentrio que no mude de linha.
1.9 Exemplo
Para ilustrar todos estes componentes, vejamos um outro exemplo, onde se pretende abrir um ficheiro de texto e list-lo, numerando as linhas (semelhante ao comando type do MS-DOS, mas acrescentando a numerao das linhas). Um exemplo da utilizao do comando type pode ser observado na figura seguinte.
Figura 2 Utilizao do comando type dos DOS. INETE Instituto de Educao Tcnica
Mais uma vez, o programa seguinte tem como objectivo a introduo aos componentes de um programa em C, e no que seja capaz de o construir. Listagem 1.2 Listar o contedo de ficheiros de texto
/* Programa: TypeWithLines (JC2010) /* Listar ficheiros de texto, numerando as linhas */ #include <stdio.h> #include <stdlib.h> void DisplayUsage(void); int nLine; int main(int argc, char* argv[]) { char szBuffer[256]; FILE *fp;
// Validar o comando
nLine = 1; while(fgets(szBuffer, 256, fp) != NULL ) fprintf(stdout, "%4d: %s", nLine++, szBuffer); fclose(fp); return 0; }
/* Help do programa */
void DisplayUsage(void) { fprintf(stderr, "\nA sintaxe do comando : "); fprintf(stderr, "\n\nTypeWithLines nomefile.ext\n" ); }
Neste programa a funo main() apresenta uma nova forma, utilizando os parmetros argc e argv. Esses parmetros so preenchidos pelo sistema operativo quando o programa executado. O parmetro argc, de tipo inteiro, contm a quantidade de palavras escritas na linha de comando, enquanto o parmetro argv um array de strings (que semelhante a uma tabela de palavras) contendo as vrias palavras escritas na linha de comando. Desta forma, durante a execuo do programa possvel saber exactamente quais as opes que o utilizador usou quando invocou o programa, tal como acontece quando usamos o comando ping no nosso sistema. Iremos tambm analisar estes argumentos (e a forma de os utilizar) mais em detalhe no captulo dedicado s strings. O programa anterior comea por verificar se o utilizador escreveu pelo menos duas palavras na linha de comando (correspondentes ao nome do programa e ao ficheiro a listar). Se isso no aconteceu invocada a funo DisplayUsage(), com informao de como utilizar programa, e depois termina.
INETE Instituto de Educao Tcnica
A seguir aberto o ficheiro a listar, cujo nome est armazenado na posio 1 do array argv (correspondente segunda palavra escrita pelo utilizador, j que a primeira o prprio nome do programa). Se o ficheiro no for encontrado enviada uma mensagem de erro para o ficheiro de erros standard (designado stderr, que normalmente o cran, tal como o stdout standard output). Por fim utilizado um ciclo while para ler cada linha do ficheiro (atravs da funo fgets()) que depois enviada para o cran. A utilizao deste programa poderia ser: C:\>TypeWithLines TypeWithLines.c caso o programa executvel (chamada TypeWithLines.exe) e o ficheiro de texto TypeWithLines.c estejam na raiz da drive E:.
1.10 Exerccios
1. Escreva o programa em C mais pequeno possvel. 2. Considere o seguinte programa:
#include <stdio.h> void DisplayLine(void); int main() { DisplayLine(); printf("\nTeach Yourself C In 21 Days!\n"); DisplayLine(); return 0; } /* imprime uma linha de asteriscos */ void DisplayLine(void) { int counter; for(counter = 0; counter < 21; counter++) printf("*"); INETE Instituto de Educao Tcnica
a. Quais as linhas que contm definio de variveis? b. Quais as linhas que contm prottipos de funes d. Quais as linhas que contm implementao de funes? e. Quais as linhas que contm comentrios? 3. O que que o seguinte programa faz?
#include <stdio.h> int main() { int ctr; for(ctr = 65; ctr < 91; ctr++) printf("%c", ctr); return 0; }
II Armazenamento de Dados
2. Variveis e Constantes
Todos os programas necessitam de guardar dados, normalmente de vrios tipos. Em C, como na maioria das linguagens, existem duas formas de armazenar valores numricos: em variveis ou em constantes. Uma varivel uma localizao em memria cujo valor pode ser alterado ao longo da execuo do programa. Ao contrrio, uma constante, consiste num valor imutvel ao longo dessa execuo.
2.1 Variveis
Uma varivel uma localizao em memria, que ao ser referenciada permite aceder aos dados a guardados. Em C os nomes das variveis tm que comear por uma letra ou underscore (_), num mximo de 252 caracteres (letras, dgitos ou underscores).
Apesar deste exemplo, a utilizao mais normal do typedef agregar vrios tipos de dados (num registo, por exemplo), que em C se chama struct.
Note que a inicializao das variveis pode ser feita tambm atravs de uma instruo de afectao no programa, para alm de se fazer na prpria declarao da varivel. necessrio ter cuidado na inicializao das variveis para no usar valores fora do alcance dos tipos das variveis. Por exemplo, as seguintes inicializaes no so detectadas como erro na maioria dos compiladores de C:
int peso = 1000000000; unsigned int valor = -2500;
2.4 Constantes
Uma constante serve tambm para guardar dados, com a diferena que esses valores no podem ser modificados ao longo da execuo do programa. Existem dois tipos de constantes: as literais e as simblicas: Nos exemplos seguintes, os nmeros 20 e 0.28 so vistos como constantes literais:
int count = 20; float taxa = 0.28;
O C tem duas formas para declarar constantes. Atravs da directiva #define e da keyword const. As constantes so declaradas de acordo com o seguinte formato:
#define CONSTNAME literal
A directiva anterior cria uma constante com o nome representado em CONSTNAME e o literal representa o valor dessa constante. Por conveno, usual utilizarem-se letras maisculas no nome deste tipo de constantes. Assim, no exemplo anterior teramos:
#define PI 3.14159
Note-se que nesta forma de declarar constantes no se usa o ; no final da instruo (j que na realidade se trata de uma directiva de pr-processamento, tal como acontece nas directivas #include). A outra forma tem o seguinte formato:
const typename CONSTNAME = literal;
Aqui a indicao que se trata de uma constante feita atravs da keyword const, vindo depois o tipo e o seu valor. Assim, ainda no exemplo da constante PI teramos:
const double PI = 3.14159;
10
2.5 Exerccios
1. Que tipo de varivel o mais indicado para os seguintes valores: a) O peso de uma pessoa, em gramas. b) O raio de uma circunferncia. c) A distncia a uma estrela, em quilmetros. 2. Qual os nomes que deveriam ter as variveis do exerccio anterior. 3. Escreva a declarao das variveis do exerccio 2. 4. Quais dos seguintes nomes de variveis so invlidos: a) 123var b) x c) um.0
INETE Instituto de Educao Tcnica
11
12
3. Inputs e Outputs
Na maioria dos programas necessitamos de ler e mostrar informao ao utilizador (normalmente atravs do teclado e do cran). Os programas que foram apresentados nos captulos anteriores j continham essas tarefas. Na realidade, este tipo de instrues so das mais complexas no C. Aqui vamos analislas de forma suficientemente detalhada, mas no de forma completa.
Adicionalmente, tambm possvel escrever valores de variveis. Tomemos o exemplo de escrever um valor em conjunto com texto, e no final mudar de linha:
printf("\nO valor de x e' %d\n", x);
e uma possvel execuo seria: O valor de x e' 12 Neste exemplo, o printf() tem dois argumentos. O primeiro, entre as aspas, contendo a string de formatao do valor numrico a imprimir, e o segundo o nome da varivel.
13
Tabela 3.2 Especificaes de converso. Especificao Significado %c Caracter %d Inteiro com sinal %ld Inteiro longo com sinal %lld Inteiro longo longo com sinal %f Nmero real (floating-point) %lf Nmero real (double floating-point) %s String de caracteres %u Inteiro sem sinal %lu Inteiro longo sem sinal
Tipo de converso char int, short long long long float double char arrays unsigned int, unsigned short unsigned long
As sequncias de escape so usadas para controlar a localizao do cursor no cran. So tambm usadas para imprimir caracteres especiais que tm um significado especial para a funo printf(). Por exemplo, se queremos imprimir uma \ temos que usar \\ para que no seja entendida com o incio de sequncia de escape. O mesmo se passa com as aspas. O seguinte exemplo demonstra as sequncias de escape mais frequentes. Listagem 3.1 Utilizao de sequncias de escape
/* Programa: SeqEscape (JC2010) */ /* Utilizao das sequncias de escape */ #include <stdio.h> int main() { printf("\nA usar o speaker do computador...\a\a\a\a\a"); printf("\nRELATORIO EXEMPLO"); printf("\n\nSequencia\tSignificado"); printf("\n=========\t==========="); printf("\n\\a\t\tbell (alert)"); printf("\n\\b\t\tbackspace"); printf("\n\\t\t\ttab"); printf("\n\\\\\t\tbackslash (contrabarra)"); printf("\n\\\"\t\tAspas"); printf("\n...\t\t..."); return 0; }
As especificaes de converso do printf() so constitudas por um determinado cdigo para cada tipo de varivel. As especificaes mais usadas foram j listadas atrs.
14
Quando se pretende imprimir mais que uma varivel no mesmo printf(), basta colocar as especificaes adequadas nas localizaes desejadas dentro do primeiro argumento da funo. Ou seja, por exemplo:
printf("Juro = %f, Valor = %d", tx_juro, montante);
Note-se que se existirem mais variveis que especificaes, essas variveis no so impressas no cran. Por outro lado, se existirem mais especificaes que variveis iro ser impresso lixo nas localizaes das especificaes que esto a mais. A funo printf() no est limitada a imprimir s variveis. Na realidade pode imprimir qualquer expresso vlida de C. Por exemplo:
montante = montante * tx_juro; printf("Juro = %f, Valor = %d", tx_juro, montante);
A utilizao da funo printf() obriga ao include do ficheiro stdio.h. A listagem seguinte ilustra a utilizao do printf(). Note que no ltimo printf() necessrio escrever %% para que o sinal % seja impresso no cran. Listagem 3.2 Sada de valores numricos
/* Programa: PrintNums (JC2010) */ /* Utilizao do printf para imprimir valores numricos. */ #include <stdio.h> int a = 2, b = 10, c = 50; float f = 1.05, g = 25.5, h = -0.1; int main() { printf("\nValores inteiros sem tabs: %d %d %d", a, b, c); printf("\nValores inteiros com tabs: \t%d \t%d \t%d\n", a, b, c); printf("\nTres floats numa linha: \t%f\t%f\t%f", f, g, h); printf("\nTres floats em 3 linhas: \n\t%f\n\t%f\n\t%f\n", f, g, h); printf("\nA taxa de juro e' %f%%", f); printf("\nO resultado de %f/%f e' %f\n", g, f, g/f); return 0; }
15
A funo printf() uma funo que aceita uma srie de arguments, cada um aplicado converso especificada na string de formatao (format-string). A funo printf() imprime a informao formatada no ficheiro de standard output, que normalmente o cran. Quando usamos a funo printf(), necessrio fazer o include do header file do standard input/output, stdio.h. A format-string obrigatria, enquanto os arguments so opcionais. Para cada argumento dever existir uma especificao de converso. A format-string poder conter tambm sequncias de escape. Quer as especificaes de converso, quer as sequncias de escape foram j listadas atrs. O valor devolvido pela funo indica o nmeros de valores que foram escritos com sucesso. Os exemplos seguintes ilustram, mais uma vez, o uso da funo printf() e o respectivo output. Listagem 3.3 Utilizao da funo printf
#include <stdio.h> int main() { printf("Isto e' um exemplo de algo impresso!"); return 0; }
O resultado da execuo do programa ser: Isto e' um exemplo de algo impresso! No exemplo seguinte: Listagem 3.4 Utilizao da funo printf com variveis
#include <stdio.h> int main() { printf("Imprimir um carcter: %c\num numero: %d\ne um float: %f", 'z', 123, 456.789); return 0; }
O resultado da execuo do programa ser: Imprimir um caracter: z um numero: 123 e um float: 456.789
16
Por exemplo:
puts("Hello, world.");
equivalente a:
printf("Hello, world.\n");
As sequncias de escape so tambm vlidas e, tal como no printf(), necessrio incluir o ficheiro stdio.h. Vejamos alguns exemplos: Listagem 3.5 Utilizao da funo puts
#include <stdio.h> int main() { puts("Impresso com a funcao puts()!"); return 0; }
O resultado da execuo do programa ser: Impresso com a funcao puts()! No exemplo seguinte: Listagem 3.6 Comparao entre as funes printf e puts
/* Programa: CompOutput (JC2010) */ /* Comparao entre printf e puts. */ #include <stdio.h> int main() { puts("Isto imprime a primeira linha. \nIsto imprime a segunda linha."); puts("Isto imprime a teceira linha."); puts("Com printf(), estas quatro linhas iriam ser impressas so' em duas!\n"); printf("Isto imprime a primeira linha. \nIsto imprime a segunda linha."); printf("Isto imprime a teceira linha."); return 0; }
17
Tabela 3.3 Funes de sada de dados. Funo Descrio fprintf Escreve dados formatados num ficheiro. fputs Escreve uma string num ficheiro. putchar Escreve um caracter no standard output. putc Escreve um caracter num ficheiro. fputchar, fputc Equivalentes s duas funes anteriores. sprintf Escreve dados formatados numa string.
l um valor inteiro do teclado e atribui esse valor varival x. Da mesma forma, a instruo seguinte l um valor float e atribui-o varivel juro:
scanf("%f", &juro);
No entanto, ao contrrio do que acontecia com a funo printf(), quando se indica o nome de cada uma das variveis que iro armazenar os valores lidos necessrio precede-lo com um &. O smbolo & o operador address-of que iremos ver com mais detalhe quando discutirmos os apontadores. Por agora, basta saber que a funo scanf() necessita deste smbolo antes de cada um dos nomes das variveis que vo ser lidas (a menos que a varivel seja um apontador ou uma string, o que iremos ver mais frente). Atravs da funo scanf() podem ser lidos vrios valores, mesmo que sejam de tipos distintos, desde que sejam fornecidas as especificaes de converso necessrias e os nomes das vrias variveis (precedidas pelo smbolo &). Por exemplo, a instruo seguinte l um inteiro e um float, atribuindo esses dois valores s variveis x e juro, respectivamente:
scanf("%d %f", &x, &juro);
Quando so lidas vrias variveis numa mesma funo scanf(), deve-se utilizar espaos (incluindo tabs e enter) para introduzir os valor. Cada especificao de converso da funo scanf() associada com um valor introduzido que seja seguido por espaos em branco. Esta potencialidade possibilita uma enorme flexibilidade na utilizao da funo scanf(). Assim, para a instruo anterior poderiamos introduzir os valores da seguinte forma: 10 12.45 ou desta outra forma: 10 12.45
INETE Instituto de Educao Tcnica
18
ou ainda: 10 12.45 Desde que exista algum espao em branco entre os valores, a funo scanf() capaz de atribuir os valores s variveis listadas como argumentos. Tal como as funes que discutimos neste ponto, para se utilizar a funo scanf() necessrio incluir o header file stdio.h. O exemplo seguinte ilustra a utilizao desta funo num programa completo. Listagem 3.7 Utilizao da funo scanf
/* Programa: LeNums (JC2010) */ /* Utilizao da funo scanf */ #include <stdio.h> int intVar = 0; float floatVar = 0.0; unsigned unsignedVar = 0; int main() { puts("\n1 - Ler um inteiro com sinal"); printf("\nIntroduza um inteiro com sinal (i.e. -123): "); scanf("%d", &intVar); puts("\n2 - Ler um floating-point"); printf("\nIntroduza um floating-point (i.e. 1.23): "); scanf("%f", &floatVar); puts("\n3 - Ler um inteiro sem sinal"); printf("\nIntroduza um inteiro sem sinal (i.e. 123): "); scanf("%u", &unsignedVar); printf("\nOs valores sao: int: %d float: %f intVar, floatVar, unsignedVar); return 0; } unsigned: %u\n",
19
scanf() uma funo que utiliza uma especificao de converso numa dada string de formatao para colocar valores nas variveis que se pretende ler, e que so os argumentos da funo. Os argumentos tm que ser os endereos das variveis em vez das variveis em si. Para variveis numricas (ou do tipo caracter, que armazenam o cdigo ASCII do caracter) pode-se passar o endereo atravs do operador address-of (&) antes do nome da varivel. A funo scanf() l os valores introduzidos no ficheiro de input standard (normalmente o teclado) e atribui cada um desses valores a um argumento. Para cada argumento ter que existir uma especificao de converso. O valor devolvido pela funo representa os valores que foram efectivamente lidos.
20
O exemplo seguinte ilustra a uilizao de caracteres especiais na funo scanf(), caracteres esses que devem introduzidos pelo utilizador na forma que esto especificados na funo. Listagem 3.9 Utilizao de carateres especiais
/* Programa: FormLer (JC2010) /* Utilizao de formatos na funo scanf */ #include <stdio.h> int i = 0, j = 0, k = 0; float f = 0.0; int main() { printf("Introduza um float e dois inteiros: "); k = scanf("f = %f i = %d %d", &f, &i , &j); printf("\nValor devolvido = %d\n", k); printf("\nf = %f\ti = %d\tj = %d\n", f, i, j); return 0; }
No entanto, se o formato no for respeitado os valores no so atribudos s variveis que se pretendem ler. A execuo seguinte ilustra esse facto.
Como se pode verificar, o facto de a introduo no ter sido feita exactamente como est formatada na format-string da funo, fez com que o ltimo valor no fosse considerado. O exemplo seguinte ilustra o facto de os argumentos da funo printf() poderem ser uma qualquer expresso vlida em C, incluindo a chamada a uma outra funo. Listagem 3.10 Expresses na funo printf
#include <stdio.h> float f1 = 0.0, f2 = 0.0, f3 = 0.0; int main() { printf("Introduza tres floats: "); printf("\nValor devolvido = %d\n", scanf("%f %f %f", &f1, &f2, &f3)); printf("\nf1 = %f\tf2 = %f\tf3 = %f\n", f1, f2, f3); return 0; }
Embora no sejam muito usados, tambm possvel ler nmeros que no estejam sob o sistema decimal, isto , nmeros do sistema octal ou hexadecimal. Nesses casos, as especificaes de converso a utilizar so %o (octal) e %x (hexadecimal).
INETE Instituto de Educao Tcnica
21
As mesmas especificaes de converso podem ser usadas na funo printf() para escrever nmeros em octal e hexadecimal. Como j vimos ao executar os vrios exemplos deste manual, por defeito os nmeros floats so representados no cran com 6 casas decimais. No entanto, possvel formatar quantos espaos deve ocupar a representao de um nmero no cran, e quantas casas decmais deve contar. Para isso basta indicar na especificao de converso qual o espao total a reservar para a representao do nmero e quantas casas decimais devem ser usadas. Os exemplos seguintes ilustram essa utilizao. Listagem 3.12 Formatao dos dados de sada
/* Programa: FormatOut (JC2010) /* Formatao dos dados no printf */ #include <stdio.h> int i = 15, j = 35, k = -25, m = -55; float x = 4.567, y = -6.78; int main() { printf("\ni i ,j, k, printf("\ni i ,j, k, printf("\ni k ,m, y, printf("\ni k ,m, y, return 0; }
= %d\tj = %d\tk = %f\ti = %6.3d\tj = %6.3d\tk = %6.3f\n", i, j, k); = %-d\tj = %+d\tk = %-f\ti = %-6.3d\tj = %-6.3d\tk = %-6.3f\n", i, j, k); = %d\tj = %d\tk = %f\ti = %6.3d\tj = %6.3d\tk = %6.3f\n", k, m, y); = %-d\tj = %+d\tk = %-f\ti = %-6.3d\tj = %-6.3d\tk = %-6.3f\n", k, m, y);
22
23
3.6 Exerccios.
1. Escrever uma instruo printf() e puts() que execute uma mudana de linha. 2. Escrever uma instruo scanf() que leia um caracter, um inteiro sem sinal e um outro caracter. 3. Escrever as instrues necessrias para ler um inteiro e imprimir o valor lido. 4. Alterar o exerccio anterior, por forma a s aceitar nmeros pares. 5. Alterar o exerccio anterior, de forma que leia valores at ser introduzido o nmero 99 ou at ter lido seis nmeros pares. Os nmeros lidos devem ser guardados num array. 6. Construir o programa completo do exerccio anterior, adicionando uma funo que imprima os valores separados por tabs, numa nica linha. 7. Indicar o(s) erro(s) contido(s) na seguinte instruo:
printf("Jack said, "Peter Piper picked a peck of pickled peppers."");
8. Escrever um programa que leia dois valores reais e mostre o resultado do produto entre esses dois nmeros. 9. Escrever um programa que leia 10 valores inteiros e mostre a soma desses nmeros. 10. Escrever um programa que leia valores inteiros, guarde-os num array, e que mostre qual o maior e o menor nmero introduzido.
24
4.1 Instrues
Uma instruo uma directiva ao computador para que este execute determinada tarefa. Em C, uma instruo, qualquer que seja o seu tipo, termina com ;. Recorde-se que esta regra no se aplica a directivas de pr-processamento (por exemplo #define). Uma instruo pode ser:
x = 2 + 3;
que a instruo de afectao. Os compiladores de C no so sensveis aos espaos, tabs ou mesmo linhas em branco usadas nas instrues. O compilador ir percorrer o texto procura de um ; de modo a avaliar a legalidade da instruo, mas nesse processo ignora todos e quaisquer espaos em branco. Assim, a instruo
x=2+3;
equivalente a
x = 2 + 3;
ou a
x 2 + 3; =
No entanto, para que o programa possa ser considerado legvel deve obedecer regra de uma instruo por linha e devidamente indentado. Nesta regra de compilao (serem ignorados os espaos em branco) existe uma excepo: Numa constante literal do tipo string, os espaos ou tabs so considerados como parte dessa string. Assim, a instruo seguinte vlida:
printf( "Hello, world!" );
Como evidente, podemos ter uma situao em que uma string tem um comprimento tal que seria aconselhvel escreve-la em duas ou mais linha. Para que isso seja possvel necessrio usar uma backslash (\) ou fechar as aspas antes da quebra da string.
25
Uma linha constituda por uma instruo que unicamente ; embora no execute nenhuma aco, uma instruo vlida e tem o nome de null statement. Embora parea absurdo, a null statement pode ser til num programa em C.
Um bloco pode ser usado em qualquer parte onde uma instruo simples possa ser usada. Note-se que a localizao das chavetas pode tomar vrias alternativas. Por exemplo, o bloco acima podia ser escrito como:
{printf("Hello, "); printf("world!");}
4.2 Expresses
Uma expresso alguma coisa que evolui para um valor numrico. A expresso mais simples que podemos ter em C consiste num nico termo: uma varivel, uma constante literal ou uma constante simblica. Vejamos alguns exemplos: Expresso PI 20 fTaxa Descrio Constante simblica (definida no programa) Constante literal Varivel
Uma constante literal evolui para o seu prprio valor, a constante simblica evolui para o valor definido aquando da sua criao atravs na directiva #define, e a varivel evolui para o valor assignado pelo programa. As expresses mais complexas consistem em ligar estes trs tipos de expresses atravs de operadores. Por exemplo:
2 + 8 1.25 / 8 + 5 * fTaxa + fTaxa * fTaxa / nCusto
Quando uma expresso tem vrios operadores, a sua evoluo depende da precedncia dos operadores, que veremos mais frente.
4.3 Operadores
Um operador um smbolo que indica que operao ou aco deve ser realizada com um ou mais operandos. Em C, todos os operandos so expresses. Os operadores podem ser divididos nas seguintes categorias:
26
Os operadores aritmticos executam uma determinada operao matemtica. Em C existem dois operadores unrios e cinco binrios. Tabela 4.1 Operadores aritmticos unrios Operador Smbolo Aco Incremento ++ Incrementa o operando uma unidade Decremento -Decrementa o operando uma unidade Exemplos ++x x++ --x x--
Estes dois operadores s podem ser usados com variveis, nunca em constantes. Note-se que ++x equivalente a x = x + 1 e --y equivalente a y = y - 1 Como os operadores unrios podem ser usados tanto como prefixos como sufixos necessrio atender ao seu comportamento especfico em cada um dos casos. Assim, temos:
ou
x = 10; y = ++x; /* y=11; x=11 */
A listagem seguinte ilustra as diferenas entre o modo prefixo e sufixo. Listagem 4.1 Utilizao dos operadores unrios
/* Programa: OperUnarios (JC2011) * Demonstracao dos operadores unarios */ #include <stdio.h> int a, b; int main() { a = b = 5; /* Uso de prefixo em b, sufixo em a */ printf(" a b\n"); printf("----------", a--, --b); printf("\n%3d %3d", a--, --b); printf("\n%3d %3d", a--, --b); printf("\n%3d %3d", a--, --b); printf("\n%3d %3d", a--, --b); printf("\n%3d %3d\n", a--, --b); return 0; }
27
A tabela seguinte mostra os operadores aritmticos binrios vlidos em C. Tabela 4.2 Operadores aritmticos binrios Operador Smbolo + Soma Subtraco * Multiplicao / Diviso % Resto da diviso inteira O programa seguinte ilustra o operador Resto. Listagem 4.2 Utilizao do operador resto da diviso inteira
//Listagem 4.2 - Demosntrao do operador resto da diviso inteira /* Programa: Resto (JMC2010) * Recebe um numero em segundos e converte em horas, minuto e segundos */ #include <stdio.h> /* Definio das constantes */ #define SECS_PER_MIN 60 #define SECS_PER_HOUR 3600 unsigned seconds, minutes, hours; unsigned secs_left, mins_left; int main() { /* Input da quantidade de segundos */ printf("Introduza o numero de segundos (< 65000): "); scanf("%d", &seconds); /* Converso em HH, MM e SS */ hours = seconds / SECS_PER_HOUR; minutes = seconds / SECS_PER_MIN; mins_left = minutes % SECS_PER_MIN; secs_left = seconds % SECS_PER_MIN; printf("%u segundos e' igual a ", seconds); printf("%u h, %u m e %u s\n", hours, mins_left, secs_left); return 0; }
Exemplo x + y x - y x * y x / y x % y
28
Neste exemplo, no sabemos se x/y realizada antes ou depois de z/y, j que contm o mesmo operador. Para se perceber a importncia desse aspecto, consideremos o seguinte exemplo:
w * x / ++y + z / y
Se a subexpresso da esquerda evoluir em primeiro lugar, ento z/y sente j o incremento de y, resultando um valor diferente do que chegaramos se a subexpresso da direita evoluir em primeiro lugar. Assim, como a gramtica no especifica estas situaes, elas devem ser evitadas usando-se parntesis.
29
Embora a utilizao mais comum das expresses relacionais seja feita em instrues do tipo if...else ou em construes condicionais, podem tambm ser usados como se fossem puros valores numricos. Vejamos um exemplo ilustrativo: Listagem 4.3 Utilizao de operadores relacionais
/* Programa: OperRelaciona (JC2010) * Demonstra a evaluao de uma expresso relacional */ #include <stdio.h> int a; int main() { a = (5 == 5); /* Evolui para 1 */ printf("\na = (5 == 5)\na = %d", a); a = (5 != 5); /* Evolui para 0 */ printf("\na = (5 != 5)\na = %d", a); a = (12 == 12) + (5 != 1); /* Evolui para 1+1 */ printf("\na = (12 == 12) + (5 != 1)\na = %d\n", a); return 0; }
A tabela seguinte define as precedncias dos operadores mais comuns do C: Tabela 4.7 Precedncias dos operadores em C Nvel Operador 1 ! ++ -- +(sinal) -(sinal) */ % 2 3 +(soma) -(subtrao) < <= > >= 4 == != 5 6 && (AND) 7 || (OR) ?: 8 = += -= *= /= %= 9
30
4.4 Exerccios
1. O cdigo seguinte no se encontra bem escrito. Introduza-o no compilador e verifique se funciona.
#include <stdio.h> int x,y;int main(){ printf( "\nEnter two numbers");scanf( "%d %d",&x,&y);printf( "\n\n%d is bigger",(x>y)?x:y);return 0;}
2. Rescreva o programa anterior de forma a que seja mais legvel. 3. Qual o valor para que evoluem as seguintes expresses:
(1 10 (5 (x + 2 * 3) % 3 * 3 - (1 + 2) == 5) = 5)
31
5.1 Instruo if
A forma simples da instruo if : if(expresso) instruo; Na sintaxe anterior, se expresso evoluir para um valor correspondente a TRUE, ento a instruo executada. Caso contrrio essa instruo ignorada. Assim, semelhana de outras linguagens, podemos dizer que a execuo da instruo depende do resultado da expresso. Quando a instruo if encontrada no programa, nesta forma simplificada, so realizadas as seguintes aces: 1. 2. A expresso expresso evolui para o seu resultado. Esta expresso normalmente uma condio lgica; Se o resultado final FALSE (ou seja, zero), a instruo if termina de imediato. Se o resultado for TRUE (ou seja, diferente de zero), ento a instruo executada.
FALSE
A instruo executada
32
Se pretendermos executar mais que uma instruo teremos que utilizar um bloco de instrues, ou seja: if(expresso) { instruo1; instruo2; /* mais instrues... */ instruoN; } Um dos erros mais comuns ao utilizar-se a instruo if colocar o ; aps a expresso que se pretende avaliar. Por exemplo if(x == 2); instruo1; Isso faz com que a instruo1 no pertena ao if, j que o ; terminou a instruo logo aps a condio a analisar. No exemplo acima, a instruo a ser executada seria a instruo nula., ou seja, seria equivalente a ter a seguinte forma: if(x == 2) ; instruo1; Vejamos um exemplo na utilizao do if. Listagem 5.1 Utilizao da instruo if
/* Programa: IfSimples (JC2010) * Utilizao da instruo if */ #include <stdio.h> int x, y; int main() { /* Input dos dois valores a testar */ printf("\nIntroduza um valor inteiro para o x: "); scanf("%d", &x); printf("\nIntroduza um valor inteiro para o y: "); scanf("%d", &y); /* Teste dos valores e output do resultado */ if(x == y) printf("x e' igual ao y\n"); if(x > y) printf("x e' maior que o y\n"); if(x < y) printf("x e' mais pequeno que o y\n"); return 0;
33
A instruo if pode incluir, opcionalmente, a clusula else. Nessa forma, a instruo if ser:
if(expresso) instruo1; else instruo2;
Neste caso, se expresso evoluir para um valor correspondente a TRUE, ento a instruo1 executada. Caso contrrio, executada a instruo2. Quer a instruo1 quer a instruo2 podem ser blocos de instrues, pelo que ter-se- que usar um par de chavetas em cada bloco:
if(expresso) { instruo1-1; instruo1-2; /* mais instrues */ instruo1-N; } else { instruo2-1; instruo2-2; /* mais instrues */ instruo2-N; }
TGPSI PSI: Manual de C if(expresso) instruo1; else instrucao2; instrucao_seguinte; if(expresso1) instruo1; else if(expressao2) instrucao2; else instruo3; instruo_seguinte;
34
O exemplo seguinte segue a lgica da listagem anterior, verificando tambm se a metade do nmero introduzido tambm par. Listagem 5.4 Utilizao da instruo if encadeado
/* Programa: IfElse3 (JC2010) * Utilizao da instruo ifs encadeados */ #include <stdio.h> int main() { long int test = 0; /* Input do numero a analisar */ printf("Introduza um inteiro: "); scanf("%ld", &test); /* Teste do numero (impar ou par) */ if(test % 2 == 0) { printf("\nO numero %ld e' par.\n", test);
TGPSI PSI: Manual de C /* Teste da metade do numero original */ if((test / 2) % 2 == 0) { printf("\nA metade de %ld tambem e' par!", test); printf("\nInteressante, nao e'?\n"); } } else printf("\nO numero %ld e' impar.\n", test); return 0; }
35
O exemplo seguinte l uma letra maiscula e converte-a para a letra minscula correspondente. Caso no seja introduzida uma letra maiscula, assinalado esse facto. Listagem 5.5 - Utilizao da instruo if encadeado (2)
/* Programa: IfElse4 (JC2010) * Conversao de maisculas em minsculas */ #include <stdio.h> int main() { char letra; /* Input da letra maiscula */ printf("\nIntroduza uma letra maiuscula: "); scanf("%c", &letra); /* Verifica se o caracter introduzido e' uma letra maiscula */ if(letra >= 'A') if (letra <= 'Z') { /* e' uma letra maiscula */ letra = letra + ('a' - 'A'); /* converso em minscula */ printf("\nIntroduziu a maiuscula de \'%c\'.\n", letra); } else /* O char e' uma letra mas no e' uma letra maiscula */ printf("\nQue tal usar a tecla SHIFT?! Pretende-se uma letra " "maiuscula!"); return 0; }
O exemplo seguinte segue a lgica da listagem anterior, mas agora sem utilizar os ifs encadeados. Listagem 5.6 Utilizao da instruo if...else (3)
/* Programa: IfElse5 (JC2010) * Conversao de maisculas em minsculas (2)*/ #include <stdio.h> int main() { char letra; /* Input da letra maiscula */ printf("\nIntroduza uma letra maiuscula: "); scanf("%c", &letra); INETE Instituto de Educao Tcnica
36
/* Verifica se o caracter introduzido e' uma letra maiscula */ if(letra >= 'A' && letra <= 'Z') { /* e' uma letra maiscula */ letra = letra + ('a' - 'A'); /* converso em minscula */ printf("\nIntroduziu a maiuscula de \'%c\'.\n", letra); } else /* O char e' uma letra mas no e' uma letra maiscula */ printf("\nQue tal usar a tecla SHIFT?! Pretende-se uma letra maiuscula!"); return 0; }
Como x diferente de zero, o if ir interpretar a expresso x como verdadeira pelo que ir executar sempre a funo printf(). De um modo geral podemos dizer que: (expresso) equivalente a (expresso != 0) j que ambas as expresses evoluem para TRUE, se expresso resultar num valor diferente de zero, e evoluem para FALSE, se expresso for zero. Utilizando o operador NOT (!), podemos tambm dizer que: (!expresso) equivalente a (expresso == 0) Para ficar mais clara a noo dos operadores relacionais e a sua precedncia, vejamos o seguinte exemplo: Listagem 5.7 Utilizao de operadores relacionais
/* Programa: OperRelacional2 (JC2010) * Utilizao de expresses lgicas */ #include <stdio.h> /* Inicializao das variveis. Note-se que c no pode ser * menor que d, seno toda a expresso iria evoluir para FALSE. */ int a = 5, b = 6, c = 5, d = 1; int x; int main() { /* Evoluo da expresso sem parentesis */ x = a < b || a < c && c < d; printf("\nSem parentesis a expressao evolui para %d", x); INETE Instituto de Educao Tcnica
TGPSI PSI: Manual de C /* Evoluo da expresso com parentesis */ x = (a < b || a < c) && c < d; printf("\nCom parentesis a expressao evolui para %d\n", x); return 0; }
37
A instruo anterior indica que se pretende adicionar varivel esquerda da afectao (neste caso, a varivel x) o valor que a varivel j armazena com o valor que est direita da afectao. De uma maneira geral, as instrues de afectao compostas tm a seguinte forma: exp1 op= exp2 que equivalente a: exp1 = exp1 op exp2; Todos os operadores aritmticos reconhecidos pelo C admitem a sua utilizao neste tipo de instrues. A tabela seguinte mostra um exemplo para cada caso. Tabela 5.1 Instrues de afectao compostas Instruo Equivalente a x *= y x = x * y y -= z + 1 y = y - z + 1 a /= b a = a / b x += y / 8 x = x + y / 8 y %= 3 y = y % 3 Combinando esta potencialidade com o operador de afectao (=), as vantagens tornamse ainda mais evidentes. Por exemplo, o cdigo seguinte faz com que ambas as variveis, x e z, sejam afectadas com o valor 14 na ltima instruo.
x = 12; z = x += 2;
38
Se expresso1 evolui para TRUE, ento toda a expresso evolui para o valor da expresso2. Se a expresso1 evolui para FALSE, ento toda a expresso evolui para o valor da expresso3. Como se pode observar, este comportamente muito semelhante ao da instruo if. Por exemplo, na expresso seguinte se x igual a y, ento toda a expresso evolui para 1, seno evolui para 100.
x == y ? 1 : 100;
o que equivalente a:
if(x > y) z = x; else z = y;
Finalmente, note-se que este operador pode ser utilizado mesmo em situaes em que no possvel usar a instruo if:
printf("O maior valor e %d", ((x > y) ? x : y));
Por exemplo, no cdigo seguinte o valor de b atribudo a x, depois a varivel a incrementada e, por fim, incrementada a varivel b.
x = (a++ , b++);
Como facilmente se percebe, a utilizao deste operador deve ser feita com extrema precauo, e, por isso, a sua maior utilizao feita no ciclo for, que iremos estudar mais frente.
TGPSI PSI: Manual de C puts("Seleccione 2 para a tarefa B."); puts("Seleccione 3 para a tarefa C."); puts("Seleccione 4 para a tarefa D."); puts("Seleccione 5 para sair do programa."); /* leitura da opco do user */ scanf("%d", &opc); if(opc == 1) puts("\nExecutando a opcao A."); else if(opc == 2) puts("\nExecutando a opcao B."); else if(opc == 3) puts("\nExecutando a opcao C."); else if(opc == 4) puts("\nExecutando a opcao D."); else if(opc == 5) { puts("\nA sair do programa...\n"); return 0; } else puts("\nEscolha invalida!\n"); return 0; }
39
A forma geral da instruo : switch(expresso_inteira) { case valor_1: instruco(es); case valor_2: instruco(es); ... case valor_n: instruco(es); default: instruco(es); } A expresso_inteira uma qualquer expresso que evolua para um valor inteiro. A instruo switch evolui a expresso_inteira e compara o resultado com os vrios valores presentes nos case (pela ordem que surgem na instruo) acontecendo uma das seguintes situaes: Se encontrado um valor igual ao valor inteiro da expresso_inteira, a execuo do programa passa para a instruo imediatamente a seguir ao valor. Se no encontrado nenhum valor igual, ento a execuo do programa passa para a instruo imediatamente a seguir ao rtulo default (se existir). Se no encontrado nenhum valor igual e no existe rtulo default, ento a execuo do programa passa para a instruo imediatamente a seguir instruo switch.
40
A instruo switch termina quando encontrada a instruo break (passando a execuo do programa para instruo passa a seguir ao switch) ou quando encontrado a chaveta que fecha a instruo switch. A listagem seguinte demonstra o uso desta instruo. Listagem 5.9 Utilizao da instruo switch
/* Programa: switch1 (JC210) * Utilizao da instruo switch */ #include <stdio.h> int main() { int selec; puts("Introduza um numero entre 1 e 5:"); scanf("%d", &selec); switch(selec) { case 1: puts("Escolheu a opcao 1."); case 2: puts("Escolheu a opcao 2."); case 3: puts("Escolheu a opcao 3."); case 4: puts("Escolheu a opcao 4."); case 5: puts("Escolheu a opcao 5."); default: puts("Opcao invalida. Tente outra vez."); } return 0; }
Como podemos ver, aps terminar a execuo das instrues correspondentes ao valor igual ao valor da expresso do switch, a instruo no termina, continuando a executar todos as instrues at terminar o corpo do switch. aqui que til a instruo break. No esquea que num switch a instruo break serve para terminar de imediato a execuo desse switch (independetemente do ponto do switch onde o break executado). Listagem 5.10 Utilizao da instruo switch (2)
/* Programa: switch2 (JC210) * Utilizao da instruo switch (2) */ #include <stdio.h> int main() { int selec; INETE Instituto de Educao Tcnica
41
SetConsoleTitle(TEXT("Listagem 5.10 Utilizao da instruo switch (2)")); printf("Introduza um numero entre 1 e 5: "); scanf("%d", &selec); switch(selec) { case 1: puts("Escolheu a opcao 1."); break; case 2: puts("Escolheu a opcao 2."); break; case 3: puts("Escolheu a opcao 3."); break; case 4: puts("Escolheu a opcao 4."); break; case 5: puts("Escolheu a opcao 5."); break; default: puts("Opcao invalida. Tente outra vez."); } return 0; }
H casos em que queremos que, uma vez encontrado um valor igual ao resultado da expresso do switch, sejam executadas as instrues de vrios valores. A listagem seguinte ilustra esse aspecto. Listagem 5.11 Utilizao da instruo switch (3)
/* Programa: Switch3 * Utilizao avanada da instruco switch */ #include <stdio.h> #include <stdlib.h> int main() { int selec, cnt = 0; printf("\nIntroduza um valor entre 1 e 10. 0 para sair: "); scanf("%d", &selec); switch(selec) { case 0: puts("Escolheu 0.\n"); exit(0); case 1: cnt++; case 2: cnt++; case 3: cnt++; case 4: cnt++; case 5: cnt++; puts("Escolheu 5 ou menos.\n"); break; INETE Instituto de Educao Tcnica
TGPSI PSI: Manual de C case 6: cnt++; case 7: cnt++; case 8: cnt++; case 9: cnt++; case 10: cnt++; puts("Escolheu 6 ou mais.\n"); break; default: puts("So' sao aceites numeros entre 1 e 10!\n"); } /* fim do switch */ printf("Foram executados %d cases.\n", cnt); return 0; }
42
Neste programa anterior usou-se uma nova function library, a exit(). Isto deve-se ao facto de queremos simular uma opo para terminar o programa e o break terminaria a execuo da instruo switch, mas iria executar o ltimo printf(). Assim, ao ser introduzido o valor 0 o programa termina de imediato.
TGPSI PSI: Manual de C case 'C': case 'c': puts("Introduziu a letra 'C' ou 'c'"); break; /* igual para as restantes letras de D a Z*/ default: printf("O caracter %c nao e' uma letra!\n", letra); } return 0; }
43
5.6 Exerccios.
1. Escrever uma instruo if que atribua a uma varivel y o valor de x, mas s no caso de x conter um valor entre 1 e 20. Caso contrrio, deixar a varivel y sem alterao. 2. Utilizar o operador ?: para resolver o exerccio anterior. 3. Escrever uma instruo if que determine quando um indivduo maior, mas no atingiu ainda a terceira idade (idade igual ou superior a 65 anos). 4. Indique se h algum problema com o seguinte cdigo.
switch(answer) { case 'Y': printf("Escolheu \"yes\""); break; case 'N': printf("Escolheu \"no\""); }
6. Reescreva a listagem do problema anterior utilizando intrues if. 7. Construa um programa que actue como uma calculadora. O programa deve suportar as operaes de adio, subtrao, multiplicao e diviso.