Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 2 Sumrio INTRODUO ........................................................................................................................................ 3 EXPRESSES ........................................................................................................................................... 4 TIPOS BSICOS DE DADOS .............................................................................................................................. 4 NOMES DE IDENTIFICADORES .......................................................................................................................... 5 VARIVEIS ................................................................................................................................................... 5 OPERADORES ............................................................................................................................................... 9 ABREVIAES EM C ..................................................................................................................................... 12 COMANDOS DE CONTROLE .................................................................................................................. 13 COMANDOS DE SELEO .............................................................................................................................. 13 COMANDOS DE ITERAO ............................................................................................................................ 18 COMANDOS DE DESVIOS .............................................................................................................................. 22 MATRIZES E STRINGS ........................................................................................................................... 26 MATRIZES UNIDIMENSIONAIS........................................................................................................................ 26 PASSANDO VETORES PARA FUNES ............................................................................................................... 27 STRINGS .................................................................................................................................................... 28 MATRIZES BIDIMENSIONAIS .......................................................................................................................... 30 MATRIZES DE STRINGS ................................................................................................................................. 31 INICIALIZAO DE MATRIZES ......................................................................................................................... 32 PONTEIROS .......................................................................................................................................... 33 VARIVEIS PONTEIROS ................................................................................................................................. 33 OPERADORES DE PONTEIROS......................................................................................................................... 33 ATRIBUIO DE PONTEIROS .......................................................................................................................... 34 INCREMENTANDO E DECREMENTANDO PONTEIROS ........................................................................................... 35 COMPARAO DE PONTEIROS ....................................................................................................................... 36 PONTEIROS E VETORES ................................................................................................................................ 36 PONTEIROS E STRINGS ................................................................................................................................. 37 ALOCAO DINMICA DE MEMRIA .............................................................................................................. 38 PONTEIROS E MATRIZES ............................................................................................................................... 40 VETORES DE PONTEIROS .............................................................................................................................. 41 PONTEIROS PARA PONTEIROS ........................................................................................................................ 42 FUNES ............................................................................................................................................. 44 FUNES RECURSIVAS ................................................................................................................................. 45 FUNES QUE RETORNAM PONTEIROS ............................................................................................................ 46 ESTRUTURAS ........................................................................................................................................ 47 REFERECIANDO ELEMENTOS DE ESTRUTURAS ................................................................................................... 48 MATRIZES DE ESTRUTURAS ........................................................................................................................... 49 PASSANDO ESTRUTURAS PARA FUNES .......................................................................................................... 49 PONTEIROS PARA ESTRUTURAS ...................................................................................................................... 51 ESTRUTURAS ANINHADAS ............................................................................................................................. 52 ENTRADA/SADA PELO CONSOLE ......................................................................................................... 53 FUNO: PRINTF() ...................................................................................................................................... 54 FUNO: SCANF() ....................................................................................................................................... 56 ENTRADA/SADA COM ARQUIVO ......................................................................................................... 58 STREAMS E ARQUIVOS ................................................................................................................................. 58 SISTEMA DE ARQUIVOS ................................................................................................................................ 59 FUNES PARA ARQUIVOS ........................................................................................................................... 61 Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 3
Captulo 1 Introduo
A linguagem C foi inventada na dcada de 70. Ela considerada uma linguagem de mdio nvel por combinar elementos de linguagens de alto nvel com a simplicidade e funcionalidade de linguagens de baixo nvel. Os cdigos feitos pela linguagem C so bastante portveis porque podem se adaptar a um software escrito de um tipo de computador a outro. Em geral, o C considerado uma linguagem estruturada, o que permite a compartimentalizao do cdigo e dos dados. Sua principal componente estrutural a funo. Funes so blocos de construo em que toda a atividade do programa ocorre, e elas admitem que voc defina e codifique separadamente as diferentes tarefas de um programa, permitindo, ento, que seu programa seja modular. Aps uma funo ter sido criada, voc pode contar com que ela trabalhe adequadamente em vrias situaes, sem criar efeitos inesperados em outras partes do programa. O fato de voc poder criar funes isoladas extremamente importante em projetos maiores onde um cdigo de um programador no deve afetar acidentalmente o de outro. Outra maneira de estruturar e compartimentalizar o cdigo em C atravs do uso de blocos de cdigo. Um bloco de cdigo um grupo de comandos de programa conectado logicamente que tratado como uma unidade. Em C, um bloco de cdigo criado colocando-se uma seqncia de comandos entre chaves. Nesse exemplo
os dois comandos aps o if e entre chaves so executados se x for igual a 4. Esses dois comandos, junto com as chaves, representam um bloco de cdigo, o que permite que muitos algoritmos sejam implementados com clareza, elegncia e eficincia. Todo compilador C vem com uma biblioteca (que um arquivo contendo as funes padro que seu programa pode usar) C padro de funes que realizam as tarefas necessrias mais comuns.
if (x == 4) { printf(Parabens, voce acertou, x 4); _getch(); }
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 4 Captulo 2 - Expresses
Tipos Bsicos de Dados
Todas as linguagens de programao de alto nvel suportam o conceito de tipos de dados, onde um tipo de dado define um conjunto de valores que uma varivel pode armazenar e o conjunto de operaes que pode ser executado com essa varivel. No C, existem 5 tipos bsicos de dados, que so: caractere (char), inteiro (int), ponto flutuante (float), ponto flutuante de preciso dupla (double) e sem valor (void).
O tipo char utilizado para especificar valores definidos pelo conjunto de caracteres ASCII, este conjunto contm letras, smbolos e at mesmo algarismos, porm os algarismos no podero ser manipulados matematicamente.
O tipo int utilizado para especificar algarismos inteiros, sendo que estes sim podero ser manipulados matematicamente.
Os tipos float e double so utilizados para especificar algarismos contnuos (fracionrios), sendo que o double aborda uma faixa de nmeros maior do que o float e com maior preciso. O padro ANSI especifica que a faixa mnima de um valor em ponto flutuante de 1e-37 a 1e+37.
O tipo void declara explicitamente uma funo que no retorna valor algum ou cria ponteiros genricos, ou seja, utiliza-se void sempre em que no h necessidade de retornar algum valor.
Tipo Tamanho Intervalo unsigned char 8 bits 0 at 255 char 8 bits -128 at 127 short int 16 bits -32,768 at 32,767 unsigned int 32 bits 0 at 4,294,967,295 int 32 bits -2,147,483,648 at 2,147,483,647 unsigned long 32 bits 0 at 4,294,967,295 enum 16 bits -2,147,483,648 at 2,147,483,647 long 32 bits -2,147,483,648 at 2,147,483,647 float 32 bits 3.4 x 10-38 at 3.4 x 10+38 double 64 bits 1.7 x 10-308 at 1.7 x 10+308 long double 80 bits 3.4 x 10-4932 at 1.1 x 10+4932
Obs.: O tipo float possui 6 dgitos de preciso, enquanto que os tipos double e long double possuem 10 dgitos de preciso.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 5 Nomes de Identificadores
So considerados identificadores: os nomes de variveis, funes, rtulos e vrios outros objetos definidos pelo usurio. Esses identificadores podem variar de um a diversos caracteres. O primeiro caractere deve ser uma letra ou um sublinhado e os caracteres subseqentes devem ser letras, nmeros ou sublinhados. Abaixo se encontram alguns exemplos:
Correto Incorreto valor 1valor Teste1 Ola&todos calculo_fatorial calculo...fatorial
A linguagem C diferencia as letras maisculas e minsculas, portanto: valor, Valor e VALOR so trs identificadores distintos. Um identificador no pode ser igual a uma palavra-chave de C e no deve ter o mesmo nome que as funes que voc escrever ou as que esto na biblioteca C.
Variveis
Uma varivel uma posio de memria com um nome, que usada para guardar um valor que pode ser modificado pelo programa. Todas as variveis em C devem ser declaradas antes de serem usadas. A forma geral de uma declarao :
tipo nome_da_varivel;
Onde, tipo deve ser um ser um tipo vlido em C, como aqueles vistos anteriormente; e nome_da_varivel deve obedecer s regras vistas na seo nome de identificadores, podendo consistir em um ou mais nomes de identificadores separados por vrgulas. Abaixo esto alguns exemplos:
int i, j, l; char letra; double valor; float peso, altura;
Todas as variveis so constitudas de dois valores, o primeiro a posio de memria, este um valor hexadecimal. O segundo o valor contido nele, este pode ser manipulado. Exemplo:
#include <conio.h> #include <stdio.h>
void main() { int y = 25; /*y assume o valor 25*/
/* imprime o valor da posio de memoria em hexadecimal */ printf("A posicao de memoria (hexadecimal) e: %X", &y);
/* imprime o valor da posio de memoria em decimal */ printf("\n\nA posicao de memoria (decimal) e: %d", &y);
/* imprime o valor de definido pelo programador */ printf("\n\nO valor contido em x e: %d", y); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 6
As variveis sero declaradas em trs lugares bsicos: dentro de funes (chamadas de variveis locais), na definio de parmetros das funes (chamadas de parmetros formais) e fora de todas as funes (chamadas de variveis globais).
Variveis locais so aquelas declaradas dentro de um determinado bloco, portanto elas no so reconhecidas fora de seu prprio bloco de cdigo. Lembrando que um bloco de cdigo comea com um abre-chave e termina com uma fecha-chave. Estas variveis existem apenas dentro deste bloco onde foram declaradas, portanto ela criada na entrada do seu bloco e destruda na sada.
Exemplo:
A varivel x foi declarada duas vezes, uma vez em funcao1( ) e outra em funcao2( ). O x na primeira funo no tem nenhuma relao com a segunda, isso ocorre porque ela uma varivel local, e funciona somente dentro do bloco em que foi declarada. Quando sai da primeira funo esta varivel destruda, acontecendo o mesmo na sada da segunda.
A maioria dos programadores declara todas as variveis usadas por uma funo imediatamente aps o abre-chaves da funo e antes de qualquer outro comando. Porm, as variveis locais podem ser declaradas dentro de qualquer bloco de cdigo. Exemplo:
void funcao1() { int x; x = 15; }
void funcao2() { int x; x = -33; } void funcao() { int x; scanf(%d, &x);
if( x = = 1) /*no h espao entre os sinais de igual*/ { int y = 5; /*esta varivel s criada na entrada deste bloco*/ printf(O resultado : %d, (x+y)); } } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 7 Nesta funo, a varivel y criada na entrada do bloco de cdigo if e destruda na sada. Alm disso, y reconhecida apenas dentro do bloco if e no pode ser diferenciada em qualquer outro lugar.
Parmetros formais: Se uma funo usa argumentos, ela deve declarar variveis que recebero os valores dos argumentos, estas variveis so chamadas de parmetros formais. Elas se comportam como qualquer outra varivel local dentro da funo. Exemplo:
Nos prximos captulos ser ensinado como realizar chamada de funes, passando variveis como parmetros. Neste exemplo, prestemos ateno na funo soma(), ela tem como parmetros de entrada as variveis a e b (ambos inteiros), estas variveis funcionam apenas neste bloco, sendo destrudas aps a sada da funo, se comportando assim como variveis locais. Importante: Voc deve ter certeza de que os parmetros formais que esto declarados so do mesmo tipo dos argumentos que voc utiliza para chamar a funo. Se h uma discordncia de tipos, resultados inesperados podem ocorrer.
Variveis globais so, ao contrrio das variveis locais, reconhecidas pelo programa inteiro e podem ser usadas por qualquer pedao do cdigo. Elas guardam seus valores durante toda a execuo do programa. Elas so criadas declarando-as fora de qualquer funo e podem ser acessadas por qualquer expresso independente de qual bloco de cdigo contm a expresso.
Vide no programa seguinte, valor foi declarada fora de todas as funes, portanto uma varivel global. Exemplo:
/* declarao da funo soma, declarando tambm a e b como parmetros formais da funo*/ int soma(int a, int b) return (a+b);
void main() { int x = 1, y = 5, z; z = soma(x,y); /* aqui ocorre uma chamada de funo, passando x e y como argumentos*/ printf(%d, z); /* imprime 6 na tela */ } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 8
A imagem abaixo o resultado do programa apresentado acima:
Observe este programa. As funes main( ) e funcao1( ) usaram a varivel valor mesmo sem t-la declarado. J a funcao2( ) declarou uma varivel local chamada valor, ou seja, com o mesmo nome com da varivel global. Quando isso acontece, todas as referncias ao nome da varivel dentro do bloco onde a varivel local foi declarada dizem respeito somente a ela mesma e no tem qualquer efeito sobre a varivel global. Notamos isso no programa acima, quando a funcao1( ) faz a chamada da funcao2( ) valor recebe a atribuio 40, que imprimido na tela, mas como uma varivel local, essa destruda assim que sai do bloco, voltando assim para a funcao1( ), bloco onde valor igual a 50.
Variveis globais so teis quando o mesmo dado usado em muitas funes em seu programa. No entanto, voc deve evitar usar variveis globais desnecessrias. Elas ocupam memria durante todo o tempo em que seu programa est executando, no apenas quando so necessrias.
int valor; void funcao1(); void funcao2();
void main() { valor = 100; printf(%d : na funcao main, valor); funcao1(); getch(); }
void funcao1() { valor = 50; printf(\n%d : na funcao 1 depois de valor = 50, valor); funcao2(); printf(\n%d: na funcao 1 depois de ter passado pela funcao 2, valor); }
void funcao2() { int valor; valor = 40; printf(\n%d : na funcao 2 depois de declara valor = 40 como variavel local, valor); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 9 Operadores
A linguagem C possui quatro classes de operadores: aritmticos, relacionais, lgicos e bit a bit. Alm de ter alguns operadores especiais para tarefas particulares.
Operador de Atribuio
Voc pode usar o operador de atribuio dentro de qualquer expresso vlida de C. A forma geral do operador de atribuio :
Nome_da_varivel = expresso;
Onde expresso pode ser uma simples constante ou uma expresso to complexa quanto voc necessite. Voc ver dois termos: lvalue e rvalue, onde lvalue se refere ao termo do lado esquerdo do igual, e rvalue do lado direito. O lvalue o destino da atribuio, ele sempre deve ser uma varivel ou um ponteiro, enquanto que o rvalue deve ser uma constante ou funo. Exemplos:
X = 40; // atribuio de uma constante inteira. Y = 3.1234; // atribuio de uma constante tipo float. Z = x + 2y; // atribuio de uma funo.
Converso de Tipos em Atribuies
Converso de tipos refere-se situao em que variveis de um tipo so misturadas com variveis de outro tipo. Em um comando de atribuio, o valor do lado direito (rvalue) de uma atribuio convertido no tipo do lado esquerdo (lvalue), como segue no exemplo abaixo:
#include <conio.h> #include <stdio.h>
void main() { int x = 2; char ch; float f = 30.6954;
ch = x; /* linha 1 */ printf("ch = %c", ch);
x = f; /* linha 2 */ printf("\nx = %d", x);
f = ch; /* linha 3 */ printf("\nf = %f", f);
f = x; /* linha 4 */ printf("\nf = %f", f); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 10 Se executarmos o programa, teremos os seguintes resultados:
Na linha 1, x est entre 0 e 156, portando ch e x possuem valores idnticos, que nesse caso 2. De outra forma, o valor de ch reflete apenas os bits menos significativos de x. Na linha 2, x recebe a parte inteira de f. Na linha 3, f converte o valor inteiro de 8 bits armazenado em ch no mesmo valor em formato de ponto flutuante. Isso tambm ocorre na linha 4, exceto por f converter um valor inteiro de 16 bits no formato de ponto flutuante.
Operadores Aritmticos
A tabela abaixo lista os operadores aritmticos de C, e suas aes.
O menos unrio multiplica seu nico operando por -1. Isto , qualquer nmero precedido por um sinal de menos troca de sinal.
Incremento e Decremento
C inclui dois operadores teis geralmente no encontrados em outras linguagens. So os operadores de incremento e decremento, ++ e --. O operador ++ soma 1 ao seu operando, e -- subtrai 1. Em outras palavras:
Ambos os operadores de incremento e decremento podem ser utilizados como prefixo ou sufixo do operando.
Prefixo Sufixo ++x; x++;
Expresso o mesmo que Ou ainda x = x + 1; ++x; x++; Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 11 Porm, h uma diferena quando esses operadores so usados em uma expresso. Quando um operador de incremento ou decremento precede seu operando, C executa a operao de incremento ou decremento antes de usar o valor do operando. Se o operador estiver aps seu operando, C usa o valor do operando antes de increment-lo ou decrement-lo. Considere o seguinte:
X = 10; Y = ++x;
Coloca 11 em y. Porm se o cdigo fosse escrito como
X = 10; Y = x++;
y receberia 10. Em ambos os casos, x recebe 11, a diferena est em quando isso acontece.
Operadores Relacionais e Lgicos
No termo operador relacional, relacional refere-se s relaes que os valores podem ter uns com os outros. No termo operador lgico, lgico refere-se s maneiras que essas relaes podem ser conectadas. Estes freqentemente trabalham juntos.
Operadores Relacionais Operador Ao > Maior que >= Maior ou igual que < Menor que <= Menor ou igual que = = Igual != Diferente
Operadores Lgicos Operador Ao && AND || OR ! NOT
A idia de verdadeiro e falso est por trs dos conceitos dos operadores lgicos e relacionais. Em C, falso zero, enquanto que verdadeiro qualquer valor diferente de zero. Abaixo temos a tabela verdade dos operadores lgicos, usando 1s e 0s.
x y x&&y x||y !x 0 0 0 0 1 0 1 0 1 1 1 0 1 1 0 1 1 0 1 0 Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 12 Ambos os operadores so menores em precedncia do que os operadores aritmticos. Isto , uma expresso como 12 > 1 + 12 avaliada como se fosse escrita 12 > (1 + 12). O resultado , obviamente, falso. permitido combinar diversas operaes em uma expresso como mostrado aqui: 10 > 5 && !(10 < 9) || 3 <= 4 Neste caso, o resultado verdadeiro.
Casts
possvel forar uma expresso a ser de um tipo usando uma construo chamada cast. A forma geral de um cast
(tipo) expresso
onde tipo um tipo de dado padro de C. Por exemplo, para ter certeza de que a expresso x/2 ser do tipo float, escreva
(float) x / 2;
Exemplo:
Abreviaes em C
C oferece uma abreviao especial que simplifica a codificao de certos tipos de comandos de atribuio. A forma geral de uma abreviao C
variavel = variavel operador expresso;
o mesmo que
variavel operador = expresso;
Exemplos:
Expresso o mesmo que x = x + 8; x += 8; y = y / 6; y /= 6; z = z * y; z *= y;
#include <conio.h> #include <stdio.h>
void main() { int x = 10; printf("\nX/3 e igual a: %f", (float) x/3); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 13 Captulo 3 Comandos de Controle
No C existe vrios comando de controle do programa. O padro ANSI divide os comandos nestes grupos:
Seleo Iterao Desvio Rtulo Expresso Bloco
Comandos de Seleo
if ... else
A forma geral da sentena if
if ( expresso) comando; else comando;
onde comando pode ser um nico comando, um bloco de comandos ou nada. Enquanto que else opcional, seu uso no obrigatrio.
Se a expresso verdadeira (algo diferente de 0), o comando ou bloco que forma o corpo do if executado; caso contrrio, o comando ou bloco que o corpo do else (se existir) executado. Lembre-se de que apenas o cdigo associado ao if ou cdigo associado ao else ser executado, nunca ambos. Abaixo vemos o fluxograma correspondente a esta estrutura de deciso.
Condio? Bloco1 Bloco2 V F Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 14 O comando condicional controlando o if deve produzir um resultado escalar. Um escalar um inteiro (int), um caractere (char) ou tipo de ponto flutuante (float). No entanto, raro usar um nmero de ponto flutuante para controlar um comando condicional, porque isso diminui consideravelmente a velocidade de execuo. (A CPU executa diversas instrues para efetuar uma operao em ponto flutuante. Ela usa relativamente poucas instrues para efetuar uma operao com caractere ou inteiro).
Veja um exemplo do uso do if:
ifs Aninhados
Um if aninhado um comando if que o objeto de outro if ou else. ifs aninhados so muito comuns em programao. Em C, um comando else sempre se refere ao comando if mais prximo, que est dentro do mesmo bloco do else e no est associado a outro if. Por exemplo
Como observado, o ltimo else no est associado a if(j) porque no pertence ao mesmo bloco. Em vez disso, ltimo else est associado ao if(i). O else interno est associado ao if(k), que o if mais prximo. O padro ANSI especifica que pelo menos 15 nveis de aninhamento devem ser suportados. Na prtica, a maioria dos compiladores permite substancialmente mais.
if(i){ if(j) comando 1; if(k) comando 2; //este if... else comando 3; //..est associado a este else } else comando 4; // associado a if(i) #include <conio.h> #include <stdio.h>
void main() { int valor; printf("Entre com um valor inteiro: "); scanf("%d", &valor);
if(valor > 0) printf("\nO valor que voce digitou e positivo"); else printf("\nO valor que voce digitou e negativo");
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 15 if else if
Uma construo comum em programao a forma ifelseif, algumas vezes chamada de escada if-else-if devido a sua aparncia. A sua forma geral
if (expresso1) comando 1; else if (expresso2) comando 2; else if (expresso3) comando 3; . . . else comando N;
As condies so avaliadas de cima para baixo. Assim que uma condio verdadeira encontrada, o comando associado a ela executado e o resto da escada contornado. Se nenhuma das condies for verdadeira, ento o ltimo else executado. Isto , se todos os outros testes condicionais falham, o ltimo comando else efetuado. Se o ltimo else no est presente, nenhuma ao ocorre se todas as condies so falsas.
?
C contm um operador muito poderoso e conveniente que substitui certas sentenas da forma if-else. O ? um operador ternrio (que requer trs operandos) que tem a forma geral
Exp1 ? Exp2 : Exp3;
Onde Exp1, Exp2 e Exp3 so expresses. Note o uso e o posicionamento dos dois pontos. O operador ? funciona desta forma: Exp1 avaliada. Se ela for verdadeira, ento Exp2 avaliada e se torna o valor da expresso. Se Exp1 falso, ento Exp3 avaliada e se torna o valor da expresso. Por exemplo,
X = 10; Y = X > 9 ? 100 : 200;
a Y atribudo um valor 100. Se X fosse menor que 9, Y teria recebido o valor 200. O mesmo cdigo, usando o comando if-else
X = 10; if ( X > 9) Y = 100; else Y = 200;
Exemplo:
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 16
Este programa anlogo ao da seo if-else, incorporando agora os conceitos do operador ?. Observe os dois e faa as comparaes.
Switch
C tem um comando interno de seleo mltipla, switch, que testa sucessivamente o valor de uma expresso contra uma lista de constantes inteiras ou de caractere. Quando o valor coincide, os comandos associados quela constante so executados. A forma geral do comando switch
switch (expresso) { case constante1: comandos break; case constante2: comandos break; . . . default: seqncia de comandos }
Abaixo vemos o fluxograma correspondente a esta estrutura de deciso.
#include <conio.h> #include <stdio.h>
void main() { int valor; printf("Entre com um valor inteiro: "); scanf("%d", &valor);
valor > 0 ? printf("\nO valor que voce digitou e positivo") : printf("\nO valor que voce digitou e negativo");
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 17
O valor da expresso testado, na ordem, contra os valores das constantes especificadas nos comandos case. Quando uma coincidncia for encontrada, a seqncia de comandos associada quele case ser executada at que o comando break ou o fim do comando swtich seja alcanado. O comando default executado se nenhuma coincidncia for detectada. O default opcional e, se no estiver presente, nenhuma ao ser realizada se todos os testes falharem.
O comando switch freqentemente utilizado na construo de menus, veja o exemplo abaixo:
Expresso Conjunto 1 Conjunto 2 ... Conjunto N Conjunto D Rtulo 1 Rtulo 2 Rtulo N Rtulo D Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 18
Comandos de Iterao
Os comandos de iterao, conhecidos tambm como laos, permitem que um conjunto de instrues seja executado at que ocorra uma certa condio. Essa condio pode ser predefinida (como ocorre no lao for) ou com o final em aberto (como ocorre nos laos while e do-while).
Lao for
O lao for uma estrutura de repetio, chamada de estrutura de repetio com contador. Ele executa um bloco de instrues em uma quantidade de vezes predefinida. A forma geral do comando for
for(inicializao; condio; incremento) { bloco }
onde inicializao uma expresso de inicializao do contador, geralmente um comando de atribuio que usado para colocar um valor inicial na varivel de controle do lao. A condio uma expresso relacional que determina quando o lao termina. O incremento define como a varivel de controle do lao varia cada vez que o lao repetido. Estas trs sees devem ser separadas por ponto-e-vrgula (;). O bloco executado enquanto a condio for verdadeira, ou seja, uma vez que a condio se torne falsa, o lao encerrado.
void funcao1(); // funo para converso de temperatura void funcao2(); // funo para calculo de fatorial
void main() { int opcao; printf("1: Conversao de Temperatura"); printf("\n2: Calcular Fatorial"); printf("\nEscolha uma opcao e tecle ENTER: "); scanf("%d",&opcao); // entrada de variavel
switch(opcao) // analisa a opcao do usuario { case 1: // caso seja 1... funcao1(); // ... executa funo 1 break;
case 2: // caso seja 2... funcao2(); // ... executa funo 2 break;
default: // caso no seja nenhuma... exit(0); // ...o programa encerrado break; } } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 19 Por exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 100:
Podem existir mais de uma expresso de inicializao e de incremento na estrutura for. Estas expresses devem ser separadas por vrgulas (,). Mas no pode haver mais de uma expresso de condio. Por exemplo:
for(i = 0, j = 10; i < 10; i++, j--) { ... }
Lao while
Outra estrutura de repetio disponvel no C o lao while. Sua forma geral :
While(condio){ bloco }
A condio pode ser qualquer expresso. Este lao se repete quando a condio for verdadeira, ou seja, qualquer valor diferente de zero. Quando a condio for falsa, o programa pula este lao e o bloco no executado.
O fluxograma desta estrutura mostrado abaixo:
Exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 100:
Condio? bloco V F #include <conio.h> #include <stdio.h>
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 20
Lao do-while
Ao contrrio dos laos for e while, que testam a condio do lao no comeo, o lao do-while sempre ser executado ao menos uma vez. Sua forma geral :
do{ bloco }while(condio);
A condio qualquer expresso relacional e/ou lgica. O bloco ser executado uma vez, se a condio for falsa, ou seja, igual a zero, o programa encerra o lao. Porm, se a condio for verdadeira, ou seja, qualquer nmero diferente de zero, o bloco executado novamente.
O fluxograma desta estrutura mostrado abaixo:
bloco Condio? V F #include <conio.h> #include <stdio.h>
void main() { int i = 1; while(i<=100) { printf("%d ", i); i++; }
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 21 Exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 100:
O comando do-while uma boa escolha na construo de menus, porque sempre se deseja que as opes do menu execute ao menos uma vez. Depois que as opes forem mostradas, o programa ser executado at que uma opo vlida seja selecionada.
Abaixo se encontra o exemplo utilizado na seo do switch, agora utilizando os conceitos de do-while:
void funcao1(); //funo para converso de temperatura void funcao2(); //funo para calculo de fatorial
void main() { int opcao; do{
printf("1: Conversao de Temperatura"); printf("\n2: Calcular Fatorial"); printf("\n3: sair"); printf("\nEscolha uma opcao e tecle ENTER: "); scanf("%d",&opcao); // entrada de variavel
}while(opcao!=1 && opcao!=2); /*este bloco ser executado sempre que opcao for diferente de 1 e de 2*/
switch(opcao) // analisa a opcao do usuario { case 1: // caso seja 1... funcao1(); // ... executa funo 1 break;
case 2: // caso seja 2... funcao2(); // ... executa funo 2 break;
case 3: // caso seja 3... exit(0); // ...o programa encerrado break; } }
#include <conio.h> #include <stdio.h>
void main() { int i = 1; do{ printf("%d ", i); i++; }while(i<=100);
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 22 Comandos de Desvios
A linguagem C possui quatro comandos que realizam um desvio incondicional: return, goto, break e continue.
Comando return
O comando return utilizado para retornar de uma funo. Ele um comando de desvio, pois faz com que a execuo retorne ao ponto em que a funo foi chamada. A sua forma geral
return expresso;
A expresso opcional, se houver alguma expresso contendo algum valor associado ao return, este retornado da funo para onde ela foi chamada. Se nenhum valor de retorno for especificado, assume-se que apenas lixo retornado. Voc pode usar quantos comandos return quiser dentro de uma funo. Entretanto, a funo deixar de executar to logo ela encontre o primeiro return. Uma funo do tipo void no pode ter um comando return.
Comando goto
No C, devido ao seu rico conjunto de estruturas de controle, h pouca necessidade da utilizao do goto. A grande preocupao da maioria dos programadores sobre o goto sua tendncia de tornar os programas ilegveis, mas se este for utilizado prudentemente, pode ser uma vantagem em certas situaes na programao. O comando goto requer um rtulo para sua operao, o qual rtulo um identificador vlido em C seguido de dois pontos. O rtulo deve estar na mesma funo do goto que o utiliza, seno voc no poder efetuar o desvio. A forma geral do goto
goto rtulo; ... rtulo: ...
Por exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 100:
#include <conio.h> #include <stdio.h>
void main() { int i = 1;
repetir: // rtulo printf("%d ",i); i++; // incremento if(i <= 100) goto repetir; // chamada do rtulo
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 23 Comando break
O comando break pode ser usado de duas formas. Ele pode ser usado em conjunto com switch...case como visto anteriormente, ou pode tambm ser usado em conjunto com um lao de repetio (for, do-while, while) que fora a interrupo deste lao independentemente da condio de controle.
Por exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 10:
Porm, o comando break fora a sada apenas do lao mais interno de onde ele se encontra. Por exemplo, o programa abaixo imprime, na tela, os nmeros de 1 a 10, 10 vezes.
#include <conio.h> #include <stdio.h>
void main() { for(int i = 1; i <= 100; i++) { printf("%d ",i); if(i == 10) break; // sai do lao quando i = 10 } _getch(); } #include <conio.h> #include <stdio.h>
void main() { for(int i = 1; i <= 10; i++) { for(int j = 1; j <= 100; j++) { printf("%d ",j); if(j == 10) break; // sai do lao mais interno quando i=10 } printf("\n"); } _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 24 Funo exit()
A funo exit() provoca uma terminao imediata do programa inteiro, forando um retorno ao sistema operacional, ela age como se estivesse finalizando o programa. A forma geral
void exit(int cdigo_de_sada);
O valor cdigo_de_sada um inteiro que ser passado para o Sistema Operacional. O zero geralmente usado como um cdigo de retorno que indica uma terminao normal do programa, enquanto que outros argumentos so usados para indicar algum tipo de erro.
O exemplo abaixo idntico ao utilizado na seo do-while:
void funcao1(); //funo para converso de temperatura void funcao2(); //funo para calculo de fatorial
void main() { int opcao; do{
printf("1: Conversao de Temperatura"); printf("\n2: Calcular Fatorial"); printf("\n3: sair"); printf("\nEscolha uma opcao e tecle ENTER: "); scanf("%d",&opcao); // entrada de variavel
}while(opcao!=1 && opcao!=2); /*este bloco ser executado sempre que opcao for diferente de 1 e de 2*/
switch(opcao) // analisa a opcao do usuario { case 1: // caso seja 1... funcao1(); // ... executa funo 1 break;
case 2: // caso seja 2... funcao2(); // ... executa funo 2 break;
case 3: // caso seja 3... exit(0); // ...o programa encerrado break; } } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 25 Neste exemplo, se o usurio escolher sair do programa, caso 3, o comando exit(0) encerrar o programa. Note que o argumento utilizado o inteiro zero, que indica sada normal do programa. As funes funcao1() e funcao2() devem ser definidas pelo programador.
Comando continue
O comando continue funciona de uma forma um tanto quanto similar ao comando break. S que, ao invs de forar a terminao do lao, continue fora que ocorra a prxima iterao deste, pulando qualquer cdigo intermedirio. Para o lao for, este comando faz com que o teste condicional e a poro de incremento do lao sejam executados. Para os laos while e do-while, o controle de programa passa para o teste condicional. Veja o exemplo a seguir, o programa imprime, na tela, os nmeros mpares de 1 a 100:
#include <conio.h> #include <stdio.h>
void main() { int resultado; for(int i = 1; i <= 100; i++) { resultado = i%2; // resto da diviso i/2 if(resultado == 0) // se o resto for 0 continue; // continue fora a proxima iterao do lao
printf("%d ",i); } _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 26 Captulo 4 Matrizes e Strings
Uma matriz um conjunto de variveis de um mesmo tipo. Em C, todas as matrizes consistem em posies contguas na memria. O endereo mais baixo corresponde ao primeiro elemento e o mais alto, ao ltimo elemento. Matrizes podem ter de uma a vrias dimenses. A matriz mais comum em C a de string, que simplesmente uma matriz de caracteres terminada por um nulo.
Matrizes Unidimensionais
A forma geral para se declarar uma matriz unidimensional
tipo nome[tamanho];
onde tamanho deve ser um inteiro que define quantos elementos a matriz ir armazenar e tipo o tipo de cada elemento da matriz. Matrizes devem ser explicitamente declaradas, juntamente com seu tamanho, para que o compilador possa alocar espao para elas na memria. Por exemplo, se voc quiser declarar um vetor (matriz unidimensional) do tipo float, chamada notas, e com 50 elementos, este vetor deve ser declarado da seguinte forma:
float notas[50];
Para vetores, cada elemento possui um ndice, sendo que o primeiro elemento possui ndice zero e o ltimo possui em seu ndice o tamanho do menos um (tamanho-1). Por exemplo, considere o vetor
int x[10];
aqui voc est declarando um vetor com dez elementos, x[0] at x[9].
No seguinte cdigo, o programa faz o carregamento de um vetor com os nmeros de 0 a 99:
Para um vetor, o tamanho total em bytes calculado da seguinte forma:
Total em bytes = sizeof(tipo) * tamanho do vetor
#include <conio.h> #include <stdio.h>
void main() { int x[100]; for(int i = 0; i < 100; i++) x[i] = i; // x[0]=0... x[1]=1... x[2]=2... etc. } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 27 A linguagem C no possui verificao de limites em matrizes. Voc poderia ultrapassar o fim de uma matriz e escrever nos dados de alguma outra varivel. Como programador, voc deve prover verificao dos limites onde for necessrio.
A tabela abaixo exemplifica como um vetor apareceria na memria comeando na posio 100 e fosse declarado na seguinte forma:
Considere o seguinte fragmento de programa que passa o endereo de x para funo():
void main() { int x[15]; funcao(x); . . . }
Se uma funo recebe um vetor, voc pode declarar o parmetro formal em uma entre trs formas: como um ponteiro, como uma matriz dimensionada ou como uma matriz adimensional. Exemplos de como funcao pode receber o vetor x:
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 28 Todos os trs mtodos possuem resultados idnticos, pois cada um diz ao compilador q um ponteiro inteiro vai ser recebido. A primeira declarao usa, de fato, um ponteiro. A segunda emprega a declarao de matriz padro. A ltima declarao simplesmente especifica que uma matriz do tipo int, de algum tamanho, ser recebida.
Strings
Uma string definida como um vetor de caracteres que terminada por um nulo. Um nulo especificado como \0 e geralmente zero. Por essa razo, voc precisa declarar matrizes de caracteres como sendo um caractere mais longo que a maior string que elas devem guardar. Por exemplo, para declarar um vetor string que guarda uma string de 10 caracteres, deve-se declarar desta forma
char string[11];
Com isso reserva espao para o nulo no final da string. Embora a linguagem C no tenha o tipo de dado string, ela permite constantes string. Uma constante string uma lista de caracteres entre aspas. Por exemplo,
ola mundo
Voc no precisa adicionar o nulo no final das constantes string manualmente, o compilador C faz isso automaticamente.
C apresenta uma gama de funes de manipulao de strings. Abaixo lista as mais comuns com seus respectivos efeitos, considere s1 e s2 duas strings, e ch um caractere.
Funo Efeito strcpy(s1,s2) Copia s2 em s1 strcat(s1,s2) Concatena s2 ao final de s1 strlen(s1,s2) Retorna o tamanho de s1 strcmp(s1,s2) Retorna 0 se s1 e s2 so iguais; menor que 0 se s1 < s2; maior que 0 se s1 > s2 strchr(s1,ch) Retorna um ponteiro para a primeira ocorrncia de ch em s1 strstr(s1,s2) Retorna um ponteiro para a primeira ocorrncia de s2 em s1
Essas funes utilizam o cabealho STRING.H.
O programa a seguir ilustra o uso dessas funes:
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 29
Deve-se lembrar que strcmp() retorna zero em caso das strings serem iguais, e zero falso por isso deve-se usar o operador ! para reverter a condio, assim se tornar verdadeiro e o bloco dentro do if ser executado. Se executarmos o programa teremos o seguinte resultado:
void main() { char string1[80]; // declarao da string1 char string2[80]; // declarao da string2
printf("Entre com a primeira string: "); gets(string1); // recebe a string1
printf("Entre com a segunda string: "); gets(string2); // recebe a string2
printf("\nO tamanho da primeira string e: %d", strlen(string1)); // imprime o tamanho da string1
printf("\nO tamanho da segunda string e: %d", strlen(string2)); // imprime o tamanho da string2
if(!strcmp(string1,string2)) // faz a comparao printf("\nAs strings sao idnticas"); else printf("\nAs strings sao diferentes");
printf("\n%s",strcat(string1,string2)); // concatenao printf("\n%s",string1); // imprime a string1 concatenada
strcpy(string1,"teste"); // copia teste para string1 printf("\n%s",string1);
if(strchr(string2,'a')) // procura pela letra a na string2 printf("\nA segunda string contem a letra a");
if(strstr("ola mundo","ola")) printf("\nA expressao \"ola mundo\" contem a palavra \"ola\"");
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 30 Matrizes Bidimensionais
A declarao de uma matriz bidimensional semelhante ao de unidimensional. Por exemplo, se voc quiser declarar uma matriz bidimensional chamada x, do tipo inteiro e de tamanho 5,10, voc escreveria
int x[5][10];
Similarmente, para acessar o elemento 0,1 voc usaria
X[0][1];
O exemplo abaixo carrega uma matriz bidimensional com os nmeros de 1 a 9 e o imprime em forma matricial:
Construindo uma tabela dessa matriz com seus valores, temos a seguinte disposio:
Coluna Linha 0 1 2 0 1 2 3 1 4 5 6 2 7 8 9
Neste exemplo, o elemento matriz[0][0] possui o valor 1, o elemento matriz[0][1] possui o valor 2, e assim por diante. O valor do ltimo elemento matriz[2][2] ser 9.
for(int i=0; i<3; i++) { for(int j=0; j<3; j++) printf("%d",matriz[i][j]); printf("\n"); } _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 31 Matrizes bidimensionais so armazenadas em uma matriz linha-coluna, onde o primeiro ndice indica a linha e o segundo, a coluna. No caso da matriz bidimensional, a seguinte frmula fornece o nmero de bytes de memria necessrios para armazen-la:
Total em bytes = tamanho do 1 ndice * tamanho do 2 ndice * sizeof(tipo)
Portando, a matriz exemplificada acima, que possui as dimenses 3, 3 teria
3 * 3 * 2
ou 18 bytes alocados, j que cada inteiro ocupa 2 bytes.
Quando passamos uma matriz bidimensional passada como um argumento para uma funo, apenas um ponteiro para o primeiro elemento realmente passado. No entanto, uma funo que recebe uma matriz bidimensional como um parmetro formal deve definir ao menos o comprimento da segunda dimenso. Voc pode especificar a primeira dimenso, se quiser, mas no necessrio.
Por exemplo, uma funo que recebe uma matriz bidimensional de inteiros com dimenses 10, 10 declarada dessa forma:
funcao(int matriz[][10]) { . . . }
Matrizes de Strings
muito comum no C a utilizao das matrizes de strings. Para criar uma, use uma matriz bidimensional de caracteres. O tamanho do ndice esquerdo indica a quantidade de strings que deseja e o tamanho do ndice do lado direito indica o comprimento mximo de cada string. Por exemplo, se voc quiser criar uma matriz de strings com a capacidade para 50 strings, sendo que, cada uma suporte no mximo 80 caracteres, voc escrever
char nome[50][80];
Para acessar uma string individualmente, voc simplesmente especifica apenas o ndice esquerdo. Por exemplo, se voc possuir uma lista com os nomes de cinqenta alunos, e quiser imprimir o nome do 4 aluno, voc dever escrever
printf(%s, nome[3]);
Com isso, toda string da 4 linha ser impressa na tela.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 32 Inicializao de Matrizes
C permite a inicializao de matrizes no momento da declarao. A forma geral de uma inicializao de matriz semelhante de outras variveis, como mostrado aqui:
A lista_de_valores uma lista separada por vrgulas de constantes cujo tipo compatvel com especificador_de_tipo. A primeira constante colocada na primeira posio da matriz, a segunda, na segunda posio e assim por diante.
No exemplo abaixo uma matriz inteira de dez elementos inicializada com os nmeros de 1 a 10:
int i[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Isso significa que i[0] ter valor 1 e i[9] ter valor 10;
Matrizes de caracteres que contm strings permitem uma inicializao abreviada que toma a forma:
char nome_da_matriz[tamanho] = string;
No cdigo abaixo, a matriz de string chamada string inicializada com a frase ola mundo.
char string[] = ola mundo
Note que no foi definido o tamanho da matriz, quando se realiza uma inicializao de matriz isso pode ser feito, pois o compilador conta os nmeros de elementos e aloca o espao automaticamente. Este cdigo o mesmo que
char string[10] = ola mundo
No esquea de contar um espao extra para o nulo (\0).
Inicializao de matrizes multidimensionais equivalente ao de matrizes unidimensionais. Por exemplo, a matriz abaixo inicializada com os nmeros de 1 a 9:
int i[3][3] = {1,2,3,4,5,6,7,8,9};
Que tambm pode ser escrita desta forma:
int i[][3] = {1,2,3,4,5,6,7,8,9};
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 33 Captulo 5 Ponteiros
Um ponteiro uma varivel que contm um endereo de memria. Esse endereo normalmente a posio de outra varivel na memria. Se uma varivel contm o endereo de outra, ento a primeira varivel dita para apontar para a segunda.
Variveis Ponteiros
Se uma varivel ir conter um ponteiro, ela deve ser declarada da seguinte forma:
tipo *nome;
onde tipo qualquer tipo vlido em C e nome o nome da varivel ponteiro.
Operadores de Ponteiros
Existem dois operadores para ponteiros: * e &. O & um operador unrio (operador unrio aquele quer requer apenas um operando) que devolve o endereo na memria de seu operando. Por exemplo,
m = &var;
coloca o endereo da memria da varivel var em m, da dizemos que m est apontando para var. O endereo no tem relao alguma com o valor de var. O operador & pode ser imaginado como retornando o endereo de. O comando de atribuio anterior significa m recebe o endereo de var.
O segundo operador de ponteiro, *, o complemento de &. um operador unrio que devolve o valor da varivel localizada no endereo que o segue. Neste caso, se m contm o endereo da varivel var,
q = *m;
coloca o valor de var em q.
Vamos supor que var usa o endereo 100 na posio de memria e que esta varivel tenha o valor 5. Portanto com a primeira atribuio m ter o valor 100, e com a segunda atribuio q ter o valor 5, porque 5 estava armazenado na posio 100, que o endereo que estava armazenado em m. O operador * pode ser imaginado como no endereo. Nesse caso, o comando anterior significa q recebe o valor que est no endereo m.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 34 Atribuio de Ponteiros
Do mesmo modo que uma varivel comum o contedo de um ponteiro pode ser passado para outro ponteiro do mesmo tipo. As variveis ponteiro devem sempre apontar para os tipos de dados corretos. Uma varivel ponteiro declarada como apontador de dados inteiros deve sempre apontar para dados deste tipo.
Observar que em C possvel atribuir qualquer endereo a uma varivel ponteiro. Deste modo possvel atribuir o endereo de uma varivel do tipo float a um ponteiro inteiro. No entanto, o programa no ir funcionar da maneira correta.
Veja o exemplo abaixo, o endereo do terceiro elemento do vetor v carregado em p1 e o endereo da varivel i carregado em p2. Alm disso, no final o endereo apontado por p1 carregado em p2. Os comandos printf() imprimem os valores e os endereos apontados pelos ponteiros respectivos. %p imprime o valor em hexadecimal assim como usado pelo computador.
Com a execuo deste programa, temos o seguinte resultado na tela:
#include <conio.h> #include <stdio.h>
void main(void)
{
int vetor[] = { 10, 20, 30, 40, 50 }; int *p1, *p2; int i = 100;
p1 = &vetor[2]; printf("Endereco de p1 e %p e seu valor e %d\n", p1, *p1);
p2 = &i; printf("\nEndereco de p2 e %p e seu valor e %d\n", p2, *p2);
p2 = p1; printf("\nEndereco de p2 e %p e seu valor e %d\n", p2, *p2);
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 35 Incrementando e Decrementando Ponteiros
O exemplo abaixo mostra que operaes de incremento e decremento podem ser aplicadas em operandos. O primeiro printf imprime 30 o segundo 40 e o terceiro 50.
Pode parecer estranho que um endereo que aponte para um nmero inteiro que armazenado em dois bytes seja incrementado por um e passe para apontar para o prximo nmero inteiro. A resposta para isto que sempre que um ponteiro incrementado (ou decrementado) ele passa a apontar para a posio do elemento seguinte (ou anterior). Do mesmo modo somar trs a um ponteiro faz com que ele passe apontar para o terceiro elemento aps o atual. Portanto, um incremento em um ponteiro que aponta para um valor que armazenado em n bytes faz que n seja somado ao endereo. possvel usar o seguinte comando:
*(p+1)=10;
Este comando armazena o valor 10 na posio de memria seguinte quela apontada por p. possvel somarem-se e subtrarem-se inteiros de ponteiros. A operao abaixo faz com que o ponteiro p passe a apontar para o terceiro elemento aps o atual.
p = p + 3;
A diferena entre ponteiros fornece quantos elementos do tipo do ponteiro existem entre os dois ponteiros. No exemplo abaixo impresso o valor 3.
#include <conio.h> #include <stdio.h>
void main(void) { int vetor[] = { 10, 20, 30, 40, 50 }; int *p1;
p1 = &vetor[2];/* endereco do terceiro elemento */ p2 = &vetor[0];/* endereco do primeiro elemento */ printf("Diferenca entre ponteiros %d\n", p1-p2); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 36 No possvel multiplicar ou dividir ponteiros.
Comparao de Ponteiros
possvel comparar ponteiros em uma expresso relacional. S possvel comparar ponteiros de mesmo tipo. O trecho de programa abaixo ilustra um exemplo deste tipo de operaes.
if (c == v) printf("As variveis estao na mesma posicao.\n"); else printf("As variaveis nao estao na mesma posicao.\n");
Sendo c e v dois ponteiros declarados e inicializados anteriormente.
Ponteiros e Vetores
Ponteiros e Vetores esto fortemente relacionados na linguagem C. O nome de um vetor um ponteiro que aponta para a primeira posio do vetor e todas as operaes j mencionadas para ponteiros podem ser executadas com um nome de vetor. Por exemplo, a declarao
int v[100];
declara um vetor de inteiros de 100 posies, e a partir dela temos que v um ponteiro equivalente ao da declarao abaixo
int *v;
Por esta razo as seguintes declaraes so idnticas e podem ser intercambiadas independentemente do modo como v foi declarado:
v[i] = *(v+i); &v[i] = v+i;
O exemplo ilustrado abaixo mostra as duas notaes sendo usadas para imprimir o mesmo vetor.
printf("\n"); for (i=0; i<9; i++) printf("%.1f ", *(v+i));
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 37 Existe uma diferena fundamental entre declarar um conjunto de dados como um vetor ou atravs de um ponteiro. Na declarao de vetor, o compilador automaticamente reserva um bloco de memria para que o vetor seja armazenado. Quando apenas um ponteiro declarado, a nica coisa que o compilador faz alocar um ponteiro para apontar para a memria, sem que espao seja reservado.
O nome de um vetor chamado de ponteiro constante e, portanto, no pode ter o seu valor alterado. Assim, os comandos abaixo no so vlidos:
Ponteiros e Strings
Na linguagem C, este tipo de inicializao de ponteiro perfeitamente vlido:
char *str = Esta e uma string
Como voc pode observar, o ponteiro str no um vetor. Todo compilador C cria o que chamada de tabela de string, que usada internamente pelo compilador para armazenar as constranges strings usadas pelo programa. Assim, o comando de declarao anterior coloca o endereo de Esta e uma string, armazenado na tabela de strings no ponteiro str. Veja o exemplo abaixo, este programa imprime na tela o contedo da string e de trs para frente:
#include <conio.h> #include <stdio.h>
void main() { int list[5], i;
/* O ponteiro list nao pode ser modificado recebendo o endereco de i */ list = &i
/* O ponteiro list nao pode ser incrementado */ list++;
for(int i = strlen(str)-1; i>=0; i--) printf("%c", str[i]);
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 38 Alocao Dinmica de Memria
A alocao dinmica o meio pelo qual um programa pode obter memria enquanto est em execuo. Como voc sabe, as variveis globais e locais devem ser declaradas de executar um programa, elas no podem ser acrescentadas durante o tempo de execuo, portanto elas so constantes. Porm, haver momentos em que um programa precisa usar quantidades de armazenamento variveis, no constantes
As funes bsicas de alocao de memria so malloc(), calloc() e free(). Estas funes so encontradas na biblioteca stdlib.h. As funes malloc() e calloc() alocam memria (neste volume utilizaremos malloc()) e free() libera. Toda vez que voc alocar espao na memria dever liber-la.
A funo malloc() tem o seguinte prottipo:
void *malloc(size_t numero_de_bytes);
Aqui, numero_de_bytes o nmero de bytes de memria que voc quer alocar. A funo malloc() devolve um ponteiro do tipo void, o que significa que voc pode atribu-lo a qualquer tipo de ponteiro, utilizando um cast.
O fragmento de cdigo seguinte aloca 1000 bytes na memria:
Como cada elemento do tipo char corresponde a 1 byte, ento teremos 1000 bytes alocados. Se quisermos 150 elementos do tipo int:
int *ptr; ptr = (int *) malloc(150*sizeof(int));
Mas infelizmente a memria disponvel para o desenvolvimento de nosso software no infinita, portanto sempre que for feita a alocao dinmica de memria devemos testar o valor devolvido por malloc(). Se houver um erro de alocao ele devolver zero (0). Exemplo:
int *ptr; ptr = (int *) malloc(150*sizeof(int)); if(!ptr) { printf(Erro! Memoria Insuficiente); _getch(); exit(1); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 39 Como j foi dito, a funo free() libera a memria alocada. Ela possui o seguinte prottipo:
void free(void *p);
muito importante que voc nunca usar free() com um argumento invlido; isso destruiria a lista de memria livre.
Veja o programa abaixo utilizando os conceitos de alocao dinmica de memria:
Note que foi utilizado um do-while para o recebimento da varivel tam, isso porque esta varivel no pode assumir um valor menor ou igual a zero, j que no se pode realizar uma alocao de memria negativa ou igual a zero.
do{ printf("Entre com a quantidade de elementos que deseja para seu vetor: "); scanf("%d", &tam); }while(tam<=0); /* tam no pode ser menor ou igual a 0 */
for(int i = 0; i < tam; i++) { printf("Entre com o %d elemento: ", i+1); scanf("%f", ptr+i); /* recebe o elemento do usuario */ }
system("cls"); printf("Seu vetor e: "); for(int i = 0; i < tam; i++) printf("%.2f ", *(ptr+i)); /* imprime o elemento */
free(ptr); /* libera memoria */ _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 40 Ponteiros e Matrizes
Nesta seo abordaremos a relao entre ponteiros e matrizes bidimensionais, j que matrizes unidimensionais (vetores) j foram tratadas anteriormente. No h muita diferena destes, apenas na forma como o ponteiro tratado para acessar um local especfico da memria.
Sabemos que um ponteiro aponta para uma rea de memria que endereada de maneira linear. Deste modo, necessrio mapear o endereo de cada elemento na matriz, que dado por linha coluna, em um endereo linear.
Considere uma matriz chamada matriz de tamanho LIN, COL que poderia ser declarada e ter um de seus elementos lidos da seguinte maneira:
Caso o programa utilizasse ponteiros ao invs de notao de matrizes o trecho de programa ficaria da seguinte maneira, observe que o endereo de cada elemento da matriz teve de ser calculado explicitamente:
#include <conio.h> #include <stdio.h> #define LIN 3 #define COL 4
for(i=0; i<LIN; i++){ for (j=0; j<COL; j++){ printf("Elemento %d %d = ", i, j); scanf("%d", matriz+(i*COL+j)); } } } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 41 Vetores de Ponteiros
Como ponteiros tambm so variveis possvel ento criar vetores de ponteiros e utiliz-los. O programa abaixo mostra um programa onde utilizado um vetor de ponteiros para linhas de caracteres.
Observe esta declarao:
char *linha[LINHAS];
Ela define um vetor, cujos elementos so ponteiros do tipo char que apontam para posies de memria. At este momento temos apenas posies reservadas para armazenar os ponteiros. O espao na memria s efetivamente alocado aps a chamada da funo malloc(). Neste programa fizemos a alocao linha por linha, onde cada linha possui capacidade para 60 elementos do tipo char, se comportando portando como uma matriz de strings (visto no captulo 4), s que utilizando o conceito de ponteiros.
for(int i = 0; i < LINHAS; i++) { /* aloca memoria, linha por linha */ if(!(linha[i] = (char *)malloc(COLUNAS*sizeof(int)))) { printf("Nao consegui alocar o vetor %d.\n", i); exit(i); } }
for(int i = 0; i < LINHAS; i++) { printf("Entre com a linha %d.\n", i); gets(linha[i]); /* recebe as strings */ }
for(int i = 0; i < LINHAS; i++) /* imprime as strings */ printf("Linha %d: %s\n", i, linha[i]);
for(int i = 0; i < LINHAS; i++) free(linha[i]); /* libera a memoria, linha por linha */
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 42 Ponteiros para Ponteiros
No exemplo da seo anterior, observamos que o nmero de linhas da matriz fixo, e, portanto, h uma mistura de notao de ponteiros com matrizes. Vamos considerar um exemplo onde tanto o nmero de linhas como o de colunas desconhecido. Neste exemplo iremos criar um vetor de ponteiros que ir armazenar o endereo inicial de cada linha. Portanto, para obter um elemento da matriz primeiro devemos descobrir onde est a linha no vetor que armazena os endereos das linhas, em seguida procuramos na linha o elemento.
O programa abaixo pede ao usurio que digite o nmero de linhas e colunas da matriz. Em seguida ler todos os elementos da matriz e a imprimir na tela. Observe que agora foi criado um ponteiro para ponteiro chamado de **matriz.
O programa primeiro pergunta o nmero de linhas da matriz para poder alocar espao para armazenar os ponteiros para cada uma das linhas. Em seguida alocado espao para armazenar cada uma das linhas.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 43
void main () { int **matriz; /* matriz de ponteiros */ int lin, col; /* nmero de linhas e colunas */
do { printf("Entre com o numero de linhas: "); scanf("%d", &lin); /* recebe o numero de linhas */ } while (lin<=0);
/* aloca as linhas da matriz */ matriz = (int **) malloc (lin * sizeof(int *)); if (!matriz) { printf("Erro! Memoria Insuficiente!"); _getch(); exit(1); }
do{ printf("Entre com o numero de colunas: "); scanf("%d", &col); /* recebe o numero de colunas */ }while (col<=0);
for (int i = 0; i < lin; i++) { /* aloca as colunas de cada linha da matriz */ *(matriz+i) = (int *) malloc(col * sizeof (int)); if(! *(matriz+i) ){ printf("Erro! Memoria Insuficiente!"); exit(1); } }
printf("Entre com os elementos da matriz\n"); for(int i = 0; i < lin; i++) { for(int j = 0; j < col; j++) { printf("\nElemento %d %d: ", i, j); scanf("%d", *(matriz +i) +j); } /* recebe os elementos */ }
system("cls"); printf("Os elementos da sua matriz sao\n\n");
for(int i = 0; i < lin; i++) { for(int j = 0; j < col; j++) printf("%d ", *(*(matriz +i) +j)); printf("\n"); /* imprime os elementos na tela */ }
free(matriz); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 44 Captulo 6 Funes
Funes so os blocos de construo de C, e o local onde toda atividade ocorre. Elas so umas das caractersticas mais importantes de C.
A forma geral de uma funo
especificador_de_tipo nome_da_funes(lista_de_parmetros) { corpo da funo }
especificador_de_tipo se refere ao tipo de valor que a funo retorna. Este pode ser qualquer tipo vlido em C.
lista_de_parmetros uma lista de variveis separadas por vrgulas e seus tipos associados, se caso a sua funo no precisar de parmetros, a lista ser vazia. No entanto, os parnteses ainda so necessrios. Exemplos:
Tambm pode ocorrer, como j foi discutido no captulo 2, a necessidade da declarao de variveis internamente, esse tipo de varivel chamada de varivel local, essas variveis vem a existir na entrada da funo e so destrudas ao sair, ou seja, no podem ser acessadas aps o fim da funo.
Em geral os argumentos podem ser passados de duas maneiras, chamada por valor ou chamada por referncia. No primeiro caso, copiado o valor de um argumento para o parmetro de uma funo, assim alteraes feitas nos parmetros formais no possuem efeito nas variveis utilizadas. No segundo caso, chamada por referncia, repassada para a funo o endereo da varivel como argumento, assim as operaes ocorrem diretamente no argumento, ou varivel global.
void funcao1(char y, int h) { bloco }
float funcao2(float x, double *z) { bloco } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 45 Funes Recursivas
Um tipo especial de funo a funo recursiva, ou recurso, que ocorre quando um comando no corpo da funo a chama. Um exemplo clssico de funo recursiva o calculo de fatorial. Veja o exemplo abaixo:
O mesmo exemplo pode ser feito de forma no-recursiva, veja o trecho do programa:
int fatorial(int x) { int resultado = 1;
for(int t = 1; t <= x; t++) resultado = resultado*(t);
return resultado; }
#include <stdio.h> #include <conio.h>
int fatorial(int x);
void main () { int num;
do{ printf("Entre com um numero natural para o calculo do fatorial: "); scanf("%d", &num); }while(num < 0);
printf("\n\nO fatorial de %d e %d", num, fatorial(num)); _getch(); }
int fatorial(int x) { int resultado; if(x == 1) return 1; else if(x == 0) return 1; else return resultado = x*fatorial(x-1); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 46 Funes que retornam ponteiros
As funes que devolvem ponteiros so manipuladas da mesma forma, embora precisem de ateno especial. Ponteiros para variveis no so variveis, eles so o endereo na memria de um certo tipo de dado. Para se retornar um ponteiro, a funo deve ter o tipo de retorno igual a um ponteiro. Veja um exemplo de uma funo que devolve um ponteiro para a primeira ocorrncia do caractere c na string s
Lembrando que quando se incrementa um ponteiro, ele aponta para o prximo elemento da memria.
printf("Entre com um caractere: "); scanf("%c", &ch);
string = match(ch, s); printf(string);
_getch(); }
char *match(char c, char *s) { while(c != *s) s++; return s; } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 47 Captulo 7 Estruturas
Em C, uma estrutura uma coleo de variveis referenciadas por um nome, fornecendo uma maneira conveniente de se ter informaes relacionadas agrupadas. Uma definio de estrutura forma um modelo que pode ser usado para criar variveis de estruturas. As variveis que compreendem a estrutura so chamadas elementos da estrutura.
Por exemplo, se quisermos uma estrutura com dados de um aluno, com informao deste como seu nome, nmero de matrcula, entre outros, devemos usar o seguinte fragmento de cdigo que mostra como criar um modelo de estrutura. A palavra-chave struct informa ao compilador que um modelo de estrutura est sendo definido.
Note que a definio termina com um ponto-e-vrgula. Isso ocorre porque uma definio de estrutura um comando. Alm disso, o nome (ou rtulo) da estrutura alunos identifica essa estrutura de dados em particular e o seu especificador de tipo.
Com este cdigo, nenhuma varivel foi de fato declarada. Foi feito apenas uma definio do formato da estrutura. Para declarar uma varivel com essa estrutura escreva
struct alunos informacao;
Isso declara uma varivel do tipo estrutura alunos chamada informacao. O compilador C aloca automaticamente memria suficiente para acomodar todas as variveis que formam a varivel estrutura. Neste caso, esta estrutura ocupa na memria o espao de 113 bytes.
Voc tambm pode declarar uma ou mais variveis enquanto a estrutura definida. Por exemplo,
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 48 O nome da estrutura pode ser omitido se voc precisar apenas de uma varivel estrutura. Isso significa que
Declara uma varivel chamada informacao como definido pela estrutura que a precede.
Portanto, a forma geral de uma definio de estrutura
struct nome { tipo nome_da_varivel1; tipo nome_da_varivel2; . . . tipo nome_da_varivelN; }variveis_estrutura;
Onde nome ou variveis_estrutura podem ser omitidos, mas no ambos.
Refereciando Elementos de Estruturas
Os elementos individuais de estruturas so referenciados atravs do operador ponto (.). Por exemplo, digamos que voc deseja acessar o nmero de faltas de um aluno, atribuindo a esse um valor, escreva
informacao.numero_de_faltas = 2;
O nome da varivel estrutura seguido por um ponto e pelo nome do elemento referencia esse elemento individual da estrutura. A forma geral para acessar um elemento de estrutura
nome_da_varivel_estrutura.nome_do_elemento
Portanto, para escrever o numero de faltas na tela escreva
printf("%d",infomrmacao.numero_de_faltas);
Analogamente, pode ser usada a funo gets() para receber o nome do aluno
gets(informacao.nome);
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 49 Matrizes de Estruturas
Para declarar uma matriz de estruturas, voc deve primeiro definir uma estrutura e, ento, declarar uma varivel matriz desse tipo. Por exemplo, para declarar uma matriz de estruturas com 50 elementos do tipo alunos, que foi definido anteriormente, deve-se escrever
struct alunos informacao[50];
Isso cria 50 conjuntos de variveis que esto organizados como definido na estrutura alunos. Para acessar uma determinada estrutura, deve-se indexar o nome da estrutura. Por exemplo, para imprimir o nmero de faltas do aluno 4, escreva
printf(%d , informao[3].numero_de_faltas);
Como todas as outras matrizes, matrizes de estruturas comeam a indexao em zero.
Passando estruturas para funes
At agora, todas as estruturas e matrizes vistas foram declaradas como globais. Mostraremos agora como passar estruturas e seus elementos para funes.
Quando voc passa um elemento de uma varivel estrutura para uma funo, est, de fato, passando o valor desse elemento para a funo. Veja o exemplo a seguir:
struct novo { char x; int y; float z; char s[10]; }var;
Abaixo so mostrados exemplos de cada elemento sendo passado para uma funo:
funcao1(var.x); /*passa o valor do caractere de x*/ funcao1(var.y); /*passa o valor inteiro de y*/ funcao1(var.z); /*passa o valor float de z*/ funcao1(var.s); /*passa o endereo da string s*/ funcao1(var.s[2]); /*passa o valor do caractere de s[2]*/
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 50 Porm, se voc quiser passar o endereo de um elemento individual da estrutura, ponha o operador & antes do nome da estrutura. Por exemplo, escreva:
funcao1(&var.x); /*passa o endereo do caractere de x*/ funcao1(&var.y); /*passa o endereo inteiro de y*/ funcao1(&var.z); /*passa o endereo float de z*/ funcao1(var.s); /*passa o endereo da string s*/ funcao1(&var.s[2]);/*passa o endereo do caractere de s[2]*/
Quando uma estrutura usada como um argumento para uma funo, a estrutura inteira passada usando o mtodo padro chamado por valor. Quando usar uma estrutura como parmetro, lembre-se de que o tipo de argumento deve coincidir com o tipo de parmetro. Por exemplo, esse programa imprime os nmeros 100 e 250, e uma constante string na tela. Definimos uma estrutura global e, ento usamos seu nome para declarar variveis estruturas e parmetros, conforme necessrio.
void funcao2(struct estrutura param2) { printf("\n%d", param2.a); printf("\n%s", param2.ch); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 51 Ponteiros para Estruturas
Na linguagem C permitido usar ponteiros para estruturas assim como ponteiros para outros tipos de variveis.
Com outros ponteiros, voc declara ponteiros para estrutura colocando * na frente do nome da varivel estrutura. Por exemplo, o cdigo seguinte declara um ponteiro para dados do tipo struct.
struct alunos *ptr;
Se vrias estruturas so usadas, a performance de seu programa pode ser reduzida a nveis inaceitveis, a soluo para esse problema passar apenas um ponteiro para uma funo. E tambm, atualmente a grande gama dos programas utilizando estruturas no possui tamanho definido, precisando para isso, realizar uma alocao dinmica de memria. Para encontrar o endereo da varivel estrutura, deve-se colocar o operador & antes do nome desta varivel. Por exemplo:
este cdigo pe o endereo da estrutura informacao no ponteiro ptr.
Para acessar os elementos de uma estrutura usando um ponteiro para estrutura, voc deve usar o operador -> (chamado operador seta). Por exemplo, isso referencia o campo numero_de_faltas:
ptr -> numero_de_faltas;
Este operador seta usado no lugar do operador ponto quando se est acessando um elemento de estrutura atravs de um ponteiro para a estrutura. Portanto lembre-se de usar o operador ponto para acessar elementos de estruturas quando estiver operando atravs da varivel estrutura, e usar o operador seta quando voc estiver operando atravs de um ponteiro para a estrutura.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 52 Estruturas Aninhadas
Quando um elemento de uma estrutura um elemento de outra estrutura, dizemos que esta uma estrutura aninhada. Considere o exemplo abaixo:
Como podemos perceber, a estrutura aluno possui dois elementos. O primeiro elemento a estrutura do tipo endereo, que contm outros dois elementos com dados do aluno relacionado ao seu endereo. O segundo elemento nome, que um vetor do tipo char.
Para acessar os elementos de uma estrutura, como sabemos, utilizamos uma varivel estrutura. Neste caso, como h uma estrutura dentro da outra, devemos utilizar duas variveis estruturas para acessar algum elemento da estrutura mais interna. O padro ANSI C especifica que as estruturas podem ser aninhadas at 15 nveis.
#include <stdio.h> #include <conio.h>
struct endereco { char rua[80]; int numero_da_casa; } var;
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 53 Captulo 8 Entrada/Sada pelo Console
Input/Output traduzindo teramos Entrada/Sada, mais conhecido como simplesmente I/O ou E/S, so funes como o prprio nome j indica, funes de entrada e sada. O arquivo de cabealho dessas funes STDIO.H, que quer dizer standard input/output. Podemos ter funes de I/O de diversas formas, como atravs do console, ou atravs de arquivos. Primeiramente vamos fala de I/O atravs do console. As funes I/O mais simples so getchar(), que l um caractere do teclado, e putchar() que escreve um caractere na tela. Ambas retornam EOF se ocorrer algum erro. Vejamos um exemplo de funo que l caracteres do teclado e inverte a caixa deles, isto , escreve maisculas como minsculas ou vice-versa.
Contudo existem alguns problemas com o getchar(), como a verso de original de C era compatvel com o UNIX, getchar() armazena em um buffer a entrada at que seja pressionado ENTER. Assim temos as funes getch() e getche(), que pertencem a biblioteca CONIO.H, embora elas no sejam definidas pelo padro ANSI, elas so mais recomendadas. A funo getch() espera at que uma tecla seja pressionada, e retorna imediatamente, e no mostra o caractere na tela. A getche() igual a getch(), mas a tecla mostrada.
Para ler e escrever strings temos as funes gets() e puts(), assim como temos as funes printf() e scanf(). A diferena bsica que uma chamada a gets() ou puts() requer bem menos tempo que printf() e scanf() porque elas aceitam apenas strings de caracteres, no se pode escrever nmeros ou fazer converses de formato. Por essa razo gets() e puts() so mais utilizadas quando o mais importante possuir um cdigo altamente otimizado. Sendo assim vamos tratar apenas das funes printf() e scanf().
#include <stdio.h> #include <conio.h> #include <ctype.h> //necessrio para as funes islower, //toupper, tolower
void main() { char ch;
printf("Digite uma frase (digite ponto para sair). \n"); do { ch = getch(); if (islower(ch)) ch = toupper(ch); else ch = tolower(ch); putchar(ch); }while (ch != '.'); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 54 Funo: printf()
O prottipo para printf()
int printf(char *string_de_controle, lista_de_argumentos);
string_de_controle constituda, basicamente, de dois tipos de itens. O primeiro tipo formado pelos caracteres que sero impressos na tela. O segundo contm comandos de formato que definem a maneira como os argumentos subseqentes sero mostrados, veja exemplo:
printf(Estou %s linguagem %c, aprendendo, C);
Ser impresso na tela: Estou aprendendo linguagem C
Um comando de formato constitudo do smbolo porcentagem (%) seguido pelo cdigo de formato, exemplos: %c ; %s ; %i (veja tabela abaixo). Deve haver o mesmo nmero de argumentos e de comandos de formato e estes dois so combinados na ordem, da esquerda para a direita.
Cdigo Formato %c Caractere %d Inteiros decimais com sinal %i Inteiros decimais com sinal %e Notao cientfica (e minsculo) %E Notao cientfica (E maisculo) %f Ponto flutuante decimal %g Usa %e ou %f, o que for mais curto %G Usa %E ou %F, o que for mais curto %o Octa sem sinal %s String de caracteres %u Inteiros decimais sem sinal %x Hexadecimal sem sinal (letras minsculas) %X Hexadecimal sem sinal (letras maisculas) %p Apresenta um ponteiro %n Ponteiro utilizado para inteiro no qual o nmero de caracteres escritos at esse ponto colocado %% Escreve o smbolo %
Para se escrever caracteres se utiliza %c, %s para strings, %d ou %i para indicar decimal com sinal, %d e %i so equivalentes, %f representa nmeros em ponto flutuante, %e ou %E indicam que se deve mostrar um double em notao cientifica, o %g ou %G faz com que o printf() decida utilizar %f ou %e, assim selecionando o de sada mais curta. Exemplo de utilizao de printf() :
char s[20]; gets(s); printf(Eu gosto de %s ., s); Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 55
Especificadores de largura mnima de campo
O nmero colocado entre o smbolo % e o cdigo do formato age como especificador de largura mnima de campo. Se a string, ou nmero, for maior do que o mnimo, este ser escrito por inteiro, caso contrrio ele preenche a sada com espaos. Ao invs de espaos, se quiser completar com zeros deve se colocar um zero antes do especificador da largura mnima. Por exemplo %05d preencher um nmero de menos de cinco dgitos com zeros de forma que seu comprimento total seja 5. Veja o exemplo abaixo:
Este programa produz o seguinte resultado:
Especificador de preciso
O especificador de preciso segue o especificador de largura mnima de campo (se houver algum), consistindo em um ponto seguido de um inteiro. O seu significado exato depende do tipo de dado a que est sendo aplicado.
Especificador de preciso aplicado a um ponto flutuante determina o nmero de casas decimais a ser mostrado. Por exemplo, %10.4f mostra um nmero com pelo menos 10 caracteres e 4 casas decimais.
Aplicado a %g ou %G ele determina a quantidade de dgitos significativos a serem impressos na tela. Aplicado a tipos inteiros (int), o especificador de preciso adiciona zeros iniciais para completar o nmero solicitado de dgitos.
Aplicados a strings ele determina o comprimento mximo do campo. Por exemplo, %5.7s ele ir mostrar uma string de no mnimo 5 e no mximo 7 caracteres. #include <stdio.h> #include <conio.h>
_getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 56 Funo: scanf()
Muito parecida com printf(), seria como seu inverso, scanf() a rotina de entrada pelo console de uso geral. Ela pode ler todos os tipos de dados intrnsecos e converte automaticamente nmeros ao formato interno apropriado. Seu prottipo :
int printf(char *string_de_controle, lista_de_argumentos);
A funo scanf() devolve o nmero de itens de dados que foi atribudo, com xito, a um valor. Se houver um erro, esta funo devolve EOF. A string_de_controle determina como os valores so lidos para as variveis apontadas na lista_de_argumentos.
Veja a tabela de especificadores de formato para scanf().
Cdigo Significado %c L um nico caractere %d L inteiro decimal %i L inteiro decimal %e L um nmero em ponto flutuante %f L um nmero em ponto flutuante %g L um nmero em ponto flutuante %o L um octal %s L uma string %x L um nmero hexadecimal %p L um ponteiro %n Recebe um valor igual ao nmero de caracteres lidos at ento %u L um inteiro sem sinal % Busca por um conjunto de caracteres
Todas as variveis utilizadas para receber valores atravs de scanf() devem ser passadas pelos seus endereos. Isso significa que todos os argumentos devem ser ponteiros para as variveis usadas como argumentos. Essa a maneira de C criar uma chamada por referncia e que permite a uma funo alterar o contedo de um argumento.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 57 Quando feita a leitura de um nmero, a funo scanf() termina a leitura de um nmero quando o primeiro caractere no numrico encontrado. J, quando feita a leitura de strings, esta funo l os caracteres at que seja encontrado um caractere de espao em branco.
Descartando espaos em branco indesejados
Descartar espaos em brancos, nada mais do que um caractere de espao em branco na string de controle. Esse espao em branco faz com que o scanf(), salte um ou mais caracteres, de espao em branco da stream de entrada, at que seja encontrado o primeiro caractere de espao no-branco. Exemplo:
Nesse caso a string entrada1 ser aulas e a entrada2 ser MTP.
Descartando caracteres de espao no-branco
Um caractere no-branco na string de controle faz com que scanf() leia e ignore caracteres iguais na stream de entrada. Se o caractere especificado no for encontrado scanf() termina. Exemplo:
sting de entrada => 10,30
int x, y; scanf(%d,%d, &x, &y);
Nesse caso x = 10 e y = 30.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 58 Captulo 9 Entrada/Sada com Arquivo
A linguagem C no contm nenhum comando E/S (entrada e sada). Ao contrrio, todas as operaes de E/S ocorrem atravs de chamadas de funes da biblioteca C padro. Essa abordagem faz o sistema de arquivos de C extremamente poderoso e flexvel.
Streams e Arquivos
O sistema de entrada e sada de C fornece uma interface consistente ao programador C, independente do dispositivo real que acessado, ou seja, esse sistema prov um nvel de abstrao entre o programador e o dispositivo utilizado. Esta abstrao chamada de stream, enquanto que o dispositivo real chamado de arquivo.
Streams
O sistema de arquivos pode trabalhar com uma grande variedade de dispositivos, acionadores de disco, terminais, entre outros. Embora cada um dos dispositivos seja bastante diferente entre si, o sistema de arquivo com buffer transforma-os em um dispositivo lgico chamado de stream, onde todas as stream se comportam de forma semelhante. Existem dois tipos de streams: texto e binria.
Uma stream de texto uma seqncia de caracteres. O padro ANSI permite (mas no exige) que uma stream de texto seja organizada em linhas e terminada por um caractere de nova linha. Porm, o caractere de nova linha. Porm, o caractere de nova linha opcional na ltima linha e determinado pela implementao.
Uma stream binria uma seqncia de bytes com uma correspondncia de um para um com aqueles encontrados no dispositivo externo, ou seja, no ocorre nenhuma traduo de caracteres. Alm disso, o nmero de bytes escritos (ou lidos) o mesmo que o encontrado no dispositivo externo.
Arquivos
Para linguagem C, arquivo pode ser qualquer coisa, como um terminal, uma impressora, ou um arquivo salvo no disco rgido. Para associar uma stream a um arquivo deve-se realizar uma operao de abertura.
Como j foi dito, todas as streams em C so iguais, porm os arquivos possuem diferenas. Por exemplo, um disco rgido pode suportar acesso aleatrio, enquanto que um teclado no pode.
Uma vez que, uma stream estiver associada a um arquivo e voc no precisar mais trocar informaes entre seu programa e o arquivo, voc realizar uma operao de fechamento. Se um arquivo aberto para sada for fechado, o contedo, se houver algum, de sua stream associada escrito no dispositivo externo. Esse processo geralmente referido como descarga (flushing) da stream e garante que nenhuma informao seja acidentalmente deixada no buffer de disco. Quando o programa termina, normalmente com o main() retornando ao sistema operacional ou com um exit(), sendo que, os Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 59 arquivos so fechados automaticamente. Sendo que, eles no so fechados quando um programa quebra (crash).
Uma stream associada a um arquivo tem uma estrutura de controle de arquivo do tipo FILE. Essa estrutura definida no cabealho STDIO.H.
Sistema de Arquivos
Ponteiro de Arquivo
Um ponteiro de arquivo um ponteiro para informaes que definem coisas sobre o arquivo, incluindo seu nome, status e a posio atual do arquivo. Um ponteiro de arquivo uma varivel do tipo FILE. Para ler ou escrever em um arquivo, seu programa precisa de um ponteiro de arquivo. Para declarar um ponteiro de arquivo, use o seguinte comando:
FILE *fp;
Abrindo um Arquivo
Para fins prticos, consideraremos sempre o arquivo neste volume como sendo um arquivo em disco, desconsiderando perifricos, portas externas, entre outros. Para abrir um arquivo, voc deve utilizar a funo fopen(), que abre uma stream para uso e associa um arquivo a ela. Para abrir um arquivo utilize a seguinte comando:
FILE *fp; fp = fopen(nome_do_arquivo, modo);
onde nome_do_arquivo um nome vlido para o arquivo que voc quiser criar. Por exemplo, se voc quiser cadastrar alunos e salvar em um arquivo um nome vlido poderia ser Alunos. Ao dar um nome ao arquivo, voc pode incluir uma especificao de caminho. E modo determina como o arquivo ser aberto. Veja abaixo os modos mais utilizados:
Modo r: Este modo abre um arquivo texto para leitura. Se este arquivo no existir ou no for encontrado, fopen() retorna um erro.
Modo w: Este modo abre um arquivo texto vazio para escrita. Se este arquivo no existir, ele ser criado, porm se ele existe, este ser destrudo para criao de um arquivo vazio para escrita, assim seu contedo ser perdido.
Modo a: Este modo abre um arquivo texto para escrita no final deste, ou seja, em forma de apndice. Explicando melhor, todo arquivo quando criado possui no final dele um marcador EOF (end of file, ou final de arquivo); se o arquivo no existir ele ser criado para escrita, porm se ele existir, ao contrrio do modo w seu contedo no ser destrudo, o marcador EOF ser removido para que continue escrevendo nele.
Modo rb: Anlogo ao modo r, s que ele abre um arquivo binrio para leitura. Modo wb: Anlogo ao modo w, s que ele abre um arquivo binrio para escrita. Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 60
Modo ab: Anlogo ao modo a, s que ele abre um arquivo binrio para apndice.
Modo r+: Este modo abre um arquivo para leitura e escrita. Este arquivo deve existir, seno fopen() retorna um erro. Para escrever neste modo, ao contrrio do apndice, o indicador de posio no se encontra no final do arquivo, e sim no comeo.
Modo w+: Este modo anlogo ao w. Porm ele realiza a leitura e escrita do arquivo.
Modo a+: Este modo anlogo ao a. Porm ele realiza a leitura e apndice.
Modo rb+: Anlogo ao modo r+, s que ele abre um arquivo binrio para leitura e escrita.
Modo wb+: Anlogo ao modo w+, s que ele abre um arquivo binrio para leitura e escrita.
Modo ab+: Anlogo ao modo a+, s que ele abre um arquivo binrio para leitura e apndice.
A funo fopen() devolve um ponteiro de arquivo. Seu programa nunca deve alterar o valor deste ponteiro. Se ocorrer um erro quando estiver tentando abrir um arquivo, fopen() devolve um ponteiro nulo. Para abrir um arquivo texto chamado teste para escrita, escreva desta forma:
O comando if utilizado faz a verificao de erro da abertura do arquivo.
Fechando um Arquivo
Para fechar uma stream que foi aberta atravs de uma chamada fopen() utilize a funo fclose(). Ela escreve qualquer dado que ainda permanece no buffer de disco no arquivo e, ento, fecha normalmente o arquivo em nvel de sistema operacional. Um fclose() tambm libera o bloco de controle de arquivo associado stream, deixando-o disponvel para reutilizao. Por exemplo, para fechar um arquivo como o do exemplo anterior utilize a seguinte notao:
fclose(fp);
onde fp o ponteiro de arquivo devolvido pela chamada fopen().
FILE *fp; fp = fopen(teste, w); if(!fp) { printf(Erro na abertura de arquivo); _getch(); exit(1); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 61 Funes para Arquivos
O sistema de arquivos ANSI contm diversas funes inter-relacionadas. Veja a tabela abaixo:
Nome Funo fopen() Abre um arquivo fclose() Fecha um arquivo putc() Escreve um caractere em um arquivo fputc() O mesmo que putc() getc() L um caractere de um arquivo fgetc() O mesmo que getc() fseek() Posiciona o arquivo em um byte especifico fprintf() para um arquivo o que printf() para o console fscanf() para um arquivo o que scanf() para o console feof() Devolve verdadeiro se o fim de arquivo for atingido ferror() Devolve verdadeiro se houve um erro rewind() Reposiciona o indicador de posio de arquivo no incio do mesmo remove() Apaga um arquivo fflush() Descarrega um arquivo
Funes: putc() e fputc()
Estas duas funes so equivalentes, elas escrevem caracteres no arquivo previamente aberto para escrita atravs da funo fopen(). Os prottipos para essas funes so
int putc(int ch, FILE *fp); int fputc(int ch, FILE *fp);
onde fp um ponteiro de arquivo devolvido por fopen() e ch o caractere a ser escrito. Por razes histricas ch definido como int, mas ch um caractere, veja o exemplo abaixo:
#include <conio.h> #include <stdio.h>
void main() { char ch1 = 'o'; FILE *fp;
fp = fopen("arquivo.txt","w"); if(!fp) { printf("Erro na abertura do arquivo"); _getch(); exit(1); }
putc(ch1, fp); putc('l', fp); fputc('a', fp);
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 62 Este cdigo cria um arquivo chamado arquivo do tipo texto (extenso .txt) e escreve nele a palavra ola, caractere por caractere, exemplificando as diversas formas como pode ser inserido um caractere em um arquivo.
Funes: getc() e fgetc()
Estas duas funes so equivalentes, elas lem caracteres no arquivo previamente aberto para leitura atravs da funo fopen(). O prottipo para essa funo
int getc(FILE *fp); int fgetc(FILE *fp);
onde fp um ponteiro de arquivo devolvido por fopen(). Veja o exemplo abaixo, este programa l o arquivo escrito pelo exemplo anterior e imprime na tela.
O lao do-while repetido enquanto ch no atingir o final do arquivo.
Funo: feof()
Quando um arquivo aberto para entrada binria, um valor inteiro igual marca de EOF pode ser lido. Isso poderia fazer com que a rotina de entrada indicasse uma condio de fim de arquivo apesar do final fsico do arquivo no tiver sido de fato alcanado. Como soluo deste problema temos a funo feof(), que determina quando o final de arquivo foi atingido na leitura de dados binrios. Seu prottipo
int feof(FILE *fp);
#include <conio.h> #include <stdio.h>
void main() { char ch; FILE *fp;
fp = fopen("arquivo.txt","r"); if(!fp) { printf("Erro na abertura do arquivo"); _getch(); exit(1); }
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 63 Esta funo devolve verdadeiro se o final do arquivo for atingido; caso contrrio, devolve falso (0). O seguinte cdigo l um arquivo binrio at que o final do arquivo seja encontrado.
while(!feof(fp)) ch = getc(fp);
Voc pode utilizar esse mtodo tanto para arquivo texto quanto binrios. Veja o exemplo a seguir, que anlogo ao da seo anterior, porm utilizando o novo conceito de feof().
Funes: fputs() e fgets()
As funes fputs() e fgets() efetuam, respectivamente, operaes de escrita e leitura de strings de um arquivo em disco. Elas funcionam de maneira semelhante a putc() e getc(), mas, ao invs de escrever ou ler um nico caractere, elas operam com strings. Seus prottipos so:
int fputs(const char *str, FILE *fp); char *fgets(char *str, int length, FILE *fp);
A funo fgets() l uma string da stream especificada at que um caractere de nova linha seja lido ou que length-1 caracteres tenham sido lidos.
#include <conio.h> #include <stdio.h>
void main() { char ch; FILE *fp;
fp = fopen("arquivo.txt","r"); if(!fp) { printf("Erro na abertura do arquivo"); _getch(); exit(1); }
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 64 Funo: rewind()
A funo rewind() reposiciona o indicador de posio de arquivo no incio do arquivo especificado, ou seja, ela rebobina o arquivo. Seu prottipo
void rewind(FILE *fp);
Veja o exemplo abaixo, voc entra com strings, que gravado no arquivo, para encerrar basta voc teclar ENTER no momento em que se pede uma string. Logo depois o arquivo rebobinado, e feito a leitura dele imprimindo as suas strings na tela.
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 65 Funo: remove()
Para apagar um arquivo basta utilizar o seguinte cdigo:
remove(fp);
Ele devolve zero caso seja bem-sucedido e um valor diferente de zero caso contrrio.
Funo: fflush()
A funo fflush() utilizada para esvaziar o contedo de uma stream de sada. Para utilizar esta funo utilize o seguinte cdigo:
fflush(fp);
Essa funo escreve o contedo de qualquer dado existente no buffer arquivo associado a fp. Se fflush() for chamada com um valor nulo, todos os arquivos abertos para sada so descarregados. Esta funo devolve 0 para indicar sucesso; caso contrrio, devolve EOF.
Funes: fread() e fwrite()
O sistema de arquivo ANSI C fornece duas funes para leitura e escrita de blocos de qualquer tipo de dado, elas so fread() e fwrite(). Seus prottipos so:
Para fread(), buffer um ponteiro para uma regio de memria que receber os dados do arquivo. Para fwrite(), buffer um ponteiro para as informaes que sero escritas no arquivos. O nmero de bytes a ler ou escrever especificado por num_bytes. O argumento count determina quantos itens (cada um de comprimento num_byte) sero lidos ou escritos. Finalmente, fp um ponteiro para uma stream aberta anteriormente.
A funo fread() devolve o nmero de itens lidos. Esse valor pode ser menor que count se o final do arquivo for atingido, ou ocorrer um erro. A funo fwrite() devolve o nmero de itens escritos. Esse valor ser igual a count a menos que ocorra um erro.
Aparentemente, fread() e fwrite() denotam certa complexidade, mas com a prtica notar suas vantagens e que apenas questo aparncia, sendo elas funes extremamente importantes e largamente utilizadas j que seu tempo de leitura e escrita em um arquivo so menores comparados a outras funes.
Veja o exemplo abaixo, o programa grava em um arquivo binrio usando fwrite() e logo depois o l utilizando fread():
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 66
Pegamos uma linha de cdigo para discusso:
fwrite(&i, sizeof(int), 1, fp);
Isso quer dizer que ser gravado uma vez (pois count 1) a informao contida na varivel i, que possui o tamanho de um arquivo do tipo int, no arquivo fp. Sabemos que int possui 2 bytes de tamanho, ento o seguinte cdigo seria perfeitamente aceitvel:
fwrite(&i, 2, 1, fp);
Note tambm que nosso arquivo binrio, portanto ele foi nomeado com a extenso .bin, assim como texto .txt.
O programa anterior perfeitamente vlido, ele grava cada dado individualmente, mas a vantagem do fwrite() e fread() se concentra especialmente em gravar um bloco de dados contendo vrios bytes com apenas uma linha de cdigo. Veja o exemplo abaixo, onde feito o cadastro de um usurio utilizando uma estrutura, escrevendo e lendo seus dados a partir de um arquivo:
#include <conio.h> #include <stdio.h>
void main() { int i = 10; float f = 21.45; char ch = 'a'; long l = 8089514; FILE *fp;
fp = fopen("arquivo.bin","wb+"); if(!fp) { printf("Erro na abertura do arquivo"); _getch(); exit(1); }
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 68 O cdigo acima um bom exemplo de como o fwrite() e o fread() so utilizados, com apenas um fwrite() pode-se escrever no arquivo todo um bloco de dados, que neste caso a estrutura struct usuario. Analgamente, com apenas um fread() pode-se ler todo um bloco de dados.
importante fazer uma verificao de erro sempre que escrever ou ler um arquivo, pois deixa seu programa menos suscetvel a bugs, e se houver realmente um erro, a identificao deste se torna mais fcil. A verificao de erro exemplificada no cdigo acima, utilizando o seguinte comando:
Para entender este comando, lembremos que fwrite() retorna a quantidade de itens escritos, como o count foi definido com 1, fwrite() dever retornar 1 se for bem- sucedida a escrita no arquivo. Mas se for diferente de 1, o bloco ser executado e o programa ser encerrado. Esta lgica anloga ao fread().
Funo: fseek()
A funo fseek() move o indicador de posio de arquivo para um local especfico definido pelo programador. Seu prottipo :
int fseek(FILE *fp, long numbytes, int origin);
Aqui, fp um ponteiro de arquivo devolvido por uma chamada fopen(). numbytes, um inteiro longo, o numero de bytes a partir de origin, que ser tornar a nova posio corrente.
Origin Nome da Macro Incio do arquivo SEEK_SET Posio atual SEEK_CUR Final do arquivo SEEK_END
Portanto, para se mover numbytes a partir do incio do arquivo, origin deve SEEK_SET. Para se mover da posio atual, deve-se utilizar SEEK_CUR e para se mover a partir do final do arquivo, deve-se utilizar SEEK_END. A funo fseek() devolve 0 quando vem-sucedida e um valor diferente de zero se ocorrer um erro.
Imaginemos o exemplo da seo anterior, onde feito o cadastro de usurios. Imaginemos que tenhamos um arquivo com 10 usurios cadastrados e queremos ler a informao do dcimo, portanto podemos o utilizar o seguinte comando para pular os 9 primeiros usurios e colocarmos o indicador de posio corrente onde desejamos:
fseek(fp, 9*sizeof(struct usuario), SEEK_SET);
Com isso podemos perceber que possvel efetuar movimentaes em mltiplos de qualquer tipo de dado simplesmente multiplicando o tamanho dos dados pelo nmero do item que deseja ser alcanado.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 69 Funes: fprintf() e fscanf()
O sistema E/S em C inclui duas funes para leitura e escrita em arquivos, elas so fprintf() e fscanf(). Elas se comportam exatamente como printf() e scanf() exceto por operarem com arquivos. Os seus prottipos so
int fprintf(FILE *fp, const char *control_string,); int fscanf(FILE *fp, const char *control_string,);
onde fp um ponteiro de arquivo devolvido por uma chamada fopen(). fprintf() e fscanf() direcionam suas operaes de E/S para o arquivo apontado por fp.
Veja o exemplo abaixo, o programa l uma string do teclado e os escreve no arquivo, logo em seguida l do arquivo e imprime na tela:
Embora as funes fprintf() e fscanf() geralmente sejam a maneira mais fcil de escrever e ler dados diversos em arquivos em disco, elas no so sempre a escolha mais apropriada. Como os dados so escritos em ASCII e formatados como apareceriam na tela (e no em binrio), um tempo extra perdido a cada chamada. Assim, se h preocupao com velocidade ou tamanho do arquivo deve-se utilizar fread() e fwrite().
#include <conio.h> #include <stdio.h>
void main() { char string[80]; FILE *fp;
fp = fopen("arquivo.txt","w+"); if(!fp) { printf("Erro na abertura do arquivo"); _getch(); exit(1); }
printf("Entre com uma string: "); fscanf(stdin, "%s", string); fprintf(fp, "%s", string);
fclose(fp); _getch(); } Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 70 Captulo 10 Interface Grfica com OpenGL O objetivo desta aula aprender a utilizar a biblioteca OpenGL. Para isto, sero utilizadas as bibliotecas OpenGL, GLU e GLUT, de maneira que o programa fique portvel e possa ser executado tanto no ambiente Windows como no ambiente Linux. Para implementao de aplicaes OpenGL na linguagem de programao C/C++ necessrio criar um projeto para linkar as bibliotecas.
A maior vantagem na sua utilizao a rapidez. OpenGL no uma linguagem de programao, uma poderosa e sofisticada API (Application Programming Interface) para criao de aplicaes grficas 2D e 3D.
A API inclui aproximadamente 250 comandos e funes. No existe um formato de arquivo OpenGL para modelos ou ambientes virtuais. OpenGL fornece um pequeno conjunto de primitivas grficas para construo de modelos, tais como pontos, linhas e polgonos.
Caractersticas Principais Projetada para aplicaes grficas interativas 2D e 3D Derivada de GL (Graphics Library SGI) Permite criar programas interativos que produzem imagens coloridas de objetos em movimento Independente do sistema operacional Aspectos Tcnicos As primitivas so vrtices e imagens No gerencia eventos de controle (mouse, exibio, teclado, etc) Tipos de Dados Tipo de dado OpenGL Representao interna Tipo de dado C equivalente Sufixo GLbyte 8-bit integer signed char b GLshort 16-bit integer short s GLint, GLsizei 32-bit integer int ou long i GLfloat, GLclampf 32-bit floating-point float f GLdouble, GLclampd 64-bit floating-point double d GLU (Graphics Utility Library) Conjunto de rotinas utilizadas freqentemente Construdas a partir de comandos OpenGL Rotinas para: Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 71 Manipulao de projees Desenho de superfcies qudricas Curvas e superfcies NURBS (representaes geomtricas complexas Spline) Manipulao de superfcies poligonais
Convenes para os Nomes das Funes <PrefixoBiblioteca><ComandoRaiz><ContadorArgumentosOpcional> <TipoArgumentosOpcional> Bibliotecas GL OpenGL: Contm as funes padres do OpenGl, definidas pelo OpenGL Architeture Review Board. GLU - OpenGL Utility Library: contm vrias rotinas que utilizam os comandos OpenGL de baixo nvel para executar tarefas como, por exemplo, definir as matrizes para projeo e orientao da visualizao, e fazer o rendering de uma superfcie. Esta biblioteca fornecida como parte de cada implementao de OpenGL, e suas funes usam o prefixo glu. GLUT - OpenGL Utility Toolkit: um toolkit independente de plataforma, que inclui alguns elementos GUI (Graphical User Interface), tais como menus pop- up e suporte para joystick. Esta biblioteca, escrita por Mark Kilgard, no domnio pblico, mas free. O seu principal objetivo esconder a complexidade das APIs dos diferentes sistemas de janelas. O seu principal objetivo esconder a complexidade das APIs dos diferentes sistemas de janelas. As funes desta biblioteca usam o prefixo glut. interessante comentar que a GLUT substitiu a GLAUX, uma biblioteca auxiliar OpenGL que havia sido criada para facilitar o aprendizado e a elaborao de programas OpenGL independente do ambiente de programao (Linux, Windows, etc.). GLAUX OpenGL Auxiliar Contm os comandos da chamada auxiliar. Permitem desenvolver aplicaes simples, independente de plataforma e sistema operacional. GLX - OpenGL Extension to the X Window System: fornecido como um "anexo" de OpenGL para mquinas que usam o X Window System. Funes GLX usam o prefixo glX. Para Microsoft Windows 95/98/NT, as funes WGL fornecem as janelas para a interface OpenGL. Todas as funes WGL usam o prefixo wgl. Para IBM/OS2, a PGL a Presentation Manager para a interface OpenGL, e suas funes usam o prefixo pgl. Para Apple, a AGL a interface para sistemas que suportam OpenGL, e as funes AGL usam o prefixo agl. FSG - Fahrenheit Scene Graph: um toolkit orientado objetos e baseado em OpenGL, que fornece objetos e mtodos para a criao de aplicaes grficas 3D interativas. FSG, que foi escrito em C++ e separado de OpenGL, fornece componentes de alto nvel para criao e edio de cenas 3D, e a habilidade de trocar dados em outros formatos grficos.
Primeiro Programa Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 72 Estrutura geral de um Programa OpenGL Podemos imaginar um programa OpenGL como dividido em vrias sees. Cada seo representada por um conjunto de funes, invocadas ou do programa principal ou de outra seo. #include <gl/glut.h> // Funo callback chamada para fazer o desenho void Desenha(void) { //Limpa a janela de visualizao com a cor de fundo especificada glClear(GL_COLOR_BUFFER_BIT); //Executa os comandos OpenGL glFlush(); }
// Inicializa parmetros de rendering void Inicializa (void) { // Define a cor de fundo da janela de visualizao como preta glClearColor(0.0f, 0.0f, 0.0f, 1.0f); }
// Programa Principal int main(void) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutCreateWindow("Primeiro Programa"); glutDisplayFunc(Desenha); Inicializa(); glutMainLoop(); }
O Cdigo acima vai gerar esta janela.
Agora vamos explicar passo a passo cada comando utilizado.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 73
Avisa a GLUT que tipo de modo de exibio deve ser usado quando a janela criada. Neste caso os argumentos indicam a criao de uma janela single-buffered (GLUT_SINGLE) com o modo de cores RGBA (GLUT_RGB). O primeiro significa que todos os comandos de desenho so feitos na janela de exibio.
glutCreateWindow("Primeiro Programa");
o comando da biblioteca GLUT que cria a janela. Neste caso, criada uma janela com o nome "Primeiro Programa". Este argumento corresponde a legenda para a barra de ttulo da janela.
glutDisplayFunc(Desenha);
Estabelece a funo "Desenha" previamente definida como a funo callback de exibio. Isto significa que a GLUT chama a funo sempre que a janela precisar ser redesenhada. Esta chamada ocorre, por exemplo, quando a janela redimensionada ou encoberta;
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
a funo que determina a cor utilizada para limpar a janela. Seu prottipo : void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alfa);. GLclampf definido como um float na maioria das implementaes de OpenGL. O intervalo para cada componente red, green, blue de 0 a 1. O componente alfa usado para efeitos especiais, tal como transparncia.
glClear(GL_COLOR_BUFFER_BIT);
"Limpa" um buffer particular ou combinaes de buffers, onde buffer uma rea de armazenamento para informaes da imagem. Os componentes RGB so geralmente referenciados como color buffer ou pixel buffer. Existem vrios tipos de buffer, mas por enquanto s necessrio entender que o color buffer onde a imagem armazenada internamente e limpar o buffer com glClear remove o desenho da janela.
glFlush();
Faz com que qualquer comando OpenGL no executado seja executado. Neste primeiro exemplo tem apenas a funo glClear.
Segundo Programa
Antes de entrar no exemplo 2 vamos conhecer mais algumas funes que possibilitaram o desenho no OpenGL.
Linhas, Pontos e Polgonos
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 74 Com apenas algumas primitivas simples, tais como pontos, linhas e polgonos, possvel criar estruturas complexas. Em outras palavras, objetos e cenas criadas com OpenGL consistem em simples primitivas grficas que podem ser combinadas de vrias maneiras.
Para desenhar outras primitivas, basta trocar GL_POINTS, que exibe um ponto para cada chamada ao comando glVertex, por:
GL_LINES: exibe uma linha a cada dois comandos glVertex; GL_LINE_STRIP: exibe uma seqncia de linhas conectando os pontos definidos por glVertex; GL_LINE_LOOP: exibe uma seqncia de linhas conectando os pontos definidos por glVertex e ao final liga o primeiro como ltimo ponto; GL_POLYGON: exibe um polgono convexo preenchido, definido por uma seqncia de chamadas a glVertex; GL_TRIANGLES: exibe um tringulo preenchido a cada trs pontos definidos por glVertex; GL_TRIANGLE_STRIP: exibe uma seqncia de tringulos baseados no trio de vrtices v0, v1, v2, depois, v2, v1, v3, depois, v2, v3, v4 e assim por diante; GL_TRIANGLE_FAN: exibe uma seqncia de tringulos conectados baseados no trio de vrtices v0, v1, v2, depois, v0, v2, v3, depois, v0, v3, v4 e assim por diante; GL_QUADS: exibe um quadrado preenchido conectando cada quatro pontos definidos por glVertex; GL_QUAD_STRIP: exibe uma seqncia de quadrilteros conectados a cada quatro vrtices; primeiro v0, v1, v3, v2, depois, v2, v3, v5, v4, depois, v4, v5, v7, v6, e assim por diante Funo que desenha um Quadrado
void Desenha(void) Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 75 { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0f, 0.0f, 0.0f); glTranslatef(-100.0f, -30.0f, 0.0f); glScalef(1.5f, 0.5f, 1.0f); glBegin(GL_QUADS); glVertex2i(100,150); glVertex2i(100,100); // Especifica que a cor corrente azul glColor3f(0.0f, 0.0f, 1.0f); glVertex2i(150,100); glVertex2i(150,150); glEnd(); glFlush(); }
Agora sim vamos Fazer nosso Segundo Programa
#include <windows.h> #include "glut/glut.h"
// Funo callback chamada para fazer o desenho void Desenha(void) { glMatrixMode(GL_MODELVIEW); glLoadIdentity();
// Limpa a janela de visualizao com a cor de fundo especificada glClear(GL_COLOR_BUFFER_BIT);
// Especifica que a cor corrente vermelha // R G B glColor3f(1.0f, 0.0f, 0.0f);
// Desenha um quadrado preenchido com a cor corrente glBegin(GL_QUADS); glVertex2i(100,150); glVertex2i(100,100); // Especifica que a cor corrente azul glColor3f(0.0f, 0.0f, 1.0f); glVertex2i(150,100); glVertex2i(150,150); glEnd();
// Executa os comandos OpenGL glFlush(); }
// Inicializa parmetros de rendering Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 76 void Inicializa (void) { // Define a cor de fundo da janela de visualizao como preta glClearColor(0.0f, 0.0f, 0.0f, 1.0f); }
// Funo callback chamada quando o tamanho da janela alterado void AlteraTamanhoJanela(GLsizei w, GLsizei h) { // Evita a divisao por zero if(h == 0) h = 1;
// Especifica as dimenses da Viewport glViewport(0, 0, w, h);
// Inicializa o sistema de coordenadas glMatrixMode(GL_PROJECTION); glLoadIdentity();
// Estabelece a janela de seleo (left, right, bottom, top) if (w <= h) gluOrtho2D (0.0f, 250.0f, 0.0f, 250.0f*h/w); else gluOrtho2D (0.0f, 250.0f*w/h, 0.0f, 250.0f); }
// Programa Principal int main(void) { glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(400,350); glutInitWindowPosition(10,10); glutCreateWindow("Quadrado"); glutDisplayFunc(Desenha); glutReshapeFunc(AlteraTamanhoJanela); Inicializa(); glutMainLoop(); }
Novamente vamos explicar os novos comandos que surgiram em nosso Segundo Exemplo
glutInitWindowSize(400,350);
Especifica o tamanho em pixels da janela GLUT.
glutInitWindowPosition(10,10); Especifica a localizao inicial da janela GLUT, que neste caso o canto superior esquerdo da tela do computador.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 77 glutReshapeFunc(AlteraTamanhoJanela);
Estabelece a funo "AlteraTamanhoJanela" previamente definida como a funo callback de alterao do tamanho da janela. Isto , sempre que a janela maximizada, minimizada, etc., a funo "AlteraTamanhoJanela" executada para reinicializar o sistema de coordenadas.
glColor3f(1.0f, 0.0f, 0.0f);
Determina a cor que ser usada para o desenho (linhas e preenchimento). A seleo da cor feita da mesma maneira que na funo glClearColor, sendo que no necessrio especificar o componente alfa, cujo valor default 1.0 (completamente opaco).
glBegin(GL_QUADS); glEnd();
Usada para desenhar um quadrado preenchido a partir dos vrtices especificados entre glBegin e glEnd. OpenGL mapeia as coordenadas dos vrtices para a posio atual da janela de visualizao na funo callback AlteraTamanhoJanela.
glViewport(0, 0, w, h);
Recebe como parmetro a nova largura e altura da janela. O prottipo desta funo : void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);. Seus parmetros especificam o canto inferior esquerdo da viewport (x,y) dentro da janela, e a sua largura e altura em pixels (width e height). Geralmente x e y so zero, mas possvel usar a viewport para visualizar mais de uma cena em diferentes reas da janela.
gluOrtho2D (0.0f, 250.0f*w/h, 0.0f, 250.0f);
usada para determinar que a projeo ortogrfica (2D) ser utilizada para exibir na tela a imagem 2D que est na janela de seleo definida atravs dos parmetros passados para esta funo. O prottipo desta funo : void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);. No sistema de coordenadas cartesianas, os valores left e right especificam os limites mnimo e mximo no eixo X; analogamente, bottom e top especificam os limites mnimo e mximo no eixo Y.
glMatrixMode(GL_PROJECTION); e glLoadIdentity();
Servem, respectivamente, para avisar a OpenGL que todas as futuras alteraes, tais como operaes de escala, rotao e translao, iro afetar a "cmera" (ou observador), e para inicializar o sistema de coordenadas antes da execuo de qualquer operao de manipulao de matrizes. Sem este comando, cada chamada sucessiva de gluOrtho2D poderia resultar em uma corrupo do volume de visualizao. Em outras palavras, a matriz de projeo onde o volume de visualizao, que neste caso um plano, definido;
Exerccio construa a casinha mostrada na janela abaixo.
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 78
Agora que j temos uma boa noo sobre desenho hora de aprender a animar.
Animao com OpenGL e GLUT
Um quadrado numa janela com fundo preto. Agora, o quadrado ser movido numa direo at bater em uma das bordas da janela e ento mudar de direo. possvel criar um lao que continuamente altera as coordenadas do objeto antes de chamar a funo "Desenha". Isto daria a impresso de que o quadrado se move na janela. O cdigo do Terceiro Programa exibido a seguir:
#include <windows.h> #include <gl/glut.h>
// Tamanho e posio inicial do quadrado GLfloat x1 = 100.0f; GLfloat y1 = 150.0f; GLsizei rsize = 50;
// Tamanho do incremento nas direes x e y // (nmero de pixels para se mover a cada // intervalo de tempo) GLfloat xstep = 1.0f; GLfloat ystep = 1.0f;
// Largura e altura da janela GLfloat windowWidth; GLfloat windowHeight;
// Funo callback chamada para fazer o desenho void Desenha(void) { glMatrixMode(GL_MODELVIEW); glLoadIdentity();
// Limpa a janela de visualizao com a cor de fundo especificada glClear(GL_COLOR_BUFFER_BIT); Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 79
// Especifica que a cor corrente vermelha // R G B glColor3f(1.0f, 0.0f, 0.0f);
// Desenha um quadrado preenchido com a cor corrente glBegin(GL_QUADS); glVertex2i(x1,y1+rsize); glVertex2i(x1,y1); // Especifica que a cor corrente azul glColor3f(0.0f, 0.0f, 1.0f); glVertex2i(x1+rsize,y1); glVertex2i(x1+rsize,y1+rsize); glEnd();
// Executa os comandos OpenGL glutSwapBuffers(); }
// Funo callback chamada pela GLUT a cada intervalo de tempo // (a window no est sendo redimensionada ou movida) void Timer(int value) { // Muda a direo quando chega na borda esquerda ou direita if(x1 > windowWidth-rsize || x1 < 0) xstep = -xstep;
// Muda a direo quando chega na borda superior ou inferior if(y1 > windowHeight-rsize || y1 < 0) ystep = -ystep;
// Verifica as bordas. Se a window for menor e o // quadrado sair do volume de visualizao if(x1 > windowWidth-rsize) x1 = windowWidth-rsize-1;
// Redesenha o quadrado com as novas coordenadas glutPostRedisplay(); glutTimerFunc(33,Timer, 1); }
// Inicializa parmetros de rendering void Inicializa (void) Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 80 { // Define a cor de fundo da janela de visualizao como preta glClearColor(0.0f, 0.0f, 0.0f, 1.0f); }
// Funo callback chamada quando o tamanho da janela alterado void AlteraTamanhoJanela(GLsizei w, GLsizei h) { // Evita a divisao por zero if(h == 0) h = 1;
// Especifica as dimenses da Viewport glViewport(0, 0, w, h);
// Inicializa o sistema de coordenadas glMatrixMode(GL_PROJECTION); glLoadIdentity();
// Estabelece a janela de seleo (left, right, bottom, top) if (w <= h) { windowHeight = 250.0f*h/w; windowWidth = 250.0f; } else { windowWidth = 250.0f*w/h; windowHeight = 250.0f; }
// Programa Principal int main(void) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(400,350); glutInitWindowPosition(10,10); glutCreateWindow("Anima"); glutDisplayFunc(Desenha); glutReshapeFunc(AlteraTamanhoJanela); glutTimerFunc(33, Timer, 1); Inicializa(); glutMainLoop(); }
Novamente vamos explicar os novos comandos OpenGL do exemplo apresentado. glutTimerFunc(33, Timer, 1);
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 81 Estabelece a funo Timer previamente definida como a funo callback de animao. Seu prottipo : void glutTimerFunc(unsigned int msecs, void (*func)(int value), int value);. Esta funo faz a GLUT esperar msecs milisegundos antes de chamar a funo func. possvel passar um valor definido pelo usurio no parmetro value. Como esta funo "disparada" apenas uma vez, para se ter uma animao contnua necessrio reinicializar o timer novamente na funo Timer.
void Timer(int value )
a funo chamada pela glutTimerFunc. No exemplo, as variveis utilizadas para determinar a posio do retngulo so atualizadas nesta funo.
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB),
Foi usada para trocar o modo de exibio de GLUT_SINGLE para GLUT_DOUBLE. Isto faz com que todo o rendering seja feito em um offscreen buffer.
glutSwapBuffers();
usada no lugar da glFlush porque quando feita a troca (ou swap) de buffers, realizada implicitamente uma operao de flush. Esta funo continua fazendo o flush mesmo que o programa esteja sendo executado no modo single-buffer, porm com uma qualidade bastante inferior.
Gerenciamento de Eventos (teclado e mouse)
A biblioteca GLUT tambm contm funes para gerenciar eventos de entrada de teclado e mouse.
glutKeyboardFunc();
Estabelece a funo callback que chamada pela GLUT cada vez que uma tecla que gera cdigo ASCII pressionada (por exemplo: a, b, A, b, 1, 2). Alm do valor ASCII da tecla, a posio (x,y) do mouse quando a tecla foi pressionada tambm retornada. Parmetros de entrada da funo callback: (unsigned char key, int x, int y).
glutSpecialFunc();
Estabelece a funo callback que chamada pela GLUT cada vez que uma tecla que gera cdigo no-ASCII pressionada, tais como Home, End, PgUp, PgDn, F1 e F2. Alm da constante que identifica a tecla, a posio corrente (x,y) do mouse quando a tecla foi pressionada tambm retornada. Parmetros de entrada da funo callback:
(unsigned char key, int x, int y)
GLUT_KEY_F1, GLUT_KEY_F2, GLUT_KEY_F3, GLUT_KEY_F4, GLUT_KEY_F5, GLUT_KEY_F6, GLUT_KEY_F7, GLUT_KEY_F8, GLUT_KEY_F9, GLUT_KEY_F10, GLUT_KEY_F11, GLUT_KEY_F12, GLUT_KEY_LEFT, GLUT_KEY_UP, GLUT_KEY_RIGHT, GLUT_KEY_DOWN, GLUT_KEY_PAGE_UP, Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 82 GLUT_KEY_PAGE_DOWN, GLUT_KEY_HOME, GLUT_KEY_END, GLUT_KEY_INSERT.
glutMouseFunc
Estabelece a funo callback que chamada pela GLUT cada vez que ocorre um evento de mouse. Parmetros de entrada da funo callback: (int button, int state, int x, int y). Trs valores so vlidos para o parmetro button: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON e GLUT_RIGHT_BUTTON. O parmetro state pode ser GLUT_UP ou GLUT_DOWN. Os parmetros x e y indicam a localizao do mouse no momento que o evento ocorreu.
Utilizando Menus e Exibindo Caracteres
A biblioteca GLUT tambm contm funes para gerenciar menus, exibir caracteres e verificar a posio do mouse na janela em qualquer instante. As funes para realizar estas tarefas esto descritas a seguir.
glutBitmapCharacter
Uma das fontes suportadas pela GLUT a bitmap, onde cada caracter corresponde a um bitmap que gerado com a funo glBitmap. A funo glutBitmapCharacter exibe um caractere deste tipo usando OpenGL. Os parmetros de entrada desta funo so:
(void *font, int character)
O primeiro parmetro identifica a fonte que ser utilizada, e o segundo o caractere. As fontes disponveis so:
Estabelece a funo callback que chamada pela GLUT cada vez que o mouse movido sobre a janela corrente enquanto um ou mais de seus botes esto pressionados. Parmetros de entrada da funo callback: (int x, int y). Os parmetros x e y indicam a posio do mouse em coordenadas da janela.
glutPassiveMotionFunc
Estabelece a funo callback que chamada pela GLUT cada vez que o mouse movido sobre a janela corrente enquanto nenhum de seus botes est pressionado. Parmetros de entrada da funo callback: (int x, int y). Os parmetros x e y indicam a posio do mouse em coordenadas da janela. Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 83
glutCreateMenu
Cria um novo menu pop-up e estabelece a funo callback que ser chamada pela GLUT quando uma de suas entradas for selecionada. Parmetros de entrada da funo callback: (int value), onde value corresponde ao valor que identifica a entrada do menu que foi selecionada.
glutAddMenuEntry
Adiciona uma entrada no final do menu corrente. Os parmetros de entrada desta funo so: (char *name, int value), onde name o conjunto de caracteres que ser exibido como uma entrada do menu, e value o valor que ser passado para a funo callback caso esta entrada seja selecionada.
glutAddSubMenu
Adiciona um submenu no final do menu corrente. Os parmetros de entrada desta funo so: (char *name, int menu), onde name o conjunto de caracteres que ser exibido como uma entrada do menu, a partir da qual ser aberto o submenu, e menu o identificador do submenu.
glutAttachMenu
Funo que "relaciona" um boto do mouse com o identificador do menu corrente. O parmetro de entrada desta funo (int button), que corresponde ao identificador do boto do mouse (GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON ou GLUT_RIGHT_BUTTON)
Exerccio Aplique uma transformao geomtrica de translao na casinha para mud-la de lugar (importante: a translao, bem como as transformaes de escala e rotao, deve ser aplicada antes que a casinha seja desenhada);
Como fazer para interagir com o programa sem que seja necessrio compilar o cdigo cada vez que o objeto, por exemplo, trocado de lugar? Neste caso, utiliza-se uma Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 84 funo callback para gerenciar eventos do teclado e/ou mouse. Assim como j feito com a callback que gerencia eventos do teclado "padro", vamos registrar uma uno callback para gerenciar eventos das teclas especiais acrestando a seguinte linha de cdigo na funo main, antes da chamada para a funo Inicializa(): glutSpecialFunc(TeclasEspeciais); Em seguida, declare as seguintes variveis globais, logo aps os includes, utilizando um tipo de dado OpenGL: GLint tx, ty; Inicialize estas variveis na funo Inicializa() com os seguintes valores: tx = 0; ty = 0; Agora altere os parmetros passados para a funo glTranslatef que chamada na funo Desenha, para que sejam passadas estas variveis, da seguinte maneira: glTranslatef(tx, ty, 0); Finalmente, para fazer o tratamento dos eventos, inclua e termine de implementar a funo callback TeclasEspeciais descrita abaixo. Complete cdigo desta funo de maneira a permitir transladar o objeto para cima, para baixo, para a esquerda e para a direita sempre que o usurio pressionar cada uma das teclas de setas (incremente e decremente as variveis tx e ty) void TeclasEspeciais(int key, int x, int y) { switch (key) { case GLUT_KEY_UP: break; case GLUT_KEY_DOWN: break; case GLUT_KEY_LEFT: break; case GLUT_KEY_RIGHT: break; } glutPostRedisplay(); }
Universidade Federal De Uberlndia Faculdade de Engenharia Eltrica e Biomdica 85