ApLP2-2006

163
UNIVERSIDADE REGIONAL INTEGRADA DO ALTO URUGUAI E DAS MISSÕES CAMPUS FREDERICO WESTPHALEN DEPARTAMENTO DE ENGENHARIAS E CIÊNCIA DA COMPUTAÇÃO Linguagem de Programação II C, Pascal e Delphi Ciência da Computação III Prof. Evandro Preuss [email protected] http://www.uri.br/~preuss 1º Semestre/2006

Transcript of ApLP2-2006

Page 1: ApLP2-2006

UNIVERSIDADE REGIONAL INTEGRADA DO ALTO URUGUAI E DAS MISSÕES

CAMPUS FREDERICO WESTPHALEN

DEPARTAMENTO DE ENGENHARIAS E CIÊNCIA DA COMPUTAÇÃO

Linguagem de Programação II

C, Pascal e Delphi

Ciência da Computação III

Prof. Evandro [email protected]://www.uri.br/~preuss

1º Semestre/2006

Page 2: ApLP2-2006

SUMÁRIO

1. INTRODUÇÃO................................................................................................................. 5

2. DADOS.............................................................................................................................. 6

2.1 ELEMENTOS DA LINGUAGEM...........................................................................................62.1.1 Elementos definidos pela linguagem:..........................................................................62.1.2 Elementos definidos pelo Usuário...............................................................................8

2.2 TIPOS DE DADOS............................................................................................................. 82.2.1 Tipos predefinidos pela linguagem..............................................................................82.2.2 Tipos definidos pelo usuário...................................................................................... 10

2.3 CONVERSÕES DE TIPOS DE DADOS..................................................................................112.4 CONSTANTES E VARIÁVEIS............................................................................................11

2.4.1 Constantes................................................................................................................. 112.4.2 Variáveis................................................................................................................... 122.4.3 Classes de armazenamento........................................................................................ 12

2.5 OPERADORES................................................................................................................. 132.5.1 Operadores aritméticos............................................................................................. 132.5.2 Operadores de atribuição.......................................................................................... 132.5.3 Operadores relacionais e lógicos..............................................................................132.5.4 Operadores bit a bit.................................................................................................. 142.5.5 Operadores de incremento e decremento...................................................................152.5.6 Operador Condicional..............................................................................................152.5.7 Operador Vírgula...................................................................................................... 16

3. ESTRUTURA DO PROGRAMA...................................................................................17

3.1 ESTRUTURA DE UM PROGRAMA EM PASCAL.................................................................173.1.1 Identificação do programa........................................................................................173.1.2 Bloco de Declarações................................................................................................ 173.1.3 Bloco de Comandos................................................................................................... 18

3.2 ESTRUTURA DE UM PROGRAMA EM C...........................................................................183.2.1 Bloco de Diretivas de Compilação............................................................................183.2.2 Bloco de Declarações:.............................................................................................. 193.2.3 Bloco de Implementação:.......................................................................................... 19

4. COMANDOS................................................................................................................... 20

4.1 COMANDOS SIMPLES...................................................................................................... 204.1.1 Comandos de Entrada e Saída..................................................................................204.1.2 Comandos de Desvio Incondicional..........................................................................25

4.2 ESTRUTURAS DE CONTROLE..........................................................................................264.2.1 Seqüência.................................................................................................................. 264.2.2 Comandos condicionais............................................................................................264.2.3 Comandos de Repetição............................................................................................31

5. FUNÇÕES E PROCEDIMENTOS................................................................................38

5.1 PROCEDIMENTOS............................................................................................................ 385.1.1 Passagem de parâmetros........................................................................................... 38

5.2 FUNÇÕES....................................................................................................................... 395.2.1 Estilos e protótipos das funções................................................................................395.2.2 Argumentos das funções............................................................................................ 39

Page 3: ApLP2-2006

5.2.3 Tipos de funções........................................................................................................ 415.3 ARGUMENTOS PASSADOS A PROGRAMAS.......................................................................43

5.3.1 Argumentos passados a programas em PASCAL.......................................................435.3.2 Argumentos passados a programas em C..................................................................43

6. MATRIZES...................................................................................................................... 45

6.1 MATRIZES EM PASCAL................................................................................................... 456.2 MATRIZES EM C............................................................................................................. 466.3 STRINGS......................................................................................................................... 476.4 MATRIZES E VETORES COMO PARÂMETROS DE FUNÇÕES................................................48

7. PONTEIROS................................................................................................................... 51

7.1 DEFINIÇÃO DE PONTEIROS.............................................................................................. 517.1.1 Declaração de variáveis tipo ponteiro.......................................................................527.1.2 Usando variáveis tipo ponteiro.................................................................................. 527.1.3 Inicializando variáveis do tipo ponteiro....................................................................547.1.4 Limitações no operador de endereços.......................................................................557.1.5 Ponteiros para matrizes............................................................................................557.1.6 Ponteiros para ponteiros........................................................................................... 567.1.7 Aritmética com ponteiros..........................................................................................56

7.2 PONTEIROS PARA FUNÇÕES............................................................................................ 577.3 PONTEIROS EM PASCAL.................................................................................................. 59

8. ESTRUTURAS, UNIÕES E ITENS DIVERSOS...........................................................62

8.1 ESTRUTURAS................................................................................................................. 628.1.1 Passando uma estrutura para uma função................................................................638.1.2 Matriz de Estruturas.................................................................................................. 638.1.3 Estruturas dentro de estruturas.................................................................................648.1.4 Ponteiros para estruturas.......................................................................................... 658.1.5 Estruturas em Pascal e Delphi..................................................................................66

8.2 UNIÕES.......................................................................................................................... 688.3 ITENS DIVERSOS............................................................................................................. 69

8.3.1 typedef....................................................................................................................... 698.3.2 enum......................................................................................................................... 70

9. ALOCAÇÃO DINÂMICA DE MEMÓRIA...................................................................71

9.1 LISTA ENCADEADA COM ALOCAÇÃO DINÂMICA DE MEMÓRIA:.......................................74

10. ARQUIVOS................................................................................................................. 80

10.1 ARQUIVO TIPADO EM DELPHI E PASCAL........................................................................8010.1.1 Declaração de arquivos........................................................................................8010.1.2 Funções de abertura e fechamento de arquivos.....................................................8110.1.3 Funções de escrita e gravação..............................................................................83

10.2 ARQUIVOS TEXTO EM PASCAL E DELPHI.......................................................................8810.2.1 Funções para manipulação de arquivos texto.......................................................90

10.3 ARQUIVOS SEM TIPOS EM PASCAL E DELPHI....................................................9210.3.1 Funções para manipulação de arquivos sem tipos................................................9210.3.2 Arquivos com diversas estruturas em Pascal e Delphi...........................................93

10.4 ARQUIVOS EM C............................................................................................................ 9610.4.1 Declaração de arquivos........................................................................................9810.4.2 Funções de abertura e fechamento de arquivos.....................................................98

Page 4: ApLP2-2006

10.4.3 Funções de escrita e gravação..............................................................................9910.4.4 Funções de Escrita e Gravação em Arquivos Texto.............................................10110.4.5 Funções "fseek" , "ftell" e "rewind".....................................................................10410.4.6 Arquivos com diversas estruturas........................................................................105

11. LINGUAGEM DELPHI............................................................................................ 108

11.1 CONCEITOS BÁSICOS.................................................................................................... 11011.1.1 Programação em Windows: Janelas e eventos....................................................110

11.2 PROGRAMAÇÃO ORIENTADA A OBJETO (POO)............................................................11011.3 O AMBIENTE DO DELPHI..............................................................................................111

11.3.1 Arquivos que Compõem um Aplicação................................................................11111.3.2 Arquivos Gerados pela Compilação....................................................................111

11.4 COMPONENTES............................................................................................................. 11211.4.1 Nomenclatura...................................................................................................... 11211.4.2 Propriedades....................................................................................................... 11211.4.3 Eventos............................................................................................................... 11311.4.4 Métodos.............................................................................................................. 11311.4.5 Janelas................................................................................................................ 11411.4.6 TMainMenu........................................................................................................ 11411.4.7 TPopUpMenu...................................................................................................... 11511.4.8 TLabel................................................................................................................. 11511.4.9 TEdit................................................................................................................... 11611.4.10 TMemo................................................................................................................ 11611.4.11 TButton............................................................................................................... 11611.4.12 TCheckBox.......................................................................................................... 11611.4.13 TRadioButton...................................................................................................... 11611.4.14 TListBox.............................................................................................................. 11711.4.15 TComboBox........................................................................................................ 11711.4.16 TScrollBox.......................................................................................................... 11711.4.17 TGroupBox......................................................................................................... 11711.4.18 TRadioGroup...................................................................................................... 11711.4.19 TPanel................................................................................................................ 11811.4.20 TActionList......................................................................................................... 11811.4.21 TBitBtn............................................................................................................... 11811.4.22 TMaskEdit........................................................................................................... 11811.4.23 TBevel................................................................................................................. 11911.4.24 TShape................................................................................................................ 11911.4.25 TImage................................................................................................................ 11911.4.26 TPageControl..................................................................................................... 11911.4.27 TTabSheet........................................................................................................... 12011.4.28 TTimer................................................................................................................ 12011.4.29 TStatusBar.......................................................................................................... 12011.4.30 TStatusPanels..................................................................................................... 12011.4.31 TStatusPanel....................................................................................................... 12011.4.32 TStringGrid......................................................................................................... 120

11.5 CAIXAS DE MENSAGEM................................................................................................ 12111.5.1 ShowMessage...................................................................................................... 12111.5.2 MessageBox........................................................................................................ 12111.5.3 InputBox............................................................................................................. 123

11.6 Dicas........................................................................................................................... 123

Page 5: ApLP2-2006
Page 6: ApLP2-2006

1. INTRODUÇÃO

C é uma linguagem de programação que foi desenvolvida por Dennis Ritchie durante o começo dos anos 70 para ser usada na implementação de sistemas operacionais e outras tarefas de programação de baixo nível.

Em 1960 um comitê de cientistas europeus definiu a linguagem Algol.

Em meados dos anos 60 pesquisadores da Universidade de Cambridge desenvolveram a linguagem BCPL na tentativa de terem um Algol simplificado.

Ainda nos anos 60, Dennis Ritchie desenvolveu a linguagem B a partir da BCPL. Em 1971 Ritchie e Thompson escreveram a primeira versão da linguagem C.

O desenvolvimento inicial de C ocorreu entre 1969 e 1973 (de acordo com Ritchie, o período mais criativo foi durante 1972). Em 1973 ela tornou-se poderosa o suficiente para reimplementar o kernel do sistema operacional Unix. Em 1978, Brian Kernighan e Dennis Ritchie publicaram o agora bastante conhecido "C Programming Language" (também conhecido como "o livro branco", K&R).

C tornou-se imensamente popular fora do Bell Labs depois de 1980 e foi por um tempo a linguagem dominante em programação de sistemas e de aplicações de micro-computadores. Ela se consagrou como a linguagem de programação de sistemas, e é a mais importante da comunidade Open Source.

Bjarne Stroustrup e outros no Bell Labs trabalharam no final dos anos 80 para adicionar a orientação a objetos ao C, criando uma linguagem chamada C++. C++ agora é a linguagem mais comum para aplicações comerciais nos sistemas Microsoft Windows, embora C permaneça mais popular no mundo Unix.

Implementações de C não checam erros tais como buffer overflow ou acesso a memória não alocada em tempo de execução. Ferramentas têm sido criadas para ajudar programadores a evitar esses erros. Da mesma forma a linguagem de programação Cyclone é uma versão modificada da linguagem de programação C destinada a reduzir esses problemas.

Page 7: ApLP2-2006

2. DADOS

2.1 Elementos da Linguagem

Normalmente uma linguagem de programação possui dois tipos de elementos: os elementos definidos pela linguagem e os elementos definidos pelo próprio usuário:

2.1.1 Elementos definidos pela linguagem:

2.1.1.1 Letras (alfanuméricas) - PASCAL e C:

A até Za até z

2.1.1.2 Dígitos (numéricos) - PASCAL e C:

0 até 9

2.1.1.3 Símbolos Especiais

Todas as linguagens possuem símbolos especiais que são diferentes em cada linguagem, mas que tem a mesma finalidade:

Pascal C Significado

+ + adição- - subtração* * multiplicação/ / divisão= = = comp. igualdade> > maior que< < menor que

>= >= maior ou igual<= <= menor ou igual<> != diferente:= = atribuição

( ) ( ) parênteses{ ou (* /* início de comentário} ou *) */ final de comentário

; ; separador ' " ou ' demarca strings ou caracteres

6

Page 8: ApLP2-2006

2.1.1.4 Palavras Reservadas ou Palavras Chave

Palavras Reservadas são símbolos que possuem significado definido na linguagem, não podendo ser redefinidos ou usado como nome de identificador.

PASCAL Cand array begin auto break casecase const div char const continuedo downto else default do doubleend file for else enum extern

function goto if float for gotoin label mod if int longnil not of register return shortor packed procedure signed sizeof static

program record repeat struct switch typedefset then to union unsigned void

type until var volatile whilewhile with

Na linguagem C, o restante dos comandos são todos funções (da biblioteca padrão ou não). Todas as palavras reservadas devem ser escritas em minúsculo.

A linguagem Pascal tem ainda alguns identificadores predefinidos pela linguagem conhecidos como Identificadores Padrão. Podem ser constantes, tipos, variáveis ou subprogramas (procedimentos ou funções) e podem ser escritos tanto em minúsculo como em maiúsculo:

abs arqtan boolean char chr coseof eoln exp false input integerln maxint odd ord output pred

read readln real reset rewrite runsin sqr sqrt str succ texttrue trunc write writeln

2.1.1.5 Delimitadores

Os elementos da linguagem (identificadores, números e símbolos especiais) devem ser separados por pelo menos um dos seguintes delimitadores: branco, final de linha ou comentário.

2.1.2 Elementos definidos pelo Usuário

2.1.2.1 Identificadores

Um identificador é um símbolo definido pelo usuário que pode ser um rótulo (label), uma constante, um tipo, uma variável, um nome de programa ou subprograma (procedimento ou função).

7

Page 9: ApLP2-2006

Os identificadores normalmente devem começar com um caractere alfabético e não pode conter espaços em branco.

O número máximo de caracteres que podem format o identificador varia de compilador para compilador. No PASCAL padrão somente os 8 primeiros caracteres são válidos; no TURBO PASCAL pode-se usar identificadores de até 127 caracteres sendo todos significativos e não há distinção entre maiúsculas e minúsculas.

No C somente os 32 primeiros caracteres são significativos e há diferença entre maiúsculas e minúsculas. Em C Cont é diferente de cont que é diferente de CONT.

2.1.2.2 Comentários

Os comentários não tem função nenhuma para o compilador e serve apenas para aumentar a legibilidade e clareza do programa.

2.1.2.3 Endentação

A endentação também não tem nenhuma função para o compilador e serve para tornar a listagem do programa mais clara dando hierarquia e estrutura ao programa.

2.2 Tipos de Dados

Um Tipo de Dado define o conjunto de valores que uma variável pode assumir e as operações que podem ser feitas sobre ela.

Toda variável em um programa deve ser associada a um e somente um tipo de dado. Esta associação é feita quando a variável é declarada na parte de declaração de variáveis do programa.

2.2.1 Tipos predefinidos pela linguagem

PASCAL

tipo intervalo de representação tamanhoshortint -128 a 127 1 bytebyte 0 a 255 1 byteinteger -32.768 a 32.767 2 bytes word 0 a 65.535 2 bytes longint -2.147.483.648 a 2.147.483.647 4 bytes real 2.9 x 10 –39 a 1.7 x 10 38 6 bytes single * 1.5 x 10 –45 a 3.4 x 10 38 4 bytes double * 5.0 x 10 –324 a 1.7 x 10 308 8 bytes extended * 1.9 x 10 –4951 a 1.1 x 10 4932 10 bytes comp * -9.2 x 10 18 a 9.2 x 10 18 8 bytes char os caracteres da tabela ASCII 1 byteboolean TRUE ou FALSE 1 byte

8

Page 10: ApLP2-2006

string tipo estruturado composto por um conjunto de elementos tipo char

quantidade de caracteres x 1 byte

* os tipos assinalados somente podem ser utilizados em máquinas com co-processador matemático (8087, 80287, 80387, 80487) ou com chip processador 80486 DX ou superior.

DELPHI

tipo intervalo de representação tamanhoshortint -128 a 127 1 bytebyte 0 a 255 1 bytesmallint -32.768 a 32.767 2 bytesword 0 a 65535 2 bytesinteger ou longint

-2.147.483.648 a 2.147.483.647 4 bytes

cardinal oulongword

0 a 4294967295 4 bytes

int64 -2 63 a 2 63 8 bytesreal * 2.9 x 10 –39 a 1.7 x 10 38 6 bytes single 1.5 x 10 –45 a 3.4 x 10 38 4 bytes double 5.0 x 10 –324 a 1.7 x 10 308 8 bytes extended 1.9 x 10 –4932 a 1.1 x 10 4932 10 bytes comp ** -2 63 a 2 63 8 bytes char os caracteres da tabela ASCII 1 byteboolean TRUE ou FALSE 1 bytestring tipo estruturado composto por

um conjunto de elementos tipo char

quantidade de caracteres x 1 byte

* Apenas para manter compatibilidade com Pascal. Este tipo não é nativo para processadores Intel e as operações com este tipo são mais lentas que os demais.

** O mesmo que um inteiro de 64 bits (int64)

C

tipo intervalo de representação tamanhochar -128 a 127 1 byteint -32.768 a -32767 2 bytes float 3.4 E-38 a 3.4 E38 4 bytes double 1.7 E-308 a 1.7 E308 8 bytes void –

Modificadores de TipoModificador Long

tipo intervalo de representação tamanholong int -2.147.483.647 a 2.147.483.647 4 bytes long double 1.2 E-4932 a 1.2 E4932 10 bytes

Modificador Unsigned

9

Page 11: ApLP2-2006

tipo intervalo de representação tamanhounsigned char 0 a 255 1 byteunsigned int 0 a 65.535 2 bytes unsigned long int 0 a 4.294.967.295 4 bytes

2.2.2 Tipos definidos pelo usuário

Os tipos definidos pelo usuário são aqueles que usam um grupo de tipos predefinidos ou um subgrupo de algum tipo. Este tipo é chamado de tipo enumerado de dados e representa uma escolha dentre um pequeno número de alternativas.

2.2.2.1 Tipo enumerado discreto

Em Pascal temos o comando TYPE para definir o tipo de dados que queremos:

TYPE tpdias = (segunda, terça, quarta, quinta, sexta, sábado, domingo);

VAR diasem: tpdias;diasem:= segunda; if (diasem = terça) then ...

Em C e C++ temos o comando enum

enum tpdias { segunda, terça, quarta, quinta, sexta, sábado, domingo } diasem

2.2.2.2 Tipo enumerado contínuo

O tipo enumerado contínuo pode ser definido como um intervalo de um tipo enumerado discreto já definido ou de um tipo padrão.

TYPE tpdias = (segunda, terça, quarta, quinta, sexta, sábado, domingo);TYPE tpfimsem = sábado..domingo;

TYPE tpdiautil = segunda..sexta;VAR fimsem: tpfimsem;

fimsem:= sábado; if (fimsem = domingo) then ...

2.3 Conversões de tipos de dados

As operações que usam comandos que envolvem variáveis de diferentes tipos são chamadas de operações de modo misto.

Ao contrário das outras linguagens, C e C++ executam conversões automáticas de dados para um tipo maior ou trunca o valor para um tipo menor.

Devemos ter cuidado quando usamos operações de modo misto em C ou C++, pois os valores podem ser truncados, enquanto que no Pascal devemos prever exatamente o tipo da variável que necessitamos, por exemplo:

10

Page 12: ApLP2-2006

PASCAL: C: C: C:

a, b:integer; int a, b; float a, b; int a;c: real; float c; int c; float b,c;a:=5; a=5; a=5; a=5;b:=3; b=3; b=3; b=3;c:=a/b; c=a/b; c=a/b; c=a/b;

c = 1,66666667 c=1,000000 c=1 c=1,666667

A linguagem C e C++ permitem a conversão temporária dos tipos de variáveis através do operador de conversão.

Sempre que você necessitar a mudar o formato de uma variável temporariamente, simplesmente preceda o identificador da variável com o tipo entre parênteses para aquele que quiser converter. Se utilizarmos o primeiro exemplo de C acima podemos obter o resultado esperado usando um operador de conversão ou cast:

int a, b;float c;a=5;b=3;c=(float)a/b;

c=1,666667

2.4 Constantes e Variáveis

2.4.1 Constantes

Constantes são valores declarados no início do programa e que não se alteram na execução do programa. Podem ser expessas em qualquer base, desde que seguidas algumas regras simples:

1. Constantes em octal na linguagem C devem sempre iniciar com um 0, como em mem = 01777

2. Constantes em hexa na linguagem C devem sempre iniciar com 0x ou 0X, como em mem = 0x1FA

3. Constantes em hexa na linguagem Pascal devem sempre iniciar com $, como em mem = $1FA

4. Constantes em decimal são escritas de modo convencional sem se inicarem com 0

2.4.2 Variáveis

Uma declaração de variável consiste do nome do tipo seguido do nome da variável (em C e C++) ou do nome da variável seguido do nome do tipo (em Pascal).

11

Page 13: ApLP2-2006

Todas as variáveis devem ser declaradas antes de serem usadas. As variáveis devem ser declaradas no início de cada função, procedimento ou início do programa. Não podem ocorrer declarações de variáveis após a primeira sentença executável de uma rotina.

As variáveis podem ser globais ou locais.

Variáveis globais são declaradas fora de qualquer função, valem em qualquer ponto do código, são inicializadas com zero automaticamente e uma única vez, são armazenadas na memória.

Variáveis locais são declaradas dentro das funções, existem apenas enquanto a função na qual foi declarada está ativa. Dentro de funções variáveis locais com mesmo nome de variáveis globais tem preferência, não são inicializadas automaticamente, ou seja, deve-se informar um valor inicial, são alocadas na pilha ("stack").

Os parâmetros das funções são tratados como se fossem variáveis locais, são inicializados com o valor passado na chamada, são declarados na lista de parâmetros, são passados por valor, somente tipos escalares de dados podem ser parâmetros.

2.4.3 Classes de armazenamento

Em C e C++ as variáveis tem diferente classes de armazenamento:

auto: variável automática. É criada quando uma rotina é chamada e destruída quando a rotina termina. É a classe default para variáveis locais a funções.

register: pede ao compilador para colocar uma variável em registrador. O compilador pode, ou não, seguir a "dica" dada pelo programador. É muito comum seu uso em variáveis de controle de laços "for". O operador endereço (&) não pode ser aplicada a uma variável de classe register.

static: é o contrário da variável "auto". Uma variável "static" é alocada na área de dados e sempre existe, mantendo seu conteúdo entre as chamadas de uma rotina.

ex: void teste(){static int x=0;x++;}

Neste caso a inicialização somente será feita na primeira evocação da rotina. O valor de "x" sobreviverá de uma chamada para outra da rotina (cada vez que for chamada, "x" aumentará de valor).

Se uma variável global possui o atributo "static" significa que ela somente poderá ser usada no arquivo onde está declarada, sendo invisível a outros arquivos que componham o sistema.

extern: significa que a variável está declarada em outro arquivo, onde sua área é alocada. É utilizada para variáveis globais a diferentes arquivos componentes de um mesmo projeto (programa).

12

Page 14: ApLP2-2006

volatile: informa ao compilador para não otimizar o uso de uma variável colocando-a em registrador. É utilizado quando uma variável pode ser atualizada concorrentemente por mais de um processo.

2.5 Operadores

2.5.1 Operadores aritméticos

PASCAL e DELPHI C

+ soma + soma– subtração – subtração* multiplicação * multiplicação/ divisão / divisão

MOD resto da divisão inteira % resto da divisão inteiraDIV inteiro da divisão

2.5.2 Operadores de atribuição

Em Pascal e Delphi temos o operador de atribuição:

:=

Em C e C++ temos os seguintes operadores de atribuição:

= += –= *= /= %=

Ex: i=2; –> atribui o número 2 à variável ii+=4; –> i=i+4;x *= y+1; –> x=x*(y+1);p %= 5; –> p = p % 5;

2.5.3 Operadores relacionais e lógicos

Os operadores relacionais são operadores binários que devolvem os valores lógicos verdadeiro e falso.

PASCAL e DELPHI C

> maior que > maior que< menor que < menor que

>= maior ou igual >= maior ou igual<= menor ou igual <= menor ou igual= igual = = igual

<> diferente != diferente

13

Page 15: ApLP2-2006

Os operadores lógicos são usados para combinar expressões relacionais. Também devolvem como resultado valores lógicos verdadeiro ou falso.

PASCAL e DELPHI C

and e && eor ou || ounot não ! nãoxor ou exclusivo ^ ou exclusivo

Uma expressão relacional ou lógica em C ou C++, retornará zero para o valor lógico falso e um para o valor lógico verdade. No entanto, qualquer valor diferente de zero será considerado um valor verdade quando inserido em uma expressão lógica.

2.5.4 Operadores bit a bit

Em C e C++ temos os operadores bit a bit. São operadores capazes de alterar os valores dos bits de uma variável. Funcionam apenas com os tipos char e int.

PASCAL e DELPHI

C OPERAÇÃO

and & eor | ounot ~ nãoxor ^ ou exclusivo

SHR >> shift para direita (divisão por 2)SHL << shift para esquerda (multiplicação por 2)

Exemplos:

C Pascal

char a, b, c; a, b, c: byte

a=1; b=3; a:=1; b:=3

(C) c = a & b 00000001 & 00000011 00000001(Pascal) c:= a and b

(C) c = a | b 00000001 | 00000011 00000011(Pascal) c:= a or b

(C) c = ~a ~ 00000001 11111110(Pascal) c:= not a

(C) c = a ^ b 00000001 ^ 00000011 00000010 (Pascal) c:= a xor b

(C) c = b >> 1 00000011 00000001(Pascal) c:= b shr 1

(C) c = b << 1 00000011 00000110(Pascal) c:= b shl 1

14

Page 16: ApLP2-2006

2.5.5 Operadores de incremento e decremento

Em C e C++ também temos os operadores de incremento e decremento:

++ incremento de um

-- decremento de um

Escrever "m++" ou "++m" quando estes se encontram isolados em uma linha não faz diferença. Quando estiverem sendo usados em conjunto com uma atribuição, entretanto:

Ex:

int m, n;m = 5; n = 4;

m = n++; m = ++n; Res: m = 4 m = 5 n = 5 n = 5

Obs.: A declaração: printf("%d %d %d",n,n++,n+1);

está correta, porém o resultado pode variar de acordo com o compilador dependendo da ordem em que os parâmetros são retirados da pilha (stack).

2.5.6 Operador Condicional

O operador condicional ternário pode ser utilizado em C e C++ quando o valor de uma atribuição depende de uma condição. O operador ternário é sibolizado pelo operador:

?

Exemplo:

if (x>3) k = k + 1; else k = s - 5;

pode ser substituído por:

k=(x>3)? k+1: s-5;

2.5.7 Operador Vírgula

Em C e C++ o operador vírgula avalia duas expressões onde a sintaxe permite somente uma. O valor do operador vírgula é o valor da expressão à direita. É comumente utilizado no laço for, onde mais de uma variável é utilizada. Por exemplo:

for(min=0, max=compr-1; min < max; min++, max--){...}

15

Page 17: ApLP2-2006

16

Page 18: ApLP2-2006

3. ESTRUTURA DO PROGRAMA

3.1 Estrutura de um Programa em Pascal

Normalmente um programa Pascal possui três partes distintas: Identificação do programa, Bloco de declarações e Bloco de comandos.

3.1.1 Identificação do programa

A identificação ou cabeçalho do programa em Pascal dá um nome ao programa e lista seus parâmetros. É a primeira linha do programa.

PROGRAM <identificação> ( <lista de parâmetros> );

3.1.2 Bloco de Declarações

Todo identificador definido pelo usuário em um programa deve ser declarado antes de referenciado (usado), caso contrário o compilador acusará um erro na fase de compilação por desconhecer o identificador.

O Bloco de Declarações define todos os identificadores utilizados pelo Bloco de Comandos, sendo todos opcionais. Quando o Bloco de Delarações existir sempre estará antes do Bloco de Comandos.

Em Pascal o Bloco de Declarações é formado por cinco partes:

3.1.2.1 Parte de Declarações de Rótulos:

Rótulos (labels) existem para possibilitar o uso do comando de desvio incondicional GOTO. Este comando comando gera a desestruturação do programa e não é aconselhado seu uso.

LABEL <rotulo1>, ... , <rotulon>;

3.1.2.2 Parte de Declarações de Constantes:

Define os identificadores que terão valores constantes dureante toda a esxecução do programa, podendo ser números, seqüências de caracteres (strings) ou mesmo outras constantes.

A declaração de constantes inicia pela palavra reservada CONST, seguida po uma seqüência de: identificador, um sinal de igual, o valor da constante e um ponto e vírgula:

CONST <identificador> = <valor> ;

17

Page 19: ApLP2-2006

3.1.2.3 Parte de Declarações de Tipos:

Serve para o programadore criar seus próprios tipos de dados.

A declaração dos tipos é iniciadas pela palavra reservada TYPE, seguida de um ou mais identificadores separados por vírgula, um sinal de igual, um tipo e um ponto e vírgula:

TYPE <tipoident1> , ... , <tipoidentn> = <tipo> ;

3.1.2.4 Parte de Declarações de Variáveis:

Quando declaramos uma variãvel temos que definir, além do nome, seu tipo. O tipo especifica os valores que poderão ser atribuídos a esta variável. O tipo pode ser algum dos tipos predefinidos pela linguagem ou um tipo definido pelo usuário.

A declaração das variáveis é iniciada pela palavra reservada VAR, seguida de um ou mais identificadores, separados por vírgula, um tipo um ponto e vírgula:

VAR < ident1> , ... , <identn> : <tipo> ;

3.1.2.5 Parte de Declarações de Subprogramas:

Nesta parte são declarados e implementados os subprogramas (funções e procedimentos) e devem estar declarados e implementados antes da sua chamada em qualquer parte do programa principal ou de subprogramas.

3.1.3 Bloco de Comandos

O Bloco de Comandos é a última parte que compõe um programa em Pascal e especifica as ações a serem executadas sobre os objetos definidos no Bloco de Declarações.

O Bloco de Comandos é também conhecido como programa principal e é iniciado pela palavra reservada BEGIN seguida de por uma seqüência de comandos e finalizada pela palavra reservada END seguida um ponto.

3.2 Estrutura de um Programa em C

Normalmente um programa em C possui três partes distintas: Bloco de Diretivas de Compilação, Bloco de declarações e Bloco de Implementação

3.2.1 Bloco de Diretivas de Compilação

Como a linguagem C não possui nenhum comando de entrada e saída incorporado à linguagem, todas essas operações são realizadas através de funções que encontram-se nas bibliotecas da linguagem.

Para utilizar essas funções dentro do programa é necessário incluir o cabeçalho das funções no início do programa através da diretiva de compilação #include:

18

Page 20: ApLP2-2006

#include <stdio.h> /* inclui a biblioteca padrão de comandos de entradae saída que se encontra no diretório padrão*/

#include “outros.h” /*inclui uma outra bliblioteca criada pelo usuário que se encontra no diretório corrente */

Também nesse bloco podemos definir as macros para o nosso programa. Uma macro pode ser simplesmente a substituição de um texto como a implementação de uma pequena função, por exemplo:

#define MAXINT 32767

#define triplo(x) ((x)*3)

#define pqt Pressione Qualquer Tecla Para Continuar...

3.2.2 Bloco de Declarações:

No bloco das declarações são declaradas todas as variáveis globais, tipos definidos pelo usuário, estruturas, uniões e declaradas todas as funções (exceto a main) que estão implementadas no programa, através de um protótipo (cabeçalho) da mesma.

int soma(int x, int y);

int num, quant;

char nome[50];

3.2.3 Bloco de Implementação:

No bloco de implementações são implementadas todas as funções que compõem o programa.

Inicialmente se implementa a função principal, que é a primeira a ser executada e logo abaixo todas as demais funções.

void main(){printf(“Olá mundo!”);}

19

Page 21: ApLP2-2006

4. COMANDOS

4.1 Comandos Simples

Os comandos simples ou não estruturados, caracterizam-se por não possuírem outros comandos relacionados.

4.1.1 Comandos de Entrada e Saída

4.1.1.1 Comandos de E/S em Pascal

A linguagem Pascal tem definido os comandos de entrada e saída na própria linguagem.

4.1.1.1.1 Read e Readln

Os comandos de Leitura (entrada) associam valores lidos do teclado ou de arquivos para as variáveis. São eles:

READ ( <var1>, ... , <varn> );

READLN ( <var1>, ... , <varn> );

4.1.1.1.2 Write e Writeln

Os comandos de gravação (saída) transferem para os dispositivos de saída (disco, video ou impressora) os valores das variáveis.

Para mostrar valores no video temos os seguintes comandos:

WRITE ( <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

WRITELN ( <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

Para imprimir valores na impressora temos os seguintes comandos:

WRITE (LST, <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

WRITELN (LST, <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

Para gravar valores em arquivos temos os seguintes comandos:

WRITE (<arq>, <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

WRITELN (<arq>, <var1> , <´texto1´> , ... , < ´texto n´>, <varn>);

20

Page 22: ApLP2-2006

4.1.1.1.3 Readkey

O comando READKEY lê um caracter do teclado e associa a uma variável do tipo char.

4.1.1.2 Comandos de E/S em C

A linguagem C não possui nenhum comando de entrada e saída predefinido na linguagem. Todas as operações de E/S são realizadas por funções que encontram-se nas mais diversas bibliotecas. As principais funções são:

4.1.1.2.1 A função “printf()”

A função “printf” é a função para saída formatada de dados e funciona da seguinte forma: o primeiro argumento é uma string entre aspas (chamada de string de controle) que pode conter tanto caracteres normais como códigos de formato que começam pelo caracter de porcentagem. Caracteres normais são apresentados na tela na ordem em que são encontrados. Um código de formato informa a função “printf” que um item não caracter deve ser mostrado. Os valores correspondentes encontram-se no segundo argumento (lista de argumentos).

SINTAXE: printf(“<string de controle>“,<lista de argumentos>);

Obs.: Além de códigos de formato e caracteres normais a string de controle pode conter ainda caracteres especiais iniciados pelo símbolo “\”.

Exemplos:

printf(“O preço é R$ %d,00”,preco);printf(“São %d horas e %d minutos.”, hora, minuto);printf(“O nome é %s.”,nome);printf(“%d dividido por %d é igual a %f”, n1, n2, (float)n1/n2);printf(“O código de %c é %d”, letra, letra);

Códigos de formato:

Normalmente os códigos de formato são utilizados na sua forma mais simples:

%c caracter simples %d decimal

%ld inteiro “longo” %f ponto flutuante

%o octal %s cadeia de caracteres

%x hexadecima %lf double

Obs.: Deve haver uma variável ou constante para cada código de formato! O tipo das variáveis ou constantes também deve coincidir com os códigos de formato.

int a;float b;char c;double d;

21

Page 23: ApLP2-2006

printf(“%d %f %c %lf”,a,b,c,d);

Sintaxe completa de um código de formato:

%[flags][largura][.precisão][tamanho]<tipo>

<tipo> indica o tipo do valor a ser exibido. Listados acima.

[flags]:

“-” indica alinhamento pela esquerda

“+” força os números a começarem por “+” ou “-”

“ “ os negativos ficam com o sinal de “-” e os positivos comum espaço em branco no lugar do sinal.

[largura]:

n indica o número máximo de casas a ocupar.

0n idêntico ao anterior, apenas com a diferença de que as casasnão ocupadas serão preenchidas com zeros.

[precisão]:

n indica o número de casas após a vírgula.

[tamanho]:

“l” long

Caracteres especiais:

Alguns caracteres, como o de tabulação, não possuem representação gráfica na tela. Por razões de compatibilidade, a linguagem C fornece constantes iniciadas pelo caracter “\” para indicar esses caracteres.

\n nova linha\r retorno do carro\t tabulação\b retrocesso (backspace)\” aspas\\ barra\0 nulo\a sinal sonoro\xn caracter de código n (em hexadecimal)

22

Page 24: ApLP2-2006

Exemplos:

printf(“Olá!\n”);printf(“Linha1\nLinha2\n”);printf(“\tParágrafo\nHoje é %d/%d/%d\n,dia,mes,ano);printf(“Este é o \”\\\” backslach\n”);printf(“\xB3\n);printf(“Atenção!!!\a\a\a Erro!!!\a\n”);

4.1.1.2.2 A função “scanf()”

É a função de entrada formatada de dados pelo teclado. Sua sintaxe é similar à da função “printf“.

scanf(“<expr. de controle>“, <lista de argumentos>);

A expressão de controle pode conter tanto códigos de formatação precedidos pelo sinal “%”, que indicam o tipo dos dados a serem lidos, como caracteres de espaçamento.

a) Códigos de formato:

%c lê um caracter%d lê um inteiro decimal%e lê um número em notação científica%f lê um número de ponto flutuante%s lê uma string%u lê um decimal sem sinal%l lê um inteiro longo%lf lê um double

Sintaxe: [largura][código de formato]

b) Caracteres de Espaçamento:

São considerados caracteres de espaçamento o espaço em branco, o caracter “\t” e o “\n”. Sempre que um destes surgir na string de controle de um comando “scanf” ele indicará que o mesmo deve ser considerado como separador dos valores a serem entrados Esses caracteres serão então lidos pelo “scanf”, porém, não armazenados.

Normalmente quando o usuário está entrando com valores atendendo a um “scanf”, quando o mesmo digita um destes caracteres de espaçamento, o mesmo é lido e não armazenado. A diferença é que se o caracter de espaçamento aparece na string de controle, então o scanf nõ é encerrado enquanto o mesmo não for digitado.

Toda entrada correspondente um comando “scanf” deve sempre ser finalizado por <ENTER>.

Ex.:

void main()

23

Page 25: ApLP2-2006

{float anos, dias;printf(“Digite sua idade em anos: ”);scanf(“%f”,&anos);dias=anos*365;printf(“Você já viveu %f dias\n”,dias);}

Obs.: Por enquanto vamos assumir que todas as variáveis da lista de argumentos, com exceção das variáveis string, deverão ser antecedidas do operador “&”. Mais adiante vamos entender a razão do operador “&” e quando o mesmo deve ser utilizado.

c) “Search set”

É possível ainda, no caso de entradas de strings determinar o conjunto de caracteres válidos (todos os caracteres que não aparecerem nesse conjunto serão considerados separadores).

Sintaxe: %[search set]

Exemplos:

%[A-Z] todos os caracteres de A até Z

%[abc] apenas os caracteres a, b ou c

%[^abc] todos os caracteres menos a, b, c

%[A-Z0-9a-z] maiúsculas + minúsculas + dígitos

4.1.1.2.3 As funções “getche()” e “getch()”

São funções que lêem caracteres do teclado sem esperar a tecla <ENTER>. Ambas não recebem argumentos e devolvem o caracter lido para a função que os chamou. A diferença entre as duas reside no fato de que “getche” ecoa o caracter lido no vídeo.

Exemplo:

void main(){char ch;printf(“Digite algum caracter: ”);ch=getch();printf(“\nA tecla digitada foi %c e seu valor na tabela ASCII é

%d.”,ch,ch);}

Obs.: Devido à maneira diferenciada como tratam o buffer de teclado, o uso das rotinas “getch” e “scanf” no mesmo programa pode trazer problemas. Para contorná-los, a função “fflush(stdin)” garante que o buffer do teclado (stdin - entrada padrão) esteja vazio.

24

Page 26: ApLP2-2006

4.1.2 Comandos de Desvio Incondicional

Comandos de desvio incondicional são comandos que alteram a seqüência normal de execução em um bloco de comandos, transferindo o processamento para um ponto no programa fonte marcado com o rótulo especificado no comando GOTO.

Em Pascal:

label <rótulo>;

begin

GOTO <rótulo>;

. . .

<rótulo> :

<comandos>;

end.

Em C:

{

GOTO <rótulo>;

. . .

<rótulo> :

<comandos>;

}

Devemos evitar sempre que possível o uso de comandos desse tipo.

Exemplo em Pascal:

uses crt;label inicio, fim_ok, fim_qm, fim;var x:char;beginclrscr;inicio:writeln('R-Repetir, F-finalizar por bem, Outra tecla- Finalizar de qualquer maneira');x:=upcase(readkey);if (x='R') then goto inicio;if (x='F') then goto fim_ok;goto fim_qm;fim_ok:writeln('Finalizando por bem');goto fim;fim_qm:writeln('Finalizando de qualquer maneira');fim:readkey;end.

Exemplo em C:

#include <stdio.h>#include <conio.h>#include <ctype.h>

char x;

void main(){

25

Page 27: ApLP2-2006

clrscr();inicio:printf("R-Repetir, F-finalizar por bem, Outra tecla- Finalizar de qualquer maneira\n");x=toupper(getch());if (x=='R') goto inicio;if (x=='F') goto fim_ok;goto fim_qm;fim_ok:printf("Finalizando por bem");goto fim;fim_qm:printf("Finalizando de qualquer maneira");fim:getch();}

4.2 Estruturas de Controle

4.2.1 Seqüência

Seqüência finita de instruções são agrupamentos de comandos, onde cada comando é executado um após o outro e sem desvios. Em Pascal a seqüência é delimitada pelas palavras reservadas BEGIN no início e END no final e seus comando são separados pelo delimitador “;” (ponto e vírgula). Em C a seqüência é delimitada pelos símbolos { no início e } no final e seus comando também são separados pelo delimitador “;” (ponto e vírgula).

4.2.2 Comandos condicionais

4.2.2.1 IF

O comando if é usado para executar um segmento de código condicionalmente. A forma mais simples do comando if é:

if (expressão)

ação;

Neste caso a ação somente será executada se a expressão ou o conjunto de expressões lógicas for verdadeira.

No caso do comando if-else o programa pode ter duas ações distintas. Se a expressão for verdadeira, será executado o conjunto de ações do comando1. Se for falsa será executado o conjunto de ações do comando2.

Em Pascal a implementação do comando if é:

IF condição THEN IF condição THEN

<comando>; <comando1>

ELSE

26

Page 28: ApLP2-2006

<comando2>;

Exemplos em Pascal

uses crt;var x: integer;beginx:=10;if x>15 then begin writeln(‘X é maior que 15’); end;end.

uses crt;var x, y: integer;beginx:=10;if (x>15) and (y>15) then begin writeln(‘X e Y são maiores que 15’); endelse begin writeln(‘X e Y não são maiores que 15’); end;end.

Em C a implementação do comando if é:

if (expressão) if (expressão)

{ {

<comando>; <comando1>;

} }

else {

<comando2>;

}

Exemplos em C:

#include <stdio.h>#include <conio.h>int x;void main(){x = 10;if (x>15) { printf("X é maior que 15\n"); }}

#include <stdio.h>#include <conio.h>int x, y;void main(){x = 10;y = 20;if (x>15 && y>15) { printf("X e Y são maiores que 15\n"); }else { printf("X e Y não são maiores que 15\n"); }}

Obs.: Deve-se tomar cuidado com os comando if-else aninhados. O else sempre está associado ao if mais próximo dentro do mesmo nível de comandos. Blocos mais internos não são considerados.

27

Page 29: ApLP2-2006

O comando if não necessita de uma expressão lógica no lugar do teste. Em C, qualquer expressão que resultar ZERO será considerada como FALSA e qualquer outro valor é considerado VERDADEIRO. Em Pascal somente é aceito os valores booleanos TRUE ou FALSE.

Em C também temos o comando if – else if - else que é freqüentemente utilizado para executar múltiplas comparações sucessiva. Sua forma geral é:

if (expressão1)

ação1;

else if (expressão2)

ação2;

else if (expressão3)

ação3;

Logicamente, cada ação poderia ser um bloco composto exigindo seu próprio conjunto de chaves. Este tipo de controle de fluxo lógico avalia a expressão até que encontre uma que é VERDADEIRA. Quando isto ocorre, todos os testes condicionais restantes serão desviados. No exemplo anterior, nenhuma ação seria tomada se nenhuma das expressões fosse avaliada como VERDADEIRA.

Para executar uma ação padrão no caso de não satisfazer nenhuma das expressões declaradas pode-se colocar um else sem expressão de teste para realizar a ação pretendida, por exemplo:

if (expressão1)

ação1;

else if (expressão2)

ação2;

else if (expressão3)

ação3;

else

ação_padrão;

Exemplo:

#include <stdio.h>#include <conio.h>

int x;

void main(){x = 16;if (x == 5)

{printf("X vale 5\n");}

28

Page 30: ApLP2-2006

else if (x == 10){printf("X vale 10\n");}

else if (x == 15){printf("X vale 15\n");}

else{printf("X não vale 5, 10 ou 15\n");}

}

4.2.2.2 Comando de Seleção múltipla: SWITCH ou CASE

Quando se deseja testar uma variável ou uma expressão em relação a diversos valores usamos o comando de seleção múltipla.

O valor da expressão seletora é comparado com cada elemento da lista de valores. Se existir um valor igual será executada somente a seqüência relacionada ao valor. Caso contrário, ou nenhuma seqüência será executada, ou a seqüência relacionada á cláusula padrão será executada se ela existir.

Em Pascal o comando de seleção múltipla é o comando CASE:

CASE <seletor> OF

<valor1> : <comandos1>;

<valor2> : <comandos2>;

. . .

<valorn> : <comandosn>;

ELSE : <comandos_padrão>;

END;

Exemplo:

uses crt;var x:integer;

beginx := 15;case x of

5: beginwriteln('X vale 5');

end;10: begin

writeln('X vale 10');end;

15: beginwriteln('X vale 15');

29

Page 31: ApLP2-2006

end;else begin

writeln('X nao vale 5, 10 ou 15');end;

end;end.

Em C o comando de seleção múltipla é o comando SWITCH:

Em C devemos tomar um pouco de cuidado, pois o comando switch possui algumas peculiaridades. Sua sintaxe é:

switch (expressão) {

case <valor1>:

<comandos1>;

break;

case <valor2>:

<comandos2>;

break;

...

case <valor n>:

<comandos n>;

break;

default:

<comandos_padrão>;

}

Exemplo:

#include <stdio.h>#include <conio.h>

int x;

void main(){x = 15;switch(x)

{case 5:

{printf("X vale 5\n");break;}

case 10:{printf("X vale 10\n");break;}

case 15:{

30

Page 32: ApLP2-2006

printf("X vale 15\n");break;}

default:{printf("X nao vale 5, 10 ou 15\n");}

}getch();}

Devemos tomar bastante cuidado com o comando obrigatório break, que faz a porção restante do comando switch ser pulada. Caso ele seja removido do segmento de código, seriam executados todos os comandos abaixo dele.

4.2.3 Comandos de Repetição

Os comandos de repetição são caracterizados por permitir que uam seqüência de comandos seja executada um número repetido de vezes.

4.2.3.1 For

O comando for é utilizado para executar uma seqüência de comandos repetidamente e com um número conhecido de vezes.

Em Pascal a sintaxe do comando é:

FOR <var> := <limite_inferior> TO <lim_superior> do

<comando>

ou

FOR <var> := <limite_superior> DOWNTO <limite_inferior> do

<comando>

Exemplos:

for i:= 1 to 10 do beginwriteln(i, ‘x’, 7, ‘=’, i*7);end;

for i:= 10 downto 1 do beginwriteln(i, ‘x’, 7, ‘=’, i*7);end;

Em C a sintaxe do comando é:

for (expr_inicialização; expr_teste; expr_incremento)

<comando>;31

Page 33: ApLP2-2006

Exemplos:

for (i=1; i<=10; i++){printf(“%d x 7 = %d \n”, i, i*7);}

for (i=10; i>=1; i--){printf(“%d x 7 = %d \n”, i, i*7);}

Quando o comando de laço for é encontrado, a expr_inicialização é executada primeiro, no início do laço, e nunca mais será executada. Geralmente esse comando fornece a inicialização da variável de controle do laço. Após isso é testada a expr_teste, que é chamada de cndição de término do laço. Quando expr_teste é avaliada como VERDADEIRA, o comando ou comandos dentro do laço serão executados. Se o laço foi iniciado, expr_incremento é executada após todos os comandos dentro do laço serem executados. Contudo, se exp_teste é avaliada como FALSA, os comandos dentro do laço serão ignorados, junto com expr_incremento, e a execução continua no comando que segue o final do laço. O esquema de endentação para os laços for com diversos comandos a serem repetidos é assim:

for (expr_inicialização; expr_teste; expr_incremento)

{

comando_a;

comando_b;

comando_c;

}

As variáveis de controle de um laço de for podem ter seu valor alterado em qualquer ponto do laço.

Qualqur uma das expressões de controle do laço de for pode ser omitida desde que sejam mantidos os “;”.

As variáveis utilizadas nas três expressões de controle não precisam ter relação entre si.

Ex.:

void main(){char c;int x,y;for(c=9;c>0;c--)

{printf(“%d”,c);}

for(c=9;c>0; ){printf(“%d”,c);

32

Page 34: ApLP2-2006

c--;}

for(x=0,y=0; x+y<100; x=x+4, y++) {printf(“%d+%d=%d\n”,x,y,x+y);}

for(;;){printf(“não saio deste laço nunca!!!!\n”);}

}

4.2.3.2 While

Assim como o laço for, while é um laço com teste no iníco. Isto significa que a expressão teste é avaliada antes dos comandos dentro do corpo do laço serem executados. Por causa disto, os laços com teste no início podem ser executados de zero a mais vezes.

Geralmente estas estruturas são usadas quando um número indefinido de repetições é esperado.

Em Pascal a sintaxe é:

WHILE <condição> do

<comandos>;

Exemplo:

uses crt;var a,b,ano: integer;begina:=1500;b:=2000;ano:=0;while a < b do begin

a := a * 1.05;b := b * 1.02;ano++;end;

writeln(ano, ‘ anos’);end.

Em C a sintaxe é:

while (expr_teste)

<comandos>;

Exemplo.:

void main(){

int a, b,ano;a=1500;b=2000;

33

Page 35: ApLP2-2006

ano=0;while(a<b)

{a=a*1.05;b=b*1.02;ano++;}

printf(“%d anos”,ano);}

4.2.3.3 Do While ou Repeat

Estes comandos, assim como o comando WHILE, são usados quando não é conhecido o número de vezes que uma seqüência de comandos deverá ser executada. Porém a seqüência será executada pelo menos uma vez.

Em Pascal a sintaxe do comando é:

REPEAT

<comandos>;

UNTIL <cond_teste>;

Exemplo:

var a:char;Beginrepeat

clrscr;writeln(‘1 - Executar’);writeln(‘2 - Sair’);a := readkey;if a = ´1´ then executar;

until a =´2´;end.

Em C a sintaxe do comando é:

do

<comandos>

while(cond_teste);

Exemplo.:

void main(){

char a;do {

clrscr();printf(“1 - Executar\n”);

34

Page 36: ApLP2-2006

printf(“2 - Sair\n”);a = getche();if (a == ´1´) executar();

} while (a != ´2´);}

Observe que em Pascal usamos o comando repeat e until fazendo com que o laço repita até que a condição seja satisfeita e em C usamos o comando do e while fazendo com que o laço repita enquanto a condição esteja sendo satisfeita.

4.2.3.4 Comandos de desvio

Nas linguagem C e Pascal temos os comandos de desvio que interrompem a execução de um laço.

4.2.3.4.1 Comando break

O comando break pode ser usado para sair de um laço for, while ou do-while (repeat) mais interno, desde que no mesmo subprograma, passando a seqüência da execução para a primeira linha após o laço.

Exemplo em Pascal:

uses crt;var x: char;i: integer;beginfor i:= 1 to 100 do begin write('Digite um numero entre 0 e 9: '); x:=readkey; if (x < #48) or (x > #57) then break; writeln(x, ' foi digitado!'); end;end.

Exemplo em C:

void main(){char x, i;for(x=1;x<=100;x++)

{printf(“Digite um número de 0 a 9:”);x = getch();if (y < 48 || y > 57) break;printf(“%d foi digitado \n”,x);}

}

4.2.3.4.2 Comando continue

35

Page 37: ApLP2-2006

O comando continue causa o fim de um dos laços de uma repetição e o retorno imediato ao teste.

Exemplo em Pascal:

uses crt;vari: integer;beginfor i:= 1 to 10 do begin if (i mod 2 <> 0) then continue; writeln(i, ' e par!'); end;end.

Exemplo em C:

void main(){int i;for(i=1;i<=10;i++)

{if ( i % 2 != 0) continue;printf(“O número %d é par!”,i);}

}

4.2.3.4.3 Função Exit

A função exit causa a imediata interrupção do programa e o retorno ao sistema operacional. Em C, o valor do parâmetro é retornado ao processo que o chamou que geralmente é o sistema operacional. O valor 0 ( exit(0);) geralmente indica que o processo terminou sem problemas.

Exemplo em Pascal:

uses crt;beginwhile true do begin write('Xx '); if keypressed then exit; end;end.

Exemplo em C:

#include <stdio.h>#include <conio.h>#include <stdlib.h>

void main(){

36

Page 38: ApLP2-2006

while(1){printf("Xx ");if ( kbhit()) exit(0);}

}

4.2.3.4.4 Comando return

O comando return causa uma interrupção no fluxo de comandos de uma função e o retorno a função chamadora. Pode ser usado com ou sem argumento dependento do tipo de função em que é utilizado, porém não é possível em uma única função seu uso com e sem argumentos.

37

Page 39: ApLP2-2006

5. FUNÇÕES E PROCEDIMENTOS

As funções formam o alicerce da programação em C e C++. Conforme vamos aumentando a prática em programação, os programas começam a tomar uma aparência modular quando programamos com funções.

Podemos fazer toda a programação em C e C++ dentro de uma função. Isto porque todos os programas devem incluir main, que é uma função.

As funções são similares aos módulos de outras linguagens. Pascal utiliza procedimentos e funções. Fortran utiliza somente funções, e a linguagem Assembly utiliza somente procedimentos. O modo como as funções trabalham determina o alto grau de eficiência, legibilidade e portabilidade do código do programa em C.

5.1 Procedimentos

Um procedimento é um tipo de subprograma utilizado na linguagem Pascal, que se assemelha em muito com um programa em Pascal. Possui um cabeçalho de identificação com o nome do procedimento, uma lista opcional de parâmetros de comunicação, um bloco de declarações e um bloco de comandos.

5.1.1 Passagem de parâmetros

Quando a variável que se quer trabalhar não é visível dentro do procedimento ela deve ser passada como parâmetro:

5.1.1.1 Passagem de parâmetros por valor

Quando uma variável é passada por valor para um prodedimento, seu valor original não é alterado.

Declaração:

procedure <nome>(<variáveis>:<tipo>)

5.1.1.2 Passagem de parâmetros por referência

Quando uma variável é passada por referência para um prodedimento, seu valor original é alterado na execução do procedimento.

Declaração:

procedure <nome>(var <variáveis>:<tipo>)

38

Page 40: ApLP2-2006

5.2 Funções

Em Pascal as funções podem ser vistas como um procedimento que retorna um único valor.

Ex.:

PROGRAM FUNCAO;VAR pr, imp: REAL;

FUNCTION calc_imposto(preco: REAL):REAL;BEGINcalc_imposto = preco * 0.17;END;

BEGINREADLN(pr);imp = calc_imposto(pr);WRITELN('Preço: ',pr,' Imposto: ',imp);END.

Em C uma função void ou que retorna um valor nulo, pode ser comparada com um procedimento utilizado na linguagem Pascal, porém todas os subprogramas em C são funções e devem retornar um valor (ou retornar void, vazio).

5.2.1 Estilos e protótipos das funções

As declarações de função começam com o protótipo da função C e C++. O protótipo de função é simples e é incluído no início do código do programa para notificar o compilador do tipo e do número de argumentos que uma função utilizará.

Embora outras variações sejam legais, sempre que possível você deve utilizar a forma do protótipo de função que é uma réplica da linha de declaração da função. Por exemplo:

tipo_de_retorno nome_da_função ( tipo(s)_argumento nome(s)_argumento);

5.2.2 Argumentos das funções

Os argumentos, ou parâmetros, passados às funções são opcionais; algumas funções podem não receber argumentos enquanto outras podem receber diversos. Os argumentos podem ser misturados, sendo possível o uso de qualquer um dos tipos de dados escalares padronizados, podendo ser int, float, double, char e ponteiros.

Existem situações onde é necessário que as sub-rotinas retornem valores calculados internamente. A linguagem C apresenta dois mecanismos para tanto:

39

Page 41: ApLP2-2006

5.2.2.1 Passagem de parâmetros por valor

As funções recebem parâmetros por valor quando na lista de argumentos existem valores ou variáveis com valores. Esses argumentos são criados na pilha no momento em que a função é chamada.

O comando return permite que uma função retorne um único valor. Esse valor é obtido na rotina chamadora na medida em que a chamada na função é feita através de uma atribuição (Ex. 2).

Ex. 1:

...int v;v=30;func1(v,25);

...

void func1(int a, int b){int x;a = a + 10;b = b - 10;x = a + b;printf("%d\n",x);}

Ex. 2:void main()

{float pr, imp;scanf("%f",&pr);imp=calc_imposto(pr);printf("Preço: %f, Imposto: %f\n",pr,imp);}

float calc_imposto(float preco);{float imposto;imposto=preco * 0.17;return(imposto);}

No exemplo 1 acima, o valor da variável v e o valor 25 são passados respectivamente para os argumentos a e b da função func1. Apesar do valor de a e b ser alterado dentro da função, essa mudança não se refletirá no valor da variável v pois o que é passado para a função é apenas uma cópia do valor da variável.

5.2.2.2 Passagem de parâmetros por referência

A passagem de parâmetros por referência faz com que os valores das variáveis passadas por referência sejam alterados dentro da função.

Em C, quando queremos que isto aconteça, ao invés de passarmos o valor como parâmetro de uma função, passamos o endereço dessa variável (que não deixa de ser um valor). O endereço,

40

Page 42: ApLP2-2006

no caso, faz as vezes de "referência" para a variável e nos permite alterar o conteúdo da mesma dentro da sub-rotina.

Ex:

void main(){int a;func1(&a);printf("%d",a);}

void func1(int *p){int x;scanf("%d",&x);*p = x * 2;}

Observe que o argumento da função func1 é um ponteiro para inteiro. O que se passa na chamada dessa função, não é o valor da variável a, mas sim seu endereço (até porque nesse momento a nem ao menos foi inicializado). Dentro da função func1, o valor digitado pelo usuário é multiplicado por 2 e é armazenado, não na variável p que contém o endereço de a, mas na própria variável a. Desta forma, quando a função acaba e o controle volta à rotina chamadora, o valor correto já está armazenado em a.

Note-se, então, que o uso de um * antes de uma variável ponteiro em uma expressão significa que não estamos nos referindo ao valor do ponteiro, mas sim ao valor para o qual aponta.

Resumindo, podemos dizer que:

&a é o endereço de a

*p é o conteúdo da variável apontada por p

5.2.3 Tipos de funções

As funções podem ser:

Funções do tipo void: As funções são do tipo void quando indicam explicitamente a ausência de argumentos na função.

EX.:

#include <stdio.h>#include <math.h>

void impressao(void);

main(){printf("Este programa extrai uma raiz quadrada\n");impressao();return(0);

41

Page 43: ApLP2-2006

}

void impressao(void){double z=5678.0;double x;x=sqrt(z);printf("A raiz quadrada de %lf é %lf\n",z,x);}

Funções do tipo char: As funções são do tipo char quando recebem um caracter como argumento.

Ex.:

#include <stdio.h>#include <conio.h>

void impressao(char c);

void main(){char meucaracter;printf("Informe um caracter pelo teclado\n");meucaracter=getch();impressao(meucaracter);}

void impressao(char c){int i;for(i=0;i<10;i++)

printf("O caracter é: %c\n",c);}

Funções do tipo int: As funções são do tipo int quando aceitam e retornam um inteiro como argumentos.

Funções do tipo long: As funções são do tipo long quando aceitam e retornam long int como argumentos.

Funções do tipo float: As funções são do tipo float quando aceitam e retornam float como argumentos.

Ex.:

#include <stdio.h>#include <math.h>

void hipotenusa(float x, float y);

main(){float cateto_y, cateto_x;

42

Page 44: ApLP2-2006

printf("Altura do triângulo retângulo: ");scanf("%f",cateto_y);printf("Base do triângulo retângulo: ");scanf("%f",cateto_x);hipotenusa(cateto_y,cateto_x);return(0);}

void hipotenusa(float x, float y){double minhahipo;minhahipo = hipot((double)x,(double)y);printf("A hipotenusa do triângulo é: %f\n",minhahipo);}

Funções do tipo double: As funções que aceitam e retornam um tipo double, ou seja um float com muita precisão são do tipo double. Todas as funções que estão definidas em math.h aceitam e retornam tipo double.

5.3 Argumentos passados a programas

Nomalmente as linguagens de programação permitem que o programa receba parâmetros passados na linha de comando no momento da sua ativação. Assim, quando usamos o comando format a: ou scan a: passamos o argumento a: para o programa.

5.3.1 Argumentos passados a programas em PASCAL

Os argumentos passados aos programas em Pascal são verificados através de dois comandos (variáveis que estão armazenados os parâmentros):

PARAMCOUNT: armazena o número de argumentos passados na linha de comando. Paramcount igual a zero indica que não há argumentos na linha de comando.

PARAMSTR: armazena as strings de argumentos da linha de comando. ParamStr(1) é o primeiro argumento.

program parametros;uses crt;var I: integer;beginif ParamCount = 0 then begin Writeln('Este programa não tem argumentos!'); exit; end;for I := 1 to ParamCount do Writeln('O ',I,'º parâmetro é: ',ParamStr(I));end.

43

Page 45: ApLP2-2006

5.3.2 Argumentos passados a programas em C

C e C++ podem aceitar inúmeros argumentos da linha de comando. A função main recebe os parâmetros com a seguinte declaração:

main(int argc, char *argv[])

O primeiro argumento é um inteiro que fornece o número de termos da linha de comando. O nome do programa executável conta como sendo o primeiro, isto é, todo programa terá argc com valor 1 se não tiver nenhum parâmetro e valor num_parâmetros + 1 quando tiver parâmetros.

O segundo argumento é um ponteiro para as strings argv. Todos os argumentos são strings de caracteres, de modo que são conhecidos no programa como:

argv[1] primeiro argumentoargv[2] segundo argumento...

Ex.:

#include <stdio.h>#include <stdlib.h>

void main(int argc, char *argv[]){int i;if (argc < 2)

{printf("Este programa não tem argumentos!");exit(1);}

for (i=1;i < argc; i++)printf("O %dº argumento é %s\n",i,argv[i]);

}

Os argumentos são recebidos da linha de comando e impressos na tela na mesma ordem. Se números forem informados na linha de comando, eles serão interpretados como strings ASCII e impressos como caracteres. Se desejarmos fazer cálculos com esses números devemos convertê-los de string para número com as funções de conversão apropriadas (atoi, atol, atof que encontram-se definidas em stdlib.h)

44

Page 46: ApLP2-2006

6. MATRIZES

Matrizes são variáveis indexadas que contêm diversos itens de dados do mesmo tipo. Cada matriz possui um nome, e seus elementos são acessados com a associação de um índice ao nome da matriz.

Uma matriz possui quatro propriedades básicas:

a) Os itens de dados individuais na matriz são chamados de elementos.

b) Todos os elementos devem ser do mesmo tipo de dados.

c) Todos os elementos são armazenados contiguamente na memória do computador, e em linguagem C o índice do primento elemento sempre será zero.

d) O nome da matriz é um valor constante que representa o endereço do primeiro elemento na matriz.

Como todos os elementos são do mesmo tamanho, não podemos definir matrizes usando uma mistura de tipos de dados, pois a localização de um elemento é feita com base no endereço do primeiro elemento mais o deslocamento proporcional ao índice.

As matrizes podem ser unidimensionais quando o acesso a um de seus elementos é feito através de um único índice, também conhecida como vetores em Pascal, ou multidimensionais quando possuem mais que uma dimensão, sendo necessário mais de um índice para acessar um de seus elementos.

6.1 Matrizes em Pascal

Uma matriz unidimensional ou vetor em Pascal é definido com o uso da palavra reservada array, seguida de seus limites inferior e superior entre colchetes, da palavra reservada of e do tipo de componente do vetor.

<nomeVetor> : ARRAY [<lim_inf> .. <lim_sup>] of <TipoComponente>

Ex:

Alunos: Array[1..40] of integer;

Uma matriz multidimensional pode ser comparada a uma tabela de duas ou mais dimensões, sendo necessários tantos índices quantas forem as dimensões.

Uma matriz multidimensional em Pascal é definida com o uso da palavra reservada array, seguida de seus limites inferior e superior para cada dimensão, separada por vírgulas, entre colchetes, da palavra reservada of e do tipo de componente do vetor.

Ex:

Notas: Array[1..40,1..3] of integer;

45

Page 47: ApLP2-2006

Uma matriz pode ser declarada e inicializada declarando-se no bloco de constantes:

constnum1: array [1..5] of integer = (2,4,6,8,10);num2: array [1..2,1..5] of integer = ((10,20,30,40,50),(15,25,35,45,55));

6.2 Matrizes em C

Uma matriz em C é definida escrevendo-se o tipo da matriz, seguida de um nome, e um par de colchetes contendo uma expressão constante que define o tamanho da matriz.

<tipo> <nomematriz> [<tamanho>]

Ex:

int alunos[40];

Uma matriz multidimensional é definida escrevendo-se o tipo da matriz, seguida de um nome, e tantos pares de colchetes quantas forem a dimensões, contendo uma expressão constante que define o tamanho da matriz em cada dimensão.

Ex:

int Notas[40][3];

Em C o primeiro elemento sempre será o elemento de índice 0.

Uma matriz pode ser inicializada explicitamente quando é declarada:

Ex.:

#include <conio.h>#include <stdio.h>

int numeros[3] = {2,4,6};char vogais[5] = {'a','b','c','d','e'};int num[2][5]={{2,4,6,8,10},{1,3,5,7,9}};

void main(){int i,j;for (i=0;i<2;i++)

{printf("\n");for (j=0;j<5;j++)

{printf(" %d",num[i][j]);}

}}

Observe qua não se pode usar uma variável na definição da matriz para dimensionar o seu tamanho, pois o compilador precisa alocar a memória necessária no momento da compilação.

46

Page 48: ApLP2-2006

6.3 Strings

Em Pascal temos o tipo de dado string predefinido na linguagem que nada mais é que um vetor de caracteres.

A linguagem C não possui este tipo de dado. Toda a vez que queremos uma string em C devemos declará-la como:

char <nome> [<tamanho>];

Quando precisamos de um vetor de string, declaramos como uma matriz de caracteres, por exemplo, se queremos uma lista de 250 nomes com 80 letras cada:

char nomes[250][80];

Toda a vez que precisamos fazer operações com strings em C, como comparação, cópia de valores, concatenação, devemos usar as funções predefinidas em string.h:

Função Sintaxe e Função

strcat char *strcat(char *dest, const char *src);Adiciona uma string a outra strcat adiciona uma códia da string de origem para o final da string de destino.

strchr char *strchr(char *s, int c);Procura numa string a primeira ocorrência de um caracter. Retorna um ponteiro para a primeira ocorrência do caracter dentro da string. Se o caracter não for encontrado, strchr retorna NULL..

strcmp int strcmp(const char *s1, const char *s2);Compara uma string com outra e retorna: < 0 se s1 for menor que s2= 0 se s1 for igual s2> 0 se s1 for maior que s2

strcpy char *strcpy(char *dest, const char *src);Copia uma string para outra. Copia string src para dest. Retorna um ponteiro para a string dest.

strcspn size_t strcspn(const char *s1, const char *s2);Procura em s1 até que qualquer um dos caracteres contidos em s2 é encontrado. O número de caracteres que são lidos em s1 é o valor retornado.

stricmp int stricmp(const char *s1, const char *s2);Compara uma string com outra sem distinção entre maiúscula e minúscula e retorna: < 0 se s1 for menor que s2= 0 se s1 for igual s2> 0 se s1 for maior que s2

strlen size_t strlen(const char *s);Calcula e retorna o tamanho de uma string.

strlwr char *strlwr(char *s);Converte letras maiúsculas em minúsculas numa string.

strncat char *strncat(char *dest, const char *src, size_t n);Adiciona uma porção de uma string a outra. strncat copia n caracteres de src para o final de dest e acrescenta um caractere NULL.

strncmp int strncmp(const char *s1, const char *s2, size_t n);Compara uma porção de uma string com uma porção de outra string.strncmp faz a mesma comparação que strcmp, mas analisa no máximo os n primeiros caracteres e retorna: < 0 se s1 for menor que s2= 0 se s1 for igual s2> 0 se s1 for maior que s2

strncpy char *strncpy(char *dest, const char *src, size_t n);Copia um um determinado número de bytes (n) de uma string para outra..

strnicmp int strnicmp(const char *s1, const char *s2, size_t n);Compara uma porção de uma string com uma porção de outra string sem distinção de maiúsculas com minúsculas. strncmp faz a mesma comparação que stricmp, mas analisa no máximo os n primeiros

47

Page 49: ApLP2-2006

caracteres.Retorna: < 0 se s1 for menor que s2= 0 se s1 for igual s2> 0 se s1 for maior que s2

strnset char *strnset(char *s, int ch, size_t n);Altera os n primeiros caracters de uma string para um caractere específico (ch).

strrchr char *strrchr(const char *s, int c); Procura numa string pela última ocorrência de um caracter (c).

strrev char *strrev(char *s);Reverte uma string. strrev muda todos os caracteres numa string para a ordem reversa, com exeção do caracter nulo de terminação.

strset char *strset(char *s, int ch);Altera todos os caracteres numa string para um determinado caracter (ch).

strspn size_t strspn(const char *s1, const char *s2);Procura numa string s1 pelo primeiro segmento que difere de s2, retornando a posição onde inicia a diferença.

strstr char *strstr(const char *s1, const char *s2); Procura numa string s1 pela ocorrência de uma dada substring s2.

strupr char *strupr(char *s);Converte letras minúsculas numa string para maiúsculas.

6.4 Matrizes e vetores como parâmetros de funções

Como já se viu anteriormente, uma função em C só aceita parâmetros por valor. Não é possível, portanto, passar um vetor ou matriz (tipos de dados estruturados) como parâmetro. A solução utilizada quando da necessidade de se trabalhar com os dados contidos em um vetor não global dentro de uma função é passar um ponteiro para este vetor como parâmetro. Para trabalhar com os elementos do vetor dentro da função procede-se de forma normal já que sempre que estamos trabalhando com vetores estamos usando um ponteiro para a primeira posição da área de memória alocada para o mesmo.

Exemplo de passagem de parâmetro por valor de um vetor :

#include <stdio.h>#include <conio.h>

void imprime(int vet2[10]);

void main(){

int a, vet[10];

clrscr();for (a=0;a<10;a++)

{scanf("%d",&vet[a]);}

imprime(vet);getch();

}

void imprime(int vet2[10]){

int a;

48

Page 50: ApLP2-2006

for (a=0;a<10;a++)printf("%d ",vet2[a]);

}

Exemplo de passagem de parâmetro por referência de um vetor :

#include <stdio.h>#include <conio.h>

void imprime(int *vet2, int n);

void main(){

int a, vet[10];

clrscr();for (a=0;a<10;a++)

{scanf("%d",&vet[a]);}

imprime(vet,10);getch();

}

void imprime(int *vet2, int n){

int a;for (a=0;a<n;a++)

printf("%d ",vet2[a]);}

Exemplo de passagem de passagem de parâmetro por valor de uma matriz:

#include <stdio.h>#include <conio.h>

void imprime(int mat2[3][3]);

void main(){

int i, j, mat[3][3];

clrscr();for (i=0;i<3;i++)

for (j=0;j<3;j++)scanf("%d",&mat[i][j]);

imprime(mat);getch();

}

void imprime(int mat2[3][3]){

int a, b;for (a=0;a<3;a++)

{printf("\n");for (b=0;b<3;b++)

49

Page 51: ApLP2-2006

{printf("%d ",mat2[a][b]);}

}}

Exemplo de passagem de passagem de parâmetro por referência de uma matriz. No caso de matrizes, pelo menos uma das dimensões tem que ser conhecida.

#include <stdio.h>#include <conio.h>

void imprime(int mat2[][3], int l);

void main(){int i, j, mat[3][3];

clrscr();for (i=0;i<3;i++)

{for (j=0;j<3;j++)

{scanf("%d",&mat[i][j]);}

}imprime(mat,3);}

void imprime(int mat2[][3], int linha){int a, b;for (a=0;a<linha;a++)

{printf("\n");for (b=0;b<3;b++)

{printf("%d ",mat2[a][b]);}

}}

50

Page 52: ApLP2-2006

7. PONTEIROS

7.1 Definição de ponteiros

Ponteiro é uma variável que pode manter um endereço de uma variável.

Um modo conveniente e muito eficiente de acessar uma variável é fazer referência a ela através de uma segunda variável que contém o endereço da variável a ser acessada (ponteiro).

Por exemplo, suponha que você tenha uma variável int chamada conteúdo_da_casa e outra chamada endereço_da_casa que pode conter o endereço de uma variável do tipo int. Em C, preceder uma variável com o operador de endereços & retorna o endereço da variável em lugar do seu conteúdo. A sintaxe para atribuir o endereço da variável em lugar do seu conteúdo. A sintaxe para atribuir o endereço de uma variável a uma variável que contém o endereço é:

endereço_da_casa = &conteúdo_da_casa

Uma variável que pode manter um endereço, como endereço_da_casa, é chamada de variável ponteiro ou simplesmente um ponteiro.

Esta figura ilustra este relacionamento. A variável conteúdo_da_casa foi colocada na memória no endereço 0318. Após a execução do comando anterior, o endereço de conteúdo_da_casa foi atribuído para a variável ponteiro endereço_da_casa.

Pode-se expressar este relacionamento dizendo que endereço_da_casa aponta para conteúdo_da_casa.

Para acessar o conteúdo da célula cujo endereço está armazenado em endereço_da_casa, somente preceda a variável ponteiro com um *, como em *endereço_da_casa.

Por exemplo, se você executar os seguintes comandos:

endereço_da_casa = &conteúdo_da_casa;

*endereço_da_casa = 10;

O valor da célula (variável) chamada conteúdo da casa será 10. Podemos pensar no * como uma instrução para seguir a seta (figura) para encontrar a célula referenciada. Note que, se endereço_da_casa mantiver o endereço de conteúdo_da_casa, ambos os comandos que seguem terão o mesmo efeito, isto é, ambos armazenarão o valor 10 em conteúdo_da_casa:

conteúdo_da_casa = 10;

*endereço_da_casa = 10;51

endereço_da_casaconteúdo_da_casa

0318[0318]

Page 53: ApLP2-2006

7.1.1 Declaração de variáveis tipo ponteiro

Como em outras linguagens, C exige uma definição para cada uma das variáveis. O seguinte comando define uma variável ponteiro endereço_da_casa, que pode manter o endereço de uma variável int:

int *endereço_da_casa;

Na verdade, há duas partes separadas para esta declaração. O tipo de dado de endereço_da_casa é

int *

e o identificador para a variável é:

endereço_da_casa

O asterisco após a int significa “aponta para”, isto é, o tipo de dado int * é uma variável ponteiro que pode manter um endereço para um int.

Este é um conceito muito importante para memorizar. Em C, ao contrário de muitas outras linguagens, uma variável ponteiro guarda o endereço de um tipo de dado particular. Aqui está um exemplo:

char *endereço_para_char;int *endereço_para_int;

O tipo de dado endereço_para_char é diferente do tipo endereço_para_int. Os erros em tempo de execução e advertências durante a compilação podem ocorrer num programa que define um ponteiro para um tipo de dado e então o utiliza para apontar para algum outro tipo de dado. É também uma prática inadequada na programação definir um ponteiro de um modo e depois utilizá-lo de outro:

int *int_ptr;float valor_real = 23.45;

int_ptr = &valor_real;

Aqui, a variável int_ptr foi definida ser do tipo int *, significando que pode conter o endereço de uma célula de memória do tipo int. O terceiro comando tenta atribuir a int_ptr o endereço &valor_real de uma variável float declarada.

7.1.2 Usando variáveis tipo ponteiro

O seguinte exemplo de código trocará os conteúdos das variáveis valor1 e valor2 usando os operadores de ponteiros:

52

endereço_da_casaconteúdo_da_casa

10 0318[0318]

Page 54: ApLP2-2006

int valor1 = 10, valor2 = 20, temp;int *int_ptr;

int_ptr = &valor1;temp = *int_ptr;*int_ptr = valor2;

valor2 = temp;

A primeira linha do programa contém as definições e inicializações padrôes. O comando aloca três células para manter um único int, dando a cada célula um nome, e inicializa duas delas. É assumido que a célula chamada valor1 está localizada no endereço 1395, que a célula chamada valor2 está localizada no endereço 3321 e que a célula chamada temp está localizada no endereço 0579.

O segundo comando no programa define int_ptr como um ponteiro para um tipo de dado int. O comando aloca a célula e lhe dá um nome (colocado no endereço 1925). Lembre-se que, quando o asterisco é combinado com o tipo de dado (neste caso int), a variável contém o endereço de uma célula do mesmo tipo de dado. Como int_ptr não foi inicializada, ela não aponta para nenhuma variável int em particular. O terceiro comando atribui a int_ptr o endereço de valor1:

O próximo comando no programa:

temp = *int_ptr;

usa a expressão *int_ptr para acessar o conteúdo da célula à qual int_ptr aponta: valor1. Portanto, o valor inteiro 10 é armazenado na variável temp. Se omitíssemos o asterisco na frente de int_ptr, o comando de atribuição ilegalmente armazenaria o conteúdo de int_ptr (o endereço 1395), na célula chamada temp, que somente pode armazenar um inteiro, e não um endereço.

O quinto comando no programa:

*int_ptr = valor2;

copia o conteúdo da variável valor2 na célula apontada pelo endereço armazenado em int_ptr.

53

valor110

[1395]

valor220

[3321]

temp

[0579]

int_ptr

[1925]

valor110

[1395]

valor220

[3321]

temp

[0579]

int_ptr1395

[1925]

valor110

[1395]

valor220

[3321]

temp10

[0579]

int_ptr1395

[1925]

Page 55: ApLP2-2006

O último comando do programa simplesmente copia o conteúdo da variável inteira temp em outra variável inteira valor2.

7.1.3 Inicializando variáveis do tipo ponteiro

As variáveis do tipo ponteiro, como muitas outras variáveis em C podem ser inicializadas em sua definição. Por exemplo, os seguintes dois comandos alocam espaço para duas células valor1 e int_ptr:

int valor1; int *int_ptr = &valor1;

Observe que não foi inicializado *int_ptr (que poderia ser um inteiro qualquer), mas foi inicializado int_ptr (que precisa ser um endereço para um int). Esta inicialização na declaração deixa a interpretação do código bastante confusa, pois o exemplo acima poderia ser escrito com mais clareza, apesar de utilizar uma linha a mais assim:

int valor1;int *int_ptr;int_ptr = &valor1;

Já que as strings em C são vetores, podemos inicializar strings nos programas associando-as ao endereço do primeiro caracter, como no exemplo abaixo:

#include <stdio.h>#include <conio.h>

void main(){char *palindroma = “Socorram o Marrocos”;int indice;

for(indice=0;indice < strlen(palindroma); indice++)printf(“%c”,palindroma[indice]);

printf(“\n”);for(indice=strlen(palindroma)-1;indice>=0; indice--)

printf(“%c”,palindroma[indice]);printf(“\n”);printf(“%s”,palindroma);printf(“\n”);

54

valor120

[1395]

valor210

[3321]

temp10

[0579]

int_ptr1395

[1925]

valor120

[1395]

valor220

[3321]

temp10

[0579]

int_ptr1395

[1925]

Page 56: ApLP2-2006

printf(palindroma);}

7.1.4 Limitações no operador de endereços

O operador de endereços & não pode ser utilizado em expressões nos seguintes casos:

a) Não pode ser utilizado com constantes:

endereco_variavel = &23;

b) Não pode ser utilizado com expressões envolvendo operadores como + / * -:

endereco_variavel = &(valor1 + 10);

c) Não pode ser utilizado precedendo variáveis declaradas como register:

register int reg1; endereco_variavel = &reg1;

7.1.5 Ponteiros para matrizes

Ponteiros e matrizes estão intimamente relacionados. O nome de uma matriz é uma constante cujo valor representa o endereço do primeiro elemento da matriz.

Por esta razão, um comando de atribuição ou qualquer outro comando não pode modificar o valor do nome de uma matriz.

Com as declarações:

float classe[10];float *float_ptr;

o nome da matriz classe é uma constante cujo valor é o endereço do primeiro elemento da matriz de 10 floats. O comando a seguir atribui o endereço do primeiro elemento da matriz à variável ponteiro float_ptr:

float_ptr = classe

Um comando equivalente é:

float_ptr = &classe[0];

Entretanto, como float_ptr contém o endereço de um float, os seguintes comandos são ilegais pois tentam atribuir um valor para a constante classe ou seu equivalente &classe[0]:

classe = float_ptr;&classe[0] = float_ptr;

55

Page 57: ApLP2-2006

7.1.6 Ponteiros para ponteiros

Em C podemos definir variáveis ponteiro que apontam para outra variável ponteiro, que, por sua vez, aponta para os dados.

Isto é necessário para programação em ambientes operacionais multitarefa, como Windows, Windows NT e OS/2 que foram projetados para maximizar o uso da memória. Para compactar o uso da memória, o sistema operacional precisa ser capaz de mover objetos na memória quando necessário.

Se seu programa aponta diretamente para a célula de memória física onde o objeto está armazenado, e o sistema operacional o mover, haverá desastre. Em vez disso, sua aplicação aponta para o endereço da célula de memória que não será modificada enquanto o programa estiver sendo executado (um endereço virtual), e a célula de memória endereço_virtual mantém o endereço_físico_atual do objeto de dados, atualizada automaticamente pelo sistema operacional.

Para definir um ponteiro para um ponteiro em C, simplesmente aumenta-se o número de asteriscos que precedem o identificador como por exemplo:

char **char_ptr;

Neste exemplo, a variável char_ptr é definida como um ponteiro para um ponteiro que aponta para um tipo de dados char.

Cada asterisco é lido como “ponteiro para”. O número de ponteiros que precisa ser seguido para acessar o item de dados, ou o número de asteriscos que deve ser colocado na variável para referenciar o valor ao qual ela aponta, é chamado de nível de indireção da variável ponteiro. O nível de indireção de um ponteiro determina quanta desreferenciação deve ser feita para acessar o tipo de dados na definição.

Observe o exemplo:

int int_dados = 5;int *int_ptr1;int **int_ptr2;int ***int_ptr3;int_ptr1 = &int_dados;int_ptr2 = &int_ptr1;int_ptr3 = &int_ptr2;

7.1.7 Aritmética com ponteiros

Em C também é possíver a realização de aritmética com ponteiros, fazendo-se adição e subtração com variáveis do tipo ponteiro.

Ex.:

int *ptr_int;

56

int_dados5

[1112]

int_ptr11112

[2368]

int_ptr22368

[3219]

int_ptr33219

Page 58: ApLP2-2006

float *ptr_float;

int um_inteiro;float um_float;

ptr_int = &um_inteiro;ptr_float = &um_float;

ptr_int++;ptr_float++;

Observe apenas que se o valor de ptr_int antes do incremento fosse 2000, após o incremento esse valor passou para 2002, pois um incremento de int corresponde a 2 bytes, da mesma forma que ptr_float passaria de 3000 para 3004.

7.2 Ponteiros para funções

Em C é possível que uma função seja ativada através de seu endereço de colocação em memória, ao invés de seu nome. Desta forma, pode-se declarar um ponteiro para uma função (um variável que armazena o endereço de uma função) e evocá-la através desse ponteiro.

Ex.:

int (*ptr_func)();

Neste caso, ptr_func é um ponteiro para uma função que retorna inteiro e não possui parâmetros. Se, por exemplo, o programa contiver uma função chamada calcula:

int calcula(void);

ptr_func irá armazenar o endereço de calcula se fizermos:

ptr_func = calcula; /*observe que nao é calcula() */

A função é ativada através do ponteiro quando se escreve:

(*ptr_func)();

Outros exemplos:

void (*func)(int);

func é um ponteiro para uma função void que possui um inteiro como parâmetro;

float (*ptf)(int,double);

ptf é um ponteiro para uma função que retorna float e possui como parâmetros um int e um double.

57

Page 59: ApLP2-2006

Os ponteiros para funções têm importantes usos. Por exemplo, considere a função qsort (ordena um vetor), que tem como um de seus parâmetros um ponteiro para uma função. Nós não podemos passar uma função por valor, isto é, passar o próprio código, mas podemos passar um ponteiro para o código, ou seja, um ponteiro para a função.

Exemplos:

#include <stdio.h>int soma(int a, int b);int sob(int a, int b);

void main(){int (*pf)(int,int); /* ponteiro para função /*int i, a, b, r;

for(i=0;i<4;i++){pf=(i%2==0)?soma:sub;printf(“\nDigite um valor: ”);scanf(“%d”,&a);printf(“\nDigite outro valor: ”);scanf(“%d”,&b);r=(*pf)(a,b);printf(“%d\n”, r);}

}

int soma(int a, int b){printf(“A soma é: \n”);return(a+b);}

int sub(int a, int b);{printf(“A subtração é: \n”);return(a-b);}

Outro caso típico de aplicação são os vetores de ponteiros para funções:

#include <stdio.h>

void zero();void um();void dois();

void main(){void (*vet[3])(); /* vetor de ponteiros para funções */int op;

vet[0] = zero;vet[1] = um;vet[2] = dois;

58

Page 60: ApLP2-2006

do{printf(“Digite um número entre 0 e 2: ”);scanf(“%d”,&op);(*vet[op])();}

while (op<0 || op>2);}

void zero(){printf(“Zero!\n”);}

void um(){printf(“Um!\n”);}

void dois(){printf(“Dois!\n”);}

7.3 Ponteiros em Pascal

Em Pascal temos praticamente todas as funcionalidades dos ponteiros de C e C++, com pequenas diferenças na sintaxe. A declaração de um ponteiro em Pascal é:

nome_do_ponteiro : ^tipo_de_dado ;

Exemplo:

px : ^integer; {ponteiro para um inteiro}z : ^real; {ponteiro para um real}mm : ^char; {ponteiro para um char}

Para associar um endereço de uma variável a um ponteiro usa-se o operador @

px := @x;

Para mostrar o valor apontado pelo ponteiro usa-se o nome do ponteiro seguido de um ^

writeln( px^ );

Exemplo:

uses crt;varx,y: integer;px: ^integer;beginclrscr;write('x: ');readln(x);write('y: ');

59

Page 61: ApLP2-2006

readln(y);px := @x;writeln('Valor apontado por px: ', px^);px := @y;writeln('Valor apontado por px: ', px^);writeln('X: ',x);writeln('Y: ',y);readkey;end.

Para usar um ponteiro para vetor ou para uma matriz é necessário primeiro criar um tipo para o qual o ponteiro possa apontar e declarar uma variável ponteiro que aponte para o tipo criado. Podemos observar que uma matriz nada mais é do que o endereço do primeiro elemento, portanto o tipo criado não precisa ter o tamanho da matriz a que se quer associar ao ponteiro, mas deve ter as mesmas dimensões da matriz:

typey= array[1..1,1..1] of integer;

varpx : ^y;

O ponteiro pode então receber o endereço de uma matriz do mesmo tipo para o qual ele aponta

px := @x;

A partir dessa associação, pode-se acessar os elementos da matriz através do nome seguido dos índices ou do ponteiro seguido de ^ e dos índices

writeln( x[8,5] );é o mesmo que writeln( px^[8,5] );

Exemplo:

uses crt;

typey= array[1..1,1..1] of integer;

varx: Array[1..10,1..10] of integer;px: ^y;i, j: integer;

beginclrscr;for i:= 1 to 10 do begin for j:= 1 to 10 do begin x[i,j]:=i*10+j; end; end;for i:= 1 to 10 do

60

Page 62: ApLP2-2006

begin for j:= 1 to 10 do begin write(x[i,j] :5); end; writeln; end;writeln(‘É o mesmo que: ’);px := @x;for i:= 1 to 10 do begin for j:= 1 to 10 do begin write(px^[i,j] :5); end; writeln; end;readkey;end.

Em Pascal também pode-se utilizar aritmética com ponteiro, de modo que incrementando-os em uma unidade eles são incrementados em tantos bytes quanto o tipo para quem eles apontam. Outra forma de mostrarmos uma matriz usando artimética com ponteiros é:

uses crt;varx: Array[1..10,1..10] of integer;px: ^integer;i, j: integer;beginclrscr;for i:= 1 to 10 do begin for j:= 1 to 10 do begin x[i,j]:=i*10+j; end; end;px := @x[1,1];for i:= 1 to 10 do begin for j:= 1 to 10 do begin write(px^ :5); px^:=px^+1; end; writeln; end;readkey;end.

61

Page 63: ApLP2-2006

8. ESTRUTURAS, UNIÕES E ITENS DIVERSOS

8.1 Estruturas

Nós podemos pensar em estruturas como sendo uma matriz ou um vetor de itens intimamente relacionados. Entretanto, ao contrário da matriz ou vetor, uma estrutura permite que se armazene diferentes tipos de dados. O conceito de estrutura de dados é comum no dia-a-dia. Um arquivo de fichas com informações sobre o cliente é uma estrutura de itens relacionados.

Nós podemos criar uma estrutura usando a palavra-chave struct e a seguinte sintaxe:

struct tipo

{

tipo var1;

tipo var2;

...

tipo varn;

} var_tipo,...;

Por exemplo se queremos criar uma estrutura (tipo definido pelo usuário) cadastro e definirmos uma variável cliente que é do tipo (estrutura) cadastro:

#include <stdio.h>#include <conio.h>

struct cadastro{char nome[30];char endereco[50];char cidade[20];} cliente;

void main(){printf(“Nome: ”);gets(cliente.nome);printf(“Endereço: ”);gets(cliente.endereco);printf(“Cidade: ”);gets(cliente.cidade);clrscr();printf(“%s mora na rua %s, na cidade de %s”, cliente.nome,

cliente.endereco,cliente.cidade);}

62

Page 64: ApLP2-2006

8.1.1 Passando uma estrutura para uma função

Podem ocorrer situações que teremos que passar informações de estruturas para funções. Quando uma estrutura é passada para uma função, as informações da estrutura são passadas por valor, e assim a função não altera a estrutura original. Por exemplo se a impressão dos dados do exemplo anterior fosse passada para uma função:

#include <stdio.h>#include <conio.h>

struct cadastro{char nome[30];char endereco[50];char cidade[20];};

void imprime(struct cadastro pessoas);

void main(){struct cadastro cliente

printf(“Nome: ”);gets(cliente.nome);printf(“Endereço: ”);gets(cliente.endereco);printf(“Cidade: ”);gets(cliente.cidade);imprime(cliente);}

void imprime(struct cadastro pessoas){clrscr();printf(“%s mora na rua %s, na cidade de %s”, pessoas.nome,

pessoas.endereco, pessoas.cidade);}

8.1.2 Matriz de Estruturas

Podemos criar uma matriz de estruturas, o que é semelhante a um fichário que contém diversas fichas de clientes. Por exemplo:

#include <stdio.h>#include <conio.h>

struct cadastro{char nome[30];char endereco[50];char cidade[20];} cliente[5];

void main(){

63

Page 65: ApLP2-2006

int i;

for(i=0;i<5;i++){printf(“Nome: ”);gets(cliente[i].nome);printf(“Endereço: ”);gets(cliente[i].endereco);printf(“Cidade: ”);gets(cliente[i].cidade);}

clrscr();for(i=0;i<5;i++)

{printf(“%s mora na rua %s, na cidade de %s \n”, cliente[i].nome,

cliente[i].endereco, cliente[i].cidade);}

}

8.1.3 Estruturas dentro de estruturas

Podemos aninhar estruturas, isto é, tornar uma estrutura parte de uma segunda estrutura. Por exemplo:

#include <stdio.h>#include <conio.h>

struct data{int dia;int mes;int ano;};

struct cadastro{char nome[30];char endereco[50];char cidade[20];struct data dnasc;};

void main(){int i;cadastro cliente[5];

for(i=0;i<5;i++){printf("Nome: ");gets(cliente[i].nome);printf("Endereço: ");gets(cliente[i].endereco);printf("Cidade: ");gets(cliente[i].cidade);fflush(stdin);printf("Data de Nascimento: ");

64

Page 66: ApLP2-2006

scanf("%d%d%d", &cliente[i].dnasc.dia, &cliente[i].dnasc.mes, &cliente[i].dnasc.ano);

fflush(stdin);}

clrscr();for(i=0;i<5;i++)

{printf("%s mora na rua %s, na cidade de %s\n", cliente[i].nome,

cliente[i].endereco,cliente[i].cidade);printf("E nasceu no dia %d/%d/%d\n", cliente[i].dnasc.dia,

cliente[i].dnasc.mes, cliente[i].dnasc.ano);}

}

8.1.4 Ponteiros para estruturas

A utilização de ponteiros para estruturas é uma técnica tão comum que um novo operador, conhecido cmo operador seta pelos programadores de C, foi desenvolvido, e tem este aspecto: -> . Em outras palavras, se definirmos uma estrutura denominada meus_dados que seja semelhante a:

struct grande_estrutura_dados{ int chave; int grande_vetor[20];} meus_dados;

Então poderemos declarar um ponteiro denominado meu_ponteiro para meus_dados como este:

struct grande_estrutura_dados *meu_ponteiro;

E atribuir um valor a ele desta forma:

meu_ponteiro = &meus_dados;

A partir de agora, podemos nos referir aos campos em meus_dados como meus_dados.chave, como:

meu_ponteiro->chave = 5;

É o mesmo que o comando a seguir:

meus_dados.chave = 5;

Em outras palavras, meu_ponteiro é um ponteiro para uma estrutura; para alcançar um campo na estrutura para a qual ele aponta, utilize o operador seta, ->. Essa é a razão pela qual o operador -> foi desenvolvido: para permitir escolher campos isolados da estrutura que está sendo apontada. Foram incluídos os operadores * e & expressamente para aqueles casos em que apontamos para uma estrutura, porque & ou * sozinhos não podem acessar elementos. Ou seja, não existe algo como *meu_ponteiro.chave; temos que utilizar em seu lugar meu_ponteiro->chave.

65

Page 67: ApLP2-2006

Uma estrutura somente pode ser passada para uma função por referência, através de um ponteiro para a estrutura. Por exemplo:

#include <stdio.h>#include <conio.h>

struct produto{int codigo;char descr[80];float preco;}p1, p2;

void leprod(produto *ptr);void imprimeprod(produto *ptr);

void main(){leprod(&p1);leprod(&p2);clrscr();imprimeprod(&p1);imprimeprod(&p2);getch();}

void leprod(produto *ptr){int aux;float aux2;fflush(stdin);printf("Codigo: ");scanf("%d",&aux);ptr->codigo = aux;fflush(stdin);printf("Descricao: ");gets(ptr->descr);printf("Preco: ");scanf("%f",&aux2);ptr->preco = aux2;}

void imprimeprod(produto *ptr){printf("%d\n",ptr->codigo);puts(ptr->descr);printf("%0.2f\n",ptr->preco);}

8.1.5 Estruturas em Pascal e Delphi

A declaração RECORD permite-nos definir um registro:

<identificador> = RECORD<campo1> : tipo;<campo2> : tipo;. . .

66

Page 68: ApLP2-2006

<campon> : tipo; END;

REGISTRO é um grupo de informações relativas a uma mesma entidade. Estas informações podem ter características diferentes, como em um R.G., onde temos diversos campos com nome, nome do pai, nome da mãe, número do registro, etc.

O registro tem uma particularidade em relação a uma matriz, enquanto em uma matriz podemos ter vários elementos de um único tipo, no registro podemos ter elementos com tipos diferentes. A definição de um registro no Turbo Pascal só pode ser feita na área de tipos (TYPE) e assim sendo, quando definimos um registro, na verdade, estamos criando um tipo novo. Para podermos utilizar este tipo, temos que declará-lo na área de variáveis (VAR), já a manipulação dos campos de um arquivo deve ser feita através da referência do nome do registro e o nome do campo unidos por um ponto (.).

Exemplos :TYPEregistro = RECORD

nome : STRING[30]; ende : STRING[25]; fone : STRING[8]; idade : BYTE;

END;

tela = RECORDatributo : BYTE;caracter : CHAR;

END;

Exemplo de referência de um campo do registro :

PROGRAM teste_reg;

TYPE

registro = RECORD nome :STRING[30]; ende :STRING[25]; fone :STRING[8]; idade :BYTE;

END; VAR

reg : registro;

BEGINreg.nome := ‘Roberto’;reg.ende := ‘Rua Anônima, 0’;reg.fone := ‘999-9999’;reg.idade:= 30;writeln(‘Nome: ’, reg.nome);writeln(‘Endereço: ’, reg.ende);writeln(‘Fone: ’, reg.fone);

67

Page 69: ApLP2-2006

writeln(‘Idade: ’, reg.idade);write(‘Nome: ’);readln(reg.nome);write(‘Endereço: ’readln(reg.ende);write(‘Fone: ’readln(reg.fone);write(‘Idade: ’readln(reg.idade);writeln(‘Nome: ’, reg.nome);writeln(‘Endereço: ’, reg.ende);writeln(‘Fone: ’, reg.fone);writeln(‘Idade: ’, reg.idade);END.

Pode-se também armazenar os registros em memória, através do uso de vetores ou matrizes de estrutras.

Exemplo:Program ExemploRegistroSeletivo;uses crt;type

cadastro = record codigo: integer; nome: string[30]; rg: string[15]; end;

varcad: Array [1..10] of cadastro;i: integer;

beginclrscr;for i:= 1 to 10 do begin write('Codigo: '); readln(cad[i].codigo); write('Nome: '); readln(cad[i].nome); write('RG: '); readln(cad[i].rg); end;clrscr;for i:= 1 to 10 do begin writeln(cad[i].codigo, ' - ', cad[i].nome, ' - ', cad[i].rg); end;readkey;

end.

68

Page 70: ApLP2-2006

8.2 Uniões

Uma União é um tipo de dados muito similar à uma estrutura, com a diferença de que todos os membros de uma união compartilham a mesma área de armazenamento, enquanto cada membro de uma estrutura possui a sua própria área. As uniões são úteis para economizar memória, em situações nas quais os campos de uma estrutura são mutuamente exclusivos.

Ex.:

union algum{int i;char c;} u;

Neste caso, a variável “u” somente poderá conter o valor do campo “i” ou do campo “c”, mas não de ambos. O compilador reservará área suficiente para o maior tipo contido na união.

Em Pascal e Delphi, podemos ter uma estrutura de registro seletivo :

Exemplo:Program ExemploRegistroSeletivo;uses crt;type

Classe = (Num, Str);

uniao = record Nome: string[30]; case campo: Classe of Num: (N: real); Str: (S: string); end;

varun: uniao;op: char;

beginclrscr;write('Nome: ');readln(un.nome);writeln('O que voce quer armazenar: [N] Numero - [S] - String?');op:=readkey;if upcase(op)='N' then begin write('Digite um numero: '); readln(un.N); writeln(un.nome); writeln(un.N:0:6); endelse begin write('Digite uma string: '); readln(un.S); writeln(un.nome); writeln(un.S);

69

Page 71: ApLP2-2006

end;readkey;end.

Neste tipo de registro, temos a possibilidade de variar a estrutura. dependendo da condição encontrada no decorrer do programa para um campo-sinal previamente declarado como tipo escalar, esta estrutura de seleção é chamada de união discriminada, cabendo desta forma ao programador manter válida.

8.3 Itens diversos

8.3.1 typedef

Podemos associar novos tipos de dados com os tipos de dados existentes, usando typedef. Por exemplo, podemos definir um tipo de dado chamado real que é do tipo float:

#include <stdio.h>

typedef float real;

void main(){real a, divisao;int b;a = 7;b = 4;divisao = a/b;printf(“%f”,divisao);}

8.3.2 enum

O tipo de dado enum permite que criemos um tipo de dado com uma escolha de itens. enum é útil quando a informação pode ser melhor representada por uma lista de valores inteiros,

70

Page 72: ApLP2-2006

9. ALOCAÇÃO DINÂMICA DE MEMÓRIA

Quando um programa em C ou Pascal é compilado, a memória do computador é dividida em quatro zonas que contêm o código do programa, todos os dados globais, a pilha, e o heap. O heap é a área de memória livre (algumas vezes chamada de armazém livre) que é manipulada com as funções de alocação dinâmica malloc e free (C) e Getmem e Freemem (Pascal).

Quando malloc (C) ou Getmem (Pascal) é chamada, ela aloca um bloco contíguo de armazenagem para o objeto especificado e então retorna um ponteiro para o início do bloco. A função free (C) ou Freemem (Pascal) retorna a memória alocada previamente para o heap, permitindo que a porção da memória seja realocada.

O argumento passado para malloc é um inteiro não-sinalizado que representa o número necessário de bytes de armazenagem. Se houver memória disponível, malloc retornará void * que pode ser convertido para o tipo desejado de ponteiro. Um ponteiro void significa um ponteiro de tipo desconhecido ou genérico. Um ponteiro void não pode ser usado para referenciar qualquer coisa (pois ele não aponta para qualquer tipo específico de dado), mas pode conter um ponteiro de qualquer outro tipo. Portanto podemos converter qualquer ponteiro num ponteiro void e reconverter sem qualquer perda de informação.

O seguinte exemplo aloca armazenagem para um número variável de valores float:

#include <stdio.h>#include <conio.h>#include <stdlib.h>

float *fpt;int i, qtd;

void main(){clrscr();printf("Quantidade de valores: ");scanf("%d",&qtd);fpt = (float *) malloc( sizeof(float) * qtd);for (i=0;i<qtd;i++)

{printf("%d§ valor: ",i+1);scanf("%f",&fpt[i]);}

for (i=0;i<qtd;i++){printf("%d§ valor: %6.2f\n",i+1,fpt[i]);}

getch();free(fpt);}

A função malloc obtém armazenagem suficiente para tantas vezes o tamanho de um float quanto for solicitado. Cada bloco de armazenagem requisitado é inteiramnte separado e distinto de todos os outros. Não podemos fazer suposições sobre onde os blocos serão alocados. Os blocos são tipicamente identificados com algum tipo de informação que permite que o sistema

71

Page 73: ApLP2-2006

operacional gerencie sua localização e tamanho. Quando o bloco não é mais necessário, podemos retorná-lo para o sistema operacional por meio do seguinte comando:

free( < nome_ponteiro > )

Em Pascal as funções são semelhantes no modo de operar mas um pouco diferentes na sintaxe. O procedimento Getmem recebe dois parâmetros, sendo o primeiro o nome do ponteiro e o segundo a quantidade de bytes a serem alocados. Uma diferença a ser observada é que o procedimento de liberação de memória Freemem precisa também da informação da quantidade de bytes a serem liberados.

O exemplo abaixo em Pascal é semelhante ao anterior escrito em C:

uses crt;type vetor = Array [1..1] of real;varfpt: ^vetor;i, qtd: integer;

beginclrscr;write('Quantidade de valores: ');readln (qtd);GetMem(fpt, sizeof(real) * qtd);for i:= 1 to qtd do begin write(i,'§ valor: '); readln(fpt^[i]); end;for i:= 1 to qtd do begin writeln(i,'§ valor: ', fpt^[i]:6:2); end;readkey;FreeMem(fpt,sizeof(integer)*qtd);end.

Quando precisamos de variáveis com um tamanho desconhecido na compilação, devemos usar alocação dinamica de memória, no heap. Devemos porém tomar o cuidado de liberar a memória quando não precisamos mais da variável, pois o compilador só devolve automaticamente a memória ocupada pelas variáveis locais. Se não liberarmos a memória corretamente, o programa pode vir a travar.

A grande vantagem da utilização de alocação dinâmica é que permite-se criar estruturas semelhantes a matrizes com dimensões desconhecidas no momento da compilação. Devido a uma limitação da linguagem Pascal, uma matriz ou vetor não pode ocupar mais do que 64 Kbytes de memória, portanto, quando necessitamos de uma matriz ou vetor com mais de 64 Kbytes devemos usar alocação dinâmica de memória.

Pode-se inclusive criar matrizes com número variado de colunas para cada linha, como por exemplo:

72

Page 74: ApLP2-2006

#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <alloc.h>

int **matriz;int *colunas;unsigned long lin, col, i, j;

void main(){clrscr();printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft());printf("Linhas: ");scanf("%d",&lin);matriz=(int **) malloc(sizeof(int *) * lin);colunas=(int *) malloc(sizeof(int) * lin);printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft());if (matriz==NULL)

{printf("Nao foi possivel alocar memoria\n");exit(1);}

for(i=0;i<lin;i++){printf("Colunas na linha %d: ",i);scanf("%d",&col);matriz[i]=(int *) malloc(sizeof(int)*col);

if(matriz[i]==NULL){printf("Nao foi possivel alocar memoria\n");exit(1);}

colunas[i]=col;printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft());}

printf("Memoria livre: %lu bytes\n", (unsigned long) coreleft());for(i=0;i<lin;i++)

{printf("Linha %d:\n",i);for(j=0;j<colunas[i];j++)

{printf("%d§ Valor: ",j);scanf("%d",&matriz[i][j]);}

}for(i=0;i<lin;i++)

{printf("\n");for(j=0;j<colunas[i];j++)

{printf("%5d",matriz[i][j]);}

}for(i=0;i<lin;i++)

{free(matriz[i]);}

free(matriz);free(colunas);printf("\nMemoria livre: %lu bytes\n", (unsigned long) coreleft());

73

Page 75: ApLP2-2006

getch();}

9.1 Lista encadeada com alocação dinâmica de memória:

Uma lista encadeada é a forma ideal de armazenamento de dados quando não se sabe antecipadamente quantos itens de dados terão de ser armazenados. Ela funciona ssim: para cada item, existe também um ponteiro direcionado para o item de dados seguinte. A qualquer momento, pode-se acrescenta outro item de dados à lista, contanto que o que o último ponteiro seja atualizado a fim de apontar para o novo item de dados. Partindo-se do início da lista, é possível percorrê-la utilizando-se o ponterio de cada item, que aponta para o próximo item de dados. O útlimo ponteiro da lista é geralmetne um ponteiro NULL, portando, sabemos que estamos no final da lista quando encontramos um ponteiro NULL. É preciso também termos 3 ponteiros auxiliares, para a alocação dinâmica da memória: um ponteiro que aponta para o primeiro elemento, para saber onde inicia a lista, um ponteiro que aponta para o último elemento da lista, para colocarmos o valor do novo ponteiro quando é inserido um elemento sem ter que percorrer a lista inteira, e um ponteiro auxiliar, que aponta para a nova área de memória alocada.

Esquematicamente, uma lista encadeada é semelhante a:

Podemos observar no exemplo a seguir, uma lista encadeada com alocação dinâmica de memória.

#include <stdio.h>#include <conio.h>#include <stdlib.h>

typedef struct produto{int codigo;char descr[40];float preco;struct produto *prox;}produto;

produto *prim, *ult, *aux;int cod;

void ledados(produto *p, int c);void imprime();void liberamem();

void main(){

74

ponteirodados

ponteirodados

ponteirodados

NULLdados

Page 76: ApLP2-2006

prim=ult=NULL;while(1)

{clrscr();printf("Codigo: ");scanf("%d",&cod);if (cod<0) break;aux=(produto *) malloc(sizeof(produto));if (aux==NULL)

{printf("Sem memoria");exit(1);}

ledados(aux,cod);if(prim==NULL)

{prim=aux;ult=prim;}

else{ult->prox=aux;ult=aux;}

}imprime();getch();liberamem();}

void ledados(produto *p, int c){float precoaux;clrscr();p->codigo=c;fflush(stdin);printf("Codigo: %d\n",p->codigo);printf("Descricao: ");gets(p->descr);fflush(stdin);printf("Preco: ");scanf("%f",&precoaux);p->preco=precoaux;p->prox=NULL;}

void imprime(){aux=prim;while(aux!=NULL)

{printf("%d - %s - %f\n",aux->codigo, aux->descr, aux->preco);aux = aux->prox;}

}

void liberamem(){aux=prim;while(aux!=NULL)

{

75

Page 77: ApLP2-2006

free(aux);aux = aux->prox;}

}

O exemplo abaixo é a implementação de uma lista encadeada com alocação de memória simples, sem ordenação sendo toda nova informação incluída no final da lista:

#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <alloc.h>#include <ctype.h>

void liberar();void listar();void insere(unsigned char infoaux);

struct lista{unsigned char info;struct lista *elo;};

struct lista *pri, *aux, *ult, *pen;unsigned char infoaux;

void main(){clrscr();pri=NULL;ult=NULL;do

{gotoxy(1,1);printf("Digite uma Letra: ");infoaux=toupper(getch());if ((infoaux>=65)&&(infoaux<=90)) insere(infoaux);listar();}

while ((infoaux>=65)&&(infoaux<=90));getch();liberar();}

void listar(){struct lista *lult;lult=pri;gotoxy(1,10);while(lult!=NULL)

{printf("%c ",lult->info);lult=lult->elo;}

}

void liberar()

76

Page 78: ApLP2-2006

{struct lista *lult;lult=pri;gotoxy(1,10);while(lult!=NULL)

{aux=lult;lult=lult->elo;free(aux);}

}

void insere(unsigned char infoaux){aux=(struct lista *) malloc(sizeof(struct lista));if (aux==NULL)

{printf("Nao foi possivel alocar memoria\n");exit(1);}

if (pri==NULL){aux->info=infoaux;aux->elo=NULL;pri=aux;ult=pri;}

else{aux->info=infoaux;aux->elo=NULL;ult->elo=aux;ult=aux;}

}

O exemplo abaixo é a implementação de uma lista encadeada com alocação de memória com ordenação das informações, ou seja, as informações são inseridas na lista de forma que ela sempre está com os dados em ordem crescente:

#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <alloc.h>#include <ctype.h>

void liberar();void listar();void insere(unsigned char infoaux);

struct lista{unsigned char info;struct lista *elo;};

struct lista *pri, *aux, *ult, *pen;

77

Page 79: ApLP2-2006

unsigned char infoaux;

void main(){clrscr();pri=NULL;do

{gotoxy(1,1);printf("Digite uma Letra: ");infoaux=toupper(getch());if ((infoaux>=65)&&(infoaux<=90)) insere(infoaux);listar();}

while ((infoaux>=65)&&(infoaux<=90));getch();liberar();}

void listar(){struct lista *lult;lult=pri;gotoxy(1,10);while(lult!=NULL)

{printf("%c ",lult->info);lult=lult->elo;}

}

void liberar(){struct lista *lult;lult=pri;gotoxy(1,10);while(lult!=NULL)

{aux=lult;lult=lult->elo;free(aux);}

}

void insere(unsigned char infoaux){int inseri;

aux=(struct lista *) malloc(sizeof(struct lista));if (aux==NULL)

{printf("Nao foi possivel alocar memoria\n");exit(1);}

if (pri==NULL){aux->info=infoaux;aux->elo=NULL;pri=aux;

78

Page 80: ApLP2-2006

}else

{if(pri->info > infoaux)

{aux->info=infoaux;aux->elo=pri;pri=aux;}

else{if(pri->elo == NULL)

{aux->info=infoaux;aux->elo=NULL;pri->elo=aux;}

else{inseri=0;pen=pri;ult=pri;while(inseri == 0 && ult->elo != NULL)

{if (ult->elo != NULL)

{pen=ult;ult=ult->elo;}

if (ult->info > infoaux){aux->info=infoaux;aux->elo=ult;pen->elo=aux;inseri=1;}

}if (inseri==0)

{aux->info=infoaux;aux->elo =NULL;ult->elo =aux;}

} }

}}

79

Page 81: ApLP2-2006

10. ARQUIVOS

Para começarmos a manipular arquivos, necessitamos lembrar alguns conceitos básicos a respeito dos mesmos. Quando pensamos em arquivos, a primeira coisa que nos vem à memória é a idéia de um arquivo físico igual aos arquivos encontrados nos escritórios. De forma geral um arquivo serve para armazenar informações através de fichas. Em informática, estes conceitos são perfeitamente válidos, pois para o armazenamento de informações em um arquivo, temos que dar uma forma ao arquivo e dar forma às informações que estarão contidas nele.

10.1 Arquivo tipado em Delphi e Pascal

10.1.1 Declaração de arquivos

A primeira preocupação é com relação ao conteúdo de um arquivo. Em um arquivo físico, este conteúdo é feito normalmente através de fichas que têm informações de uma mesma forma. Para nós, esta ficha é um registro e como já vimos anteriormente, o registro é uma estrutura que deve ser definido, na área de tipos, porém só a definição de um registro não implica na formação de um arquivo. Para formá-lo devemos ter um conjunto destas fichas, no nosso caso, devemos declarar uma variável do tipo arquivo e esta variável pode ser declarada de duas formas básicas :

FILE

Esta declaração define uma variável como sendo arquivo. Sua sintaxe :

identificador : FILE OF tipo;

ou

identificador : FILE;

Vejamos um exemplo de definição de um tipo arquivo:

TYPEregistro = RECORD

nome : STRING[30];cep : LONGINT;rg : STRING[8];cic : STRING[11];

END;

VARarquivo_pessoal : FILE OF registro;arquivo_numerico : FILE OF BYTE; arquivo_sem_tipo : FILE;

Porém, somente a declaração de uma variável do tipo arquivo não quer dizer que já podemos manipular o arquivo, assim como no arquivo físico, aquele de aço, aqui teremos tarefas

80

Page 82: ApLP2-2006

semelhantes, como por exemplo abrir uma gaveta, retirar ou colocar uma ficha, fechar uma gaveta, identificar o arquivo através de uma etiqueta qualquer, organizar as informações, etc.

Veremos então os comandos para fazermos tais tarefas:

O primeiro comando que veremos é o que nos permite associar a variável do tipo arquivo ao nome externo deste arquivo, ou seja, o nome local que este deve estar.

ASSIGN

Este procedimento permite que associemos o nome externo de um arquivo a uma variável do tipo arquivo. O nome externo é aquele utilizado pelo sistema operacional, portanto deve ser válido para o mesmo. São possíveis todas as formas de referência usadas no PATH, e quando a unidade ou subdiretórios forem omitidos, estes assumirão o default. Após o uso do ASSIGN, este continuará valendo até que seja dado um novo ASSIGN. O tamanho máximo do nome do arquivo é de 79 bytes. Este procedimento nunca deve ser usado em um arquivo já aberto, pois caso o nome do arquivo tenha tamanho zero, o arquivo será associado ao dispositivo padrão de saida. Sua sintaxe:

ASSIGN(VAR <arq>, <nomearq> : STRING);

arq, deve ser uma variável do tipo arquivo. por exemplo:

Exemplo:PROGRAM teste_assign;VARarq1, arq2 : FILE OF BYTE;

BEGINASSIGN(arq2,’teste.dat’);ASSIGN(arq1,''); {o nome externo do arquivo omitido}END. {determina que o dispositivo de saida } {será o standart }

10.1.2 Funções de abertura e fechamento de arquivos

Com a definição de uma variável do tipo arquivo e a sua associação a um nome de arquivo externo, já temos um bom caminho andado, porém ainda nos faltam alguns comandos básicos para, efetivamente, podermos manipular os arquivos. Voltando à analogia com um arquivo de aço, veremos que a primeira coisa que faremos para dar início a manipulação deste arquivo é abri-lo. Pois bem, no nosso arquivo, também deveremos ter esta atividade, ou seja, abrir o arquivo e para isto temos dois comandos básicos:

RESET

Este procedimento permite-nos abrir um arquivo já existente. No caso do uso deste, para a tentativa de abertura de um arquivo não existente, ocorrerá um erro de execução. Para que o

81

Page 83: ApLP2-2006

procedimento tenha sucesso é necessário que antes de executá-lo, tenhamos utilizado o procedimento ASSIGN. Sua sintaxe :

RESET(VAR <arquivo> [:FILE; <tamanho> : WORD]);

Exemplo:PROGRAM teste_reset;Uses CRT;VARarquivo : FILE OF BYTE;nomearq : STRING[67];BEGINWRITE('Entre com o nome do arquivo que quer abrir ') ;READLN(nomearq);ASSIGN(arquivo,nomearq);RESET(arquivo);END.

Este comando apenas permite-nos abrir um arquivo já existente. para que possamos abrir um arquivo novo, temos um outro comando:

REWRITE

Este comando permite criar e abrir um novo arquivo. Caso o arquivo já exista, terá seu conteúdo eliminado e será gerado um novo arquivo. Antes de executarmos este procedimento, devemos usar o ASSIGN, e caso a variável do tipo arquivo não seja tipada, o tamanho de cada registro será de 128 bytes, isto se não for especificado o tamanho do registro. Sua sintaxe:

REWRITE(VAR <arquivo> [: FILE ; <tamanho> : WORD]);

Vejamos um exemplo, usando o comando REWRITE :

PROGRAM teste_rewrite;Uses Crt;VARarquivo : FILE OF BYTE;nomearq: STRING[67];

BEGINWRITE('Entre com o nome do arquivo que quer abrir ');READLN(nomearq);ASSIGN(arquivo,nomearq);REWRITE(arquivo);END.

Em ambos os exemplos anteriores, vemos uma deficiência. Enquanto um comando apenas nos permite a abertura de arquivos já existentes, o outro apenas abre arquivos novos ou destrói um possível conteúdo anterior.

Para resolver esse problema podemos usar as diretivas de compilação para checagem de erros de entrada/saída {$I }. Esta diretiva retorna um código de erro em uma função do Turbo

82

Page 84: ApLP2-2006

Pascal chamada IORESULT. Para não abortar um programa quando ocorre um erro de I/O, usa-se a diretiva {$I–}. Para voltar ao padrão, usa-se a diretiva {$I+}.

Por exemplo:

PROGRAM teste_rewrite_ou_close;Uses Crt;VARarquivo : FILE OF BYTE;nomearq: STRING[67];

BEGINWRITE('Entre com o nome do arquivo que quer abrir ');READLN(nomearq);ASSIGN(arquivo,nomearq);{$I-}RESET(arquivo);{$I+}if IORESULT <> 0 then REWRITE(arquivo);END.

A segunda tarefa que devemos nos preocupar é o fato do arquivo permanecer aberto, ou abrirmos o mesmo arquivo mais de uma vez. Para termos um uso adequado de um arquivo, devemos abri-lo e depois de utilizado fechá-lo.

RESET

Este procedimento permite gue se feche um arquivo anteriormente aberto, só sendo permitido o fechamento de um arquivo por vez. Sua sintaxe:

CLOSE (VAR <arq>);

Exemplo :

PROGRAM teste_close;

VARarquivo : FILE OF BYTE;nomearq: STRING[67];

BEGINWRITE('Entre com o nome do arquivo que quer abrir');READLN(nomearq);ASSIGN(arquivo,nomearq);REWRITE(arquivo);CLOSE(arquivo);END.

10.1.3 Funções de escrita e gravação

Porém para manipularmos um arquivo não basta apenas abrí-lo e fechá-lo, temos, na maioria das vezes, que ler uma informação contida nele, outras vezes registrar informações novas,

83

Page 85: ApLP2-2006

ou ainda, fazer manutenção em informações já existentes. Vejamos então, como são os comandos que nos permitem tais tarefas:

10.1.3.1 WRITE

Este procedimento além de ser usado para exibir mensagens e variáveis no dispositivo padrão de saída (video), pode ser usado para gravar informações em outros dispositivos, como um arquivo. Sua sintaxe:

WRITE(<arq>, <reg1>[,<reg2>,..., <regn>] ;

Exemplo:

PROGRAM teste_write_arq;CONSTnomearq = 'TESTE.DAT';max = 10;

TYPEregistro = RECORD

nome : STRING[30]; ender: STRING[25];

END;

VARarquivo : FILE OF registro;reg : registro;ind : BYTE;

BEGINASSIGN(arquivo,nomearq);REWRITE(arquivo);FOR ind := 1 TO MAX DO

BEGINWRITE('Digite o ',ind,'o Nome ');READLN(reg.nome);WRITE('Digite o ',ind,'o Endereco ');READLN(reg.ender);WRITE(arquivo,reg);END;

CLOSE(arquivo);END.

10.1.3.2 READ

Como já vimos anteriormente, este procedimento permite que atribuamos a uma variável, um valor obtido por um dispositivo associado. Este dispositivo pode ser também um arquivo, e se no caso da leitura em arquivo, for detectado o fim do mesmo, será gerado um erro. Sua sintaxe:

READ(<arq>, <reg>);

84

Page 86: ApLP2-2006

Vejamos um exemplo simples de uma leitura em arquivos:

PROGRAM teste_read_arq;Uses Crt;CONSTnomearq = ´TESTE.DAT´;max = 10;

TYPEregistro = RECORD

nome : STRING[30];ender : STRING[25];

END;

VARarquivo: FILE OF registro;

reg: registro; ind: BYTE;

BEGINASSIGN(arquivo,nomearq);RESET(arquivo);FOR ind := 1 TO MAX DO

BEGINREAD(arquivo,reg);WRITELN ( 'Este é o ', ind, '.º Nome ', reg.nome) ;WRITELN('Este é ' o ',ind,'.º Endereco ',reg.ender);END;

CLOSE(arquivo);END.

No exemplo anterior, não temos problema algum ao executar a leitura no arquivo, pois este havia sido gravado anteriormente por nós mesmos e com uma quantidade de registros predefinidos. Porém, na maioria das vezes, não temos idéia da quantidade de registros contidos em um arquivo e para esta situação,devemos saber quando chegamos ao final de um arquivo. O Turbo nos fornece tal função :

10.1.3.3 EOF

Esta função nos retorna o valor TRUE quando for encontrada a marca de fim de arquivo. Sua sintaxe :

EOF(VAR <arq>) : BOOLEAN;

Utilizando o exemplo anterior, com uma pequena variação :

PROGRAM teste_eof;Uses crt;CONST

nomearq = 'TESTE.DAT';

TYPEregistro = RECORD

85

Page 87: ApLP2-2006

nome : STRING[30];ender: STRING[25];

END;

VAR

arquivo: FILE OF registro;reg: registro;ind: BYTE;

BEGIN ASSIGN(arquivo,nomearq); RESET(arquivo);ind := 1;WHILE NOT EOF(arquivo) DO

BEGINREAD(arquivo,reg);WRITELN ( 'Este é o ´,ind,'.º Nome ',reg.nome) ; WRITELN('Este é o ',ind,'.º Endereco ', reg.ender);ind := ind + 1;END;

CLOSE(arquivo);END.

O laço é repetido até que seja encontrada a marca de fim de arquivo.

Porém, para a manutenção de alguns registros de um determinado arquivo, temos que saber qual a posição deste registro no arquivo e também qual a posição do último registro.

Quando estamos manipulando um arquivo, existe a todo momento um ponteiro que fica deslocando-se de acordo com as leituras e gravações, ou seja, quando abrimos um arquivo,este ponteiro indica a posição zero, ou que é o primeiro registro fisico do arquivo. A cada leitura ou gravação este ponteiro avança uma posição, mas existem algumas funções e procedimentos que permitem a manipulação deste ponteiro.

10.1.3.4 SEEK

Este procedimento permite que movamos o ponteiro do arquivo para uma posição preestabelecida, podendo ser usado em arquivos de qualquer tipo exceto os de tipo TEXTO. Só pode ser usado em arquivos previamente abertos. Sua sintaxe :

SEEK(VAR <arq>; <posicao> : LONGINT);

Exemplo:

PROGRAM teste_seek;CONSTmax = 10;

TYPEregistro = RECORD

nome : STRING[30]; ender: STRING[25];

END;

86

Page 88: ApLP2-2006

VARarquivo : FILE OF registro;reg : registro;ind : BYTE;

BEGINASSIGN(arquivo,’TESTE.DAT’);REWRITE(arquivo);FOR ind := 1 TO MAX DO

BEGINWRITE('Digite o ',ind,'o Nome ');READLN(reg.nome);WRITE('Digite o ',ind,'o Endereco ');READLN(reg.ender);WRITE(arquivo,reg);END;

SEEK(arquivo,4); READ(arquivo,reg);WRITELN ('Este é o 5º Nome ',reg.nome) ; WRITELN ('Este é o 5º Endereco ', reg.ender);CLOSE(arquivo);END.

10.1.3.5 FILEPOS

Esta função nos retoma a posição atual do ponteiro do arquivo. Assim que abrimos um arquivo, com RESET ou REWRITE, a posição do ponteiro é zero, ou seja, o primeiro registro, não pode ser usado em arquivos do tipo TEXTO. Sua sintaxe :

FILEPOS(VAR <arq>) : LONGINT;

10.1.3.6 FILESIZE

Esta função retorna o tamanho de um arquivo em número de registros. Caso o arquivo esteja vazio, a função retornará 0. Não pode ser usada, em arquivos do tipo TEXTO. Sua sintaxe:

FILESIZE(VAR <arq>) : LONGINT;

Vejamos agora, um exemplo englobando estes últimos comandos:

PROGRAM teste_ponteiro;Uses Crt;VARnomearq: STRING[67];arquivo: FILE OF BYTE;tamanho: LONGINT;

BEGINWRITE('Entre com o nome do arquivo ');READLN(nomearq);

87

Page 89: ApLP2-2006

ASSIGN(arquivo,nomearq);RESET(arquivo);TAMANHO := FILESIZE(arquivo);WRITELN('O tamanho do arquivo ',nomearq, ´ em bytes ',tamanho);WRITELN('Posicionando no meio do arquivo... ');SEEK(arquivo,tamanho DIV 2);WRITELN ('A posicao atual é ', FILEPOS (arquivo) ) ;CLOSE(arquivo);READLN;END.

10.1.3.7 WITH

Este comando permite que a referência a uma variável do tipo registro seja simplificada. Podemos encadear até sete registros em um comando WITH. A referência aos campos dos registros pode ser efetuada com o uso deste comando sem a utilização do ponto, ligando o nome do registro ao nome do campo. Sua sintaxe:

WITH <registro1>, [<registron>...] DO BLOCO;

ExemploPROGRAM teste_with;CONSTmax = 10;

TYPEregistro = RECORD

nome : STRING[30];ender: STRING[25];

END;

VARarquivo : FILE OF registro;reg : registro;ind : BYTE;

BEGINASSIGN(arquivo,'TESTE.DAT');REWRITE(arquivo);WITH reg DO BEGIN FOR ind := 1 TO MAX DO

BEGIN WRITE('Digite o ',ind,'º Nome '); READLN(nome); WRITE('Digite o ',ind,'º Endereco '); READLN(ender); WRITE(arquivo,reg); END;

SEEK(arquivo,0); WHILE NOT EOF(arquivo) DO BEGIN READ(arquivo,reg); WRITELN ('Este é o ',filepos(arquivo),'º Nome ',nome) ; WRITELN ('Este é o ',filepos(arquivo),'º Endereco ', ender); END;

88

Page 90: ApLP2-2006

END;CLOSE(arquivo);END.

10.2 Arquivos Texto em Pascal e Delphi

Uma outra forma de se trabalhar com um arquivo, é definindo-o como sendo do tipo Texto. Esta forma de definição permite-nos ter registros de tamanhos diferentes, e cada registro é identificado pela sequência CR LF, Carriage Retum, e Line Feed, correspondentes aos caracteres ASCII $0D e $0A. O identificador TEXT define uma variável como sendo arquivo do tipo texto.

Exemplo:

PROGRAM teste_text;

USES CRT;

VARarq : TEXT; ch : CHAR;

BEGINWRITELN('Escolha onde deseja que seja impressa a fraseWRITELN(' Impressora, Disco, ou Video, (I, D,V) ' ) ; REPEATch := UPCASE(READKEY);UNTIL ch IN ['I','D','V'];IF ch = 'I' THEN

ASSIGN(arq,'PRN') ELSEIF ch = 'D' THEN

ASSIGN(arq,'TESTE.DAT') ELSEASSIGN(arq,'CON');

{$I-}REWRITE(ARQ);{$I+}IF IORESULT <> O THEN

WRITELN('Arquivo nao aberto ') ELSEBEGINWRITELN(arq,'Teste de TEXT ');CLOSE(arq);

END;WRITE('Tecle algo para continuar ');READKEY;END.

Este outro exemplo copia o arquivo “autoexec.bat” para um novo arquivo removendo todas as linhas marcadas com comentário (rem).

Program ExemploArquivoTexto;Uses CRT, Strings;

89

Page 91: ApLP2-2006

vararq1, arq2: text;buffer: string;aux: string[3];i: integer;

beginassign(arq1,'c:\autoexec.bat');assign(arq2,'c:\autoexec.new');{$I-}reset(arq1);{$I+}if IORESULT <> 0 then begin writeln('Nao foi possivel abrir o arquivo C:\AUTOEXEC,BAT'); end;rewrite(arq2);while not eof(arq1) do begin readln(arq1,buffer); aux:=copy(buffer,1,3); for i:= 1 to 3 do begin aux[i]:=upcase(aux[i]); end; if aux<>'REM' then begin writeln(arq2,buffer); end; end;writeln(arq2,'rem - Alterado pela exemplo de Arquivos Texto usando Pascal!');flush(arq2);end.

10.2.1 Funções para manipulação de arquivos texto

10.2.1.1 APPEND

Procedimento que permite a abertura de um arquivo do tipo TEXT, permitindo-se que se faça inclusão ao seu final. Se por acaso existir um caractere ^Z (ASCII 26) no arquivo, será assumido este ponto como fim do mesmo. O arquivo deverá ser previamente associado a um nome externo, e após o uso deste procedimento somente será permitida a inclusão de dados ao seu final. Sua sintaxe:

APPEND(var <arq> : TEXT);

Este procedimento não permite que se faça a abertura de um arquivo que ainda não existe. O seu uso correto se faz apenas quando o arquivo já existir. Se em seu disco de trabalho existe um arquivo chamado AUTOEXEC.BAT, faça o seguinte teste :

PROGRAM teste_append;

90

Page 92: ApLP2-2006

VARarq : TEXT; {define arq do tipo arquivo texto}BEGINASSIGN(arq,'\autoexec.bat'); {associa o nome externo a arq}APPEND(arq);WRITELN(arq,'ECHO INCLUIDO PELO TURBO');CLOSE(arq);END.

10.2.1.2 EOF(TEXT)

Esta função retorna verdadeiro se for encontrado o fim de um arquivo do tipo texto. A diferença entre EOF para Texto e EOF para arquivos tipados é que na primeira, a referência ao arquivo é opcional. Sua sintaxe:

EOF[(VAR <arq> : TEXT)] : BOOLEAN;

10.2.1.3 SEEKEOF

Esta função retorna verdadeiro se encontrado status de final de arquivo. É bastante parecida com a função EOF, exceto que esta salta todos os brancos e tabs quando da leitura. Somente para arquivos do tipo texto. Sua sintaxe:

SEEKEOF[(VAR <arq>:TEXT)] : BOOLEAN;

10.2.1.4 SEEKEOLN

Esta função retorna verdadeira se encontrada marca de fim de linha, salta todos os caracteres em branco e tabulações encontradas durante a leitura. Sua sintaxe:

SEEKEOLN[(VAR <arq> : TEXT)] : BOOLEAN;

10.2.1.5 FLUSH

Este procedimento permite que seja descarregada a área de Buffer de um arquivo do tipo Texto. Em sua utilização, pode ser usada a função IORESULT, que retornará zero caso a operação for bem sucedida. Sua sintaxe :

FLUSH(VAR <arq> : TEXT);

Exemplo:PROGRAM teste_flush;vararq : TEXT;

BEGINASSIGN(arq,'\autoexec.bat');

91

Page 93: ApLP2-2006

APPEND(arq);WRITELN(arq,'ECHO INCLUIDO PELO TURBO');FLUSH(arq);END.

No exemplo anterior, caso não tivéssemos nos utilizando da rotina FLUSH, a gravação não teria sido efetivada, pois a informação estaria apenas bufferizada.

10.2.1.6 SETTEXTBUF

Este procedimento permite-nos associar um arquivo com tipo TEXTO a uma área de buffer na área de dados do programa. Utilize sempre que possivel múltiplos de 128 para o tamanho do Buffer. Normalmente, esta área já está disposta pelo sistema operacional e corresponde a 128 Bytes. Este comando deve ser usado antes que o arquivo seja aberto, podendo ser usado tanto para leitura como para gravação. Este procedimento acelera os procedimentos de leitura e de gravação. Sua sintaxe :

SETTEXTBUF(VAR <arq>:TEXT; VAR <buffer> [;<tamanho> : WORD]);

10.3 ARQUIVOS SEM TIPOS EM PASCAL E DELPHI

Às vezes, temos a necessidade de manipular arquivos sem saber qual seu tipo de conteúdo. Poderiamos defini-lo do tipo BYTE, ou ainda, do tipo CHAR, porém se o arquivo tiver um tamanho relativamente grande, sua manipulação será meio lenta e neste caso, temos algumas opções.

10.3.1 Funções para manipulação de arquivos sem tipos

10.3.1.1 BLOKREAD

Procedimento que permite a leitura de um ou mais registros (blocos de 128 bytes), num máximo de 65535 bytes (64 K) de um arquivo sem tipo em uma variável que pode ser de qualquer tipo. Sua sintaxe:

BLOCKREAD(VAR <arq>: FILE; VAR <buffer>; <contador> : WORD; [VAR <resultado> : WORD];

10.3.1.2 BLOCKWRITE

Procedimento que permite a gravação de um ou mais registros (bloco de 128 bytes) de um arquivo sem tipo em uma variável que pode ser de qualquer tipo.

Sua sintaxe:

92

Page 94: ApLP2-2006

BLOCKWRITE(VAR <arq>: FILE; VAR <buffer>; <contador> : WORD; [VAR <resultado> : WORD];

Exemplo que utiliza estes comandos :

PROGRAM teste_biock;

VAR arqent,arqsai : FILE; nomeent,nomesai : STRING[79]; lidos, gravados : WORD; buf : ARRAY[1..4096] OF CHAR;

BEGINWRITE('Entre com o nome do arquivo de Origem ');READLN(nomeent);ASSIGN(arqent,nomeent);RESET(arqent,l);WRITE ('Entre com o nome do arquivo de Destino ') ;READLN(nomesai);ASSIGN(arqsai,nomesai);REWRITE(arqsai,l);WRITELN('Copiando ',FileSize(arqent),' bytes...');REPEAT

BLOCKREAD(arqent,buf,sizeof(buf),lidos);BLOCKWRITE(arqsai,buf,lidos,gravados);

UNTIL (lidos = 0) OR (gravados <> lidos);Close(arqent);Close(arqsai);END.

É de fundamental importância, que ao abrir o arquivo coloque-se além da variável tipo File, também o tamanho 1.

10.3.1.3 TRUNCATE

Este procedimento faz com que o arquivo seja truncado em seu tamanho, na posição corrente do ponteiro do arquivo. Sua sintaxe ;

TRUNCATE(VAR <arq>);

10.3.2 Arquivos com diversas estruturas em Pascal e Delphi

Um arquivo pode conter diversas estruturas. Para uma leitura correta desses arquivos é necessário conhecer o "layout" desse arquivo.

93

Page 95: ApLP2-2006

Por exemplo, um arquivo DBF, utilizado por dBase, Clipper, FoxPro e reconhecido por qualquer programa que importe base de dados, é dividido em 3 partes distintas: cabeçalho, atributos dos campos e dados.

O cabeçalho possui um registro com a seguinte definição:

str_dbf = record versao: byte; ano: byte; mes: byte; dia: byte; n_regs: longint; tam_cab: integer; tam_reg: integer; reservado: Array[1..20] of char; end;

A seguir para cada atributo (campo) há o seguinte registro:

descr_atr = record nome: array[1..11] of char; tipo: char; reservado1: array[1..4] of char; tamanho: byte; num_dec: byte; reservado2: array[1..14] of char; end;

A quantidade de atributos é dada pela fórmula:

atributos := trunc((dbf.tam_cab-sizeof(str_dbf))/sizeof(descr_atr));

Os dados são gravados a partir do 1º byte posterior ao tamano do cabeçalho (cab.tam_cab). No início de cada registro (conjunto de atributos) é gravado um byte para marcar se o registro está deletado (se o caracter for igual a 42 (*)) ou não (se o caracter for igual a 32 (espaço em branco)), e são todos gravados em modo texto, sendo que cada registro referente a cada atributo possui o tamanho definido na descrição do atributo (tamanho + num_dec).

Program LeDBF;Uses CRT;

TYPE

str_dbf = record versao: byte; ano: byte; mes: byte; dia: byte; n_regs: longint; tam_cab: integer; tam_reg: integer;

94

Page 96: ApLP2-2006

reservado: Array[1..20] of char; end;

descr_atr = record nome: array[1..11] of char; tipo: char; reservado1: array[1..4] of char; tamanho: byte; num_dec: byte; reservado2: array[1..14] of char; end;

VARdesc: descr_atr;dbf: str_dbf;arq:FILE;quant, i: integer;aux: char;nomeaux: Array[1..256] of string[12];tipo: Array[1..256] of char;tam, dec: Array[1..256] of byte;buffer: char;nome_arquivo: string;tm, cont, k, qtd, l, tm1, tm2, op, tamanho, zz, byteslidos: integer;

BEGINclrscr;write('Nome do Arquivo: ');readln(nome_arquivo);assign(arq,nome_arquivo);{$I-}reset(arq,1);{$I+}if IORESULT <> 0 then begin writeln('Nome de Arquivo Invalido!'); readkey; exit; end;BLOCKREAD(arq,dbf,32,byteslidos);writeln('versao: ',dbf.versao);writeln('ano: ',dbf.ano);writeln('mes: ',dbf.mes);writeln('dia: ',dbf.dia);writeln('n§ reg: ',dbf.n_regs);writeln('t_cab: ',dbf.tam_cab);writeln('t_reg: ',dbf.tam_reg);writeln('reserv: ',dbf.reservado);writeln('-------------------------------');readkey;quant := trunc((dbf.tam_cab-sizeof(str_dbf))/sizeof(descr_atr));writeln('Blidos: ',byteslidos);writeln('Quant: ',quant);writeln('Tam cab: ',sizeof(str_dbf));writeln('Tam campos: ',sizeof(descr_atr));for i:=1 to quant do begin BLOCKREAD(arq,desc,sizeof(descr_atr),byteslidos); tipo[i]:=desc.tipo; tam[i]:=desc.tamanho; nomeaux[i]:=desc.nome;

95

Page 97: ApLP2-2006

dec[i]:=desc.num_dec; writeln(desc.nome, ' - ',desc.tipo, ' - ',desc.tamanho, ' - ',desc.num_dec); end;

write('Ler quantos registros - (999 - todos)? ');readln(qtd);seek(arq,dbf.tam_cab);if (qtd=999) then qtd:=dbf.n_regs;cont:=1;while ((cont<=qtd) and (not eof(arq))) do begin writeln(' Registro: ',cont,' -------------------------'); BLOCKREAD(arq,aux,1,byteslidos); if (aux<>' ') then writeln('-> ',aux,' (deletado) '); for k:=1 to quant do begin write(nomeaux[k],': '); for l:= 1 to tam[k] do begin BLOCKREAD(arq,buffer,1,byteslidos); write(buffer); end; writeln; end; readkey; cont:=cont+1; end;writeln(' ************* FIM ');

readkey;clrscr;end.

10.4 Arquivos em C

Um arquivo em “C” não possui a idéia de registro. Podemos gravar dados no formato de caracter (ASCII) ou em binário (“binary file”). A seqüência e interpretação dos dados é de inteira responsabilidade do programador do sistema. Um arquivo em “C” é uma seqüência contínua de butes gravados em memória secundária. Cada byte do arquivo possui um endereço único que é o deslocamento relativo ao início do arquivo.

Toda a manipulação de arquivos é realizada através de funções de biblioteca. Existem dois níveis de funções: as rotinas de “baixo nível” - mais eficientes, que utilizam diretamente os recursos do sitema operacional - e as de “alto nível” - mais fáceis de serem utilizadas - construídas sobre as funções de “baixo nível”.

Para as rotinas de alto-nível, os arquivos são acessados através de ponteiros para estruturas do tipo “FILE”, definidas em “stdio.h”. Para as rotinas de baixo nível os arquivos são identificados por um número inteiro que é o código identificador do arquivo retornado pelo sistema operacional (file handle). Na estrutura FILE, o número identificador do arquivo é o campo “fd”.

As rotinas de alto-nível possuem por sua vez dois conjuntos de rotinas: rotinas para manipulação de arquivos texto e rotinas para manipulação de arquivos binários. A diferença

96

Page 98: ApLP2-2006

básica entre os dois conjuntos é que as rotinas de manipulação de arquivos binários armazenam uma cópia dos bytes da memória principal para a secundária enquanto que as de manipulação de arquivos texto armazenam a representação ASCII dos valores.

Principais rotinas de baixo nível (prototipadas em io.h)

access - Verifica se um arquivo existe e se pode ser lido/gravado.

chmod - Modifica os atributos de um arquivo.

close - Fecha um arquivo.

creat - Cria um arquivo. Está em desuso

eof - Verifica se a leitura chegou ao final de um arquivo.

filelenght - Informa o tamanho de um arquivo.

getftime - Informa a data de criação/acesso de um arquivo.

lock - Coloca um arquivo em uso exclusivo. É utilizada para fazer controle de acesso concorrente em ambiente multi-usuário ou de rede.

lseek - Descola o ponteiro de leitura para um byte específico no arquivo.

open - Abre/cria um arquivo.

read - Lê dados de um arquivo.

tell - Informa em qual byte está o ponteiro do arquivo.

unlock - Libera o arquivo do uso exclusivo.

write - Escreve dados em um arquivo.

Principais rotinas de alto nível:

fclose - Fecha um arquivo.

feof - Informa se a leitura chegou ao fim de arquivo.

fflush - Esvazia o buffer do arquivo.

fgetc - Lê um caracter de um arquivo.

fgets - Lê uma string de um arquivo.

fputc - Escreve um caracter em um arquivo.

fputs - Escreve uma string em um arquivo.

fread - Lê dados de um arquivo.

fscanf - Lê dados de um arquivo, como “scanf”

fseek - Desloca o ponteiro do arquivo para um determinado byte.

ftell - Indica em qual byte se localiza o ponteiro do arquivo.

fwrite - Escreve em um arquivo.

remove - Remove um arquivo.

rename - Muda o nome de um arquivo.

97

Page 99: ApLP2-2006

setvbuf - Modifica o tamanho interno do buffer do arquivo.

fflushall - Descarrega o buffer de todos os arquivos.

fprintf - Escreve em um arquivo, no mesmo formato que printf.

Obs: Existem cinco arquivos tipo “stream” pré-definidos que são automaticamente abertos quando um programa entra em execução:

stdin - Dispositivo padrão de entrada (geralmente teclado).

stdout - Dispositivo padrão de saída (geralmente vídeo).

stderr - Dispositivo padrão para saída de erros.

stdaux - Dispositivo auxiliar (porta serial, por exemplo).

stdprn - Impressora padrão do sistema.

Exemplo:

printf(“%d”,x);

é o mesmo que

fprintf(stdout, “%d”, x);

10.4.1 Declaração de arquivos

Quando se usa o conjunto de rotinas de alto nível, utilizam-se ponteiros do tipo FILE para armazenar uma referência para um arquivo. FILE é na verdade uma estrutura que guarda uma série de informações sobre o arquivo. Uma estrutura desse tipo é alocada pela rotina “fopen” e uma referência para a mesma deve ser armazenada.

Exemplo:

FILE *arq, *arq1;

10.4.2 Funções de abertura e fechamento de arquivos

A função fopen é usada para a abertura de arquivos tanto no modo texto como no modo binário. Em seus parâmetros devemos indicar o nome com o qual o arquivo é (ou será) identificado no dispositivo de memória secundária e o modo que se deseja trabalhar com o mesmo (leitura, escrita, alteração, etc). A função fopen retorna um ponteiro para a estrutura do tipo FILE que descreve o arquivo.

Função “fopen”

Sintaxe:

98

Page 100: ApLP2-2006

<fstream> = fopen(<nome_arquivo>,”<modo>“);

onde:

fstream = ponteiro para o arquivo;

nomearq = string que contém o nome do arquivo no disco;

“modo” = string constante composta por dois caracteres que indica o modo de abertura do arquivo:

modos:

w – abre/cria para escrita. Se já existe, é destruído.

r – abre somente para leitura.

a – abre o arquivo para escrita a partir do fim do mesmo ou cria se o arquivo não existir.

r+ – abre um arquivo já existente tanto para leitura como para gravação. Se este arquivo já existir ele não será destruído.

w+ – abre um arquivo tanto para leitura como para gravação. Se este arquivo já existir ele será destruído.

a+ – abre um arquivo para leitura/gravação ao final do arquivo. Se o arquivo não existe ele é criado.

No MS-DOS ainda há como segundo caracter de modo as opções:

b – especifica que o arquivo é binário

t – especifica que o arquivo é texto

A função fopen retorna NULL se não puder abrir/criar o arquivo.

Exemplo:

...char narq[20];

arq1 = fopen(“texto.txt”,“wt”);if (arq1 == NULL) printf(“Não consegui abrir o arquivo\n”);

strcpy(narq,“dados”);arq2 = fopen(narq,“rb”);if (arq2 == NULL) printf(“Não consegui abrir o arquivo %s”,narq);...

Função “fclose”

99

Page 101: ApLP2-2006

A função fclose deve ser usada toda a vez que não for mais necessário trabalhar com um arquivo. Libera os buffers alocados pelo sistema operacional para o gerenciamento do arquivo garantindo que todos os dados são efetivamente descarregados no dispositivo de memória secundária. Libera também a estrutura do tipo FILE.

Sintaxe:

fclose <fstream>

onde:

fstream = ponteiro para o arquivo

Exemplo:

fclose(arq1);fclose(arq2);

10.4.3 Funções de escrita e gravação

10.4.3.1 Função “fwrite”

A função fwrite copia uma porção da memória principal para um dispositivo de memória secundária. Recebe como parâmetros o endereço do início da área e a quantidade de bytes a ser copiada.

Sintaxe

fwrite(<ptr>, <tamanho>, <nro>, <fstream>);

onde:

ptr = ponteiro para o início dos dados a serem gravados

tamanho = tamanho do registro lógico;

nro = quantidade de registros lógicos (registro físico = nro x tamanho);

fstream = ponteiro para o arquivo;

fwrite retorna o número de itens que conseguiu gravar no arquivo.

10.4.3.2 Função “fread”

A função fread tem a função inversa da função fwrite carregando um conjunto de bytes do dispositivo de memória secundária para a memória principal. Possui os mesmos parâmetros que fwrite porém com o sentido inverso.

Sintaxe

fread(<ptr>, <tamanho>, <nro>, <fstream>);

100

Page 102: ApLP2-2006

onde:

ptr = ponteiro para o início da área onde devem ser armazenados os dados lidos;

tamanho = tamanho do registro lógico;

nro = quantidade de registros lógicos a serem lidos;

fstream = ponteiro para o arquivo;

fread retorna o número de itens que conseguiu ler do arquivo.

10.4.3.3 Função “feof” - Teste de Fim de Arquivo:

A função de teste de fim de arquivo feof retorna o valor lógico verdadeiro quando o programa tenta ler o arquivo após o último byte gravado.

Sintaxe:

<x> = feof (<fstream>);

onde:

fstream = ponteiro para o arquivo;

x = um inteiro que recebe o valor 1 se foi encontrado o fim de arquivo, senão recebe 0.

Ex.:

while(!feof(arq1))

fread(&buf,sizeof(int),10,arq1);

Exemplo de um programa que grava e escreve na tela uma estrutura de nome e idade:

#include <conio.h>#include <stdio.h>#include <stdlib.h>#include <io.h>

typedef struct{char nome[30];int idade;}pessoa;

pessoa cliente;

FILE *arq1;int i, tamanho;

void main(){

101

Page 103: ApLP2-2006

clrscr();arq1 = fopen("clientes.dat","ab+");if (arq1==NULL) exit(1);for(i=0;i<4;i++);

{printf("nome: ");fflush(stdin);gets(cliente.nome);fflush(stdin);printf("idade: ");scanf("%d",&cliente.idade);fwrite(&cliente,sizeof(cliente),1,arq1);}

clrscr();rewind(arq1);while(!feof(arq1))

{fread(&cliente,sizeof(pessoa),1,arq1);if(!feof(arq1))

{printf("nome: %s - %d anos\n",cliente.nome, \

cliente.idade);}

}getch();}

10.4.4 Funções de Escrita e Gravação em Arquivos Texto

10.4.4.1 Função “fputc”

A funçao fputc permite que se armazene um caracter (um byte) em um arquivo texto.

Sintaxe:

fputc(<char>,<fstream>);

onde:

char = caracter a ser gravado;

fstream = ponteiro para o arquivo;

10.4.4.2 Função “fgetc”

A funçao fgetc permite que se leia um caracter (um byte) de um arquivo texto.

Sintaxe:

<c> = fgetc(<fstream>);

onde:

102

Page 104: ApLP2-2006

c = variável que recebe o caracter lido;

fstream = ponteiro para o arquivo;

10.4.4.3 Função “fputs”

A funçao fputs permite que se grave um string em um arquivo texto.

Sintaxe:

fputs(<str>,<fstream>);

onde:

str = ponteiro para o string a ser gravado (substitui o “\0” por um “\n” no momento da gravação);

fstream = ponteiro para o arquivo;

10.4.4.4 Função “fgets”

A funçao fgets permite que se leia um string inteiro de uma só vez de um arquivo texto. Lê todos os caracteres até encontrar um “\n” ou estourar o limite estabelecido nos parâmetros.

Sintaxe:

fgets(<str>,<tammax>,<fstream>);

onde:

str = ponteiro para o string a ser lido (carrega todos os caracteres até encontrar um “\n” e acrescenta um “\0” no fim do string).

tammax = número máximo de caracteres que podemser lidos.

fstream = ponteiro para o arquivo;

10.4.4.5 Função “fprintf”

A funçao fprintf permite a gravação formatada de dados em um arquivo texto. Os dados são armazendados no arquivo da mesma maneira que seriam jogados no dispositivo de saída padrão. A sintaxe é igual a da função printf diferenciando-se apenas pela indicação do arquivo destino.

Sintaxe:

fprintf (<fstream>, “<string de controle>”, <lista de argumentos>);

funciona como o comando printf com a diferença que os caracteres são enviados para o arquivo especificado por fstream.

103

Page 105: ApLP2-2006

10.4.4.6 Função “fscanf”

Possui a mesma filosofia de fprintf só que para a leitura de dados. Possui sintaxe idêntica a da função scanf diferenciando-se apenas pela indicação do arquivo fonte.

Sintaxe:

fscanf (<fstream>, “<string de controle>”, <lista de argumentos>);

Funciona como o comando scanf com a diferença que os caracteres são lidos do arquivos específicado por fstream

O programa abaixo é um exemplo de programa que utiliza as funções fgets, fputs, fgetc, fputc, fscanf, fprintf, para manipular um arquivo texto.

#include <stdio.h>#include <conio.h>#include <stdlib.h>#include <string.h>

FILE *arq1;char i, caracter, meu_complemento[20], frase_do_arq[80];

void main(){arq1 = fopen("teste.txt","w+t");if(arq1==NULL)

{printf("Nao foi possivel abrir o arquivo!");exit(1);}

strcpy(meu_complemento,"Maravilhoso!");fprintf(arq1,"Ola Mundo %s\n",meu_complemento);fputs("Este e' o alfabeto: ",arq1);for(i=65;i<=90;i++)

{fputc(i,arq1);}

clrscr();rewind(arq1);fscanf(arq1,"%s",frase_do_arq);printf("%s",frase_do_arq);fgets(frase_do_arq,80,arq1);printf("%s",frase_do_arq);while(!feof(arq1))

{caracter=fgetc(arq1);putchar(caracter);}

getch();}

104

Page 106: ApLP2-2006

10.4.5 Funções "fseek" , "ftell" e "rewind"

As funções fseek, ftell e rewind são usadas para determinar ou modificar a localização do marcador de posição de arquivo.

A sintaxe é:

fseek (ponteiro_arquivo, bytes_de_deslocamento, de_onde);

A função fseek reinicializa o marcador de posição no arquivo apontado por por ponteiro_arquivo para o número de bytes_de_deslocamento a partir:

do início do arquivo (de_onde = 0)

da localização atual do marcador de posição no arquivo (de_onde = 1)

do final do arquivo (de_onde = 2).

A função fseek retornará 0 se o reposicionamento for bem sucedido ou EOF se não.

Para determinar a quantidade de bytes_de_deslocamento pode-se usar a função sizeof que retorna o tamanho de uma variável ou de uma estrutura.

EX:

fseek(arq1,sizeof(float),0);fseek(arq1,sizeof(clientes),1);

A função ftell retorna a posição atual do marcador de posição no arquivo apontado por ponteiro_arquivo. Esta posiçào é indicada por um deslocamento medido em bytes, a partir do início do arquivo.

A sintaxe é:

variável_long = ftell (ponteiro_arquivo);

A função rewind simplesmente reinicializa para o início do arquivo o marcador de posição no arquivo apontado por ponteiro_arquivo.

A sintaxe é:

rewind(ponteiro_arquivo);

10.4.6 Arquivos com diversas estruturas

Um arquivo pode conter diversas estruturas. Para uma leitura correta desses arquivos é necessário conhecer o "layout" desse arquivo.

Por exemplo, um arquivo DBF, utilizado por dBase, Clipper, FoxPro e reconhecido por qualquer programa que importe base de dados, é dividido em 3 partes distintas: cabeçalho, atributos dos campos e dados.

105

Page 107: ApLP2-2006

O cabeçalho possui um registro com a seguinte definição:

typedef struct{char versao;char ano;char mes;char dia;long int n_regs;int tam_cab;int tam_reg;char reservado[20];} inf_DBF;

A seguir para cada atributo (campo) há o seguinte registro:

typedef struct{char nome[11];char tipo;char reservado[4];char tamanho;char num_dec;char reservado2[14];} descr_atrib;

A quantidade de atributos é dada pela fórmula:

atributos = (cab.tam_cab - sizeof(inf_DBF))/sizeof(descr_atrib);

Os dados são gravados a partir do 1º byte posterior ao tamano do cabeçalho (cab.tam_cab). No início de cada registro (conjunto de atributos) é gravado um byte para marcar se o registro está deletado (se o caracter for igual a 42 (*)) ou não (se o caracter for igual a 32 (espaço em branco)), e são todos gravados em modo texto, sendo que cada registro referente a cada atributo possui o tamanho definido na descrição do atributo (tamanho + num_dec).

O seguinte programa lê um arquivo DBF:

#include <conio.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <io.h>

typedef struct{char versao;char ano;char mes;char dia;long int n_regs;int tam_cab;int tam_reg;char reservado[20];} str_dbf;

106

Page 108: ApLP2-2006

typedef struct{char nome[11];char tipo;char reservado1[4];char tamanho;char num_dec;char reservado2[14];} descr_atr;

descr_atr desc;str_dbf dbf;FILE *arq;int quant, i;char aux;char nomeaux[256][12];char tipo[256];char tam[256];char dec[256];int tm, j, k, qtd, l, tm1, tm2, op, tamanho, zz;

void main(int argc, char *argv[]){if (argc!=2)

{printf("\nA sintaxe e' ledbf arquivo.dbf\n");exit(1);}

clrscr();arq=fopen(argv[1],"rb");if (arq==NULL)

{printf("Arquivo Inexistente!");exit(1);}

fread(&dbf,sizeof(str_dbf),1,arq);printf("versao: %d\n",dbf.versao);printf("ano: %d\n",dbf.ano);printf("mes: %d\n",dbf.mes);printf("dia: %d\n",dbf.dia);printf("nº reg: %ld\n",dbf.n_regs);printf("t_cab: %i\n",dbf.tam_cab);printf("t_reg: %i\n",dbf.tam_reg);printf("reserv: %s\n",dbf.reservado);printf("-------------------------------\n\n");tamanho=sizeof(str_dbf);getch();quant=(int)((dbf.tam_cab-sizeof(str_dbf))/sizeof(descr_atr));for (i=0;i<quant;i++)

{fread(&desc,sizeof(descr_atr),1,arq);tipo[i]=desc.tipo;tam[i]=desc.tamanho;strcpy(nomeaux[i],desc.nome);dec[i]=desc.num_dec;printf("\n%11s - %c - %2d - %2d",desc.nome, desc.tipo, desc.tamanho,

desc.num_dec);tamanho += sizeof(descr_atr);}

printf("\n\nLer quantos registros - (999 - todos)? ");

107

Page 109: ApLP2-2006

scanf("%d",&qtd);fseek(arq,dbf.tam_cab,0);if (qtd==999) qtd=dbf.n_regs;j=1;while ((j<=qtd) &&(!(feof(arq))))

{printf("\n\n Registro: %d -------------------------",j);fread(&aux,1,1,arq);if (aux!=' ') printf("\n-> %c (deletado) ",aux);for (k=0;k<quant;k++)

{printf("\n %12s: ",nomeaux[k]);for (l=1;l<=tam[k];l++)

{fread(&aux,1,1,arq);printf("%c",aux);}

}getch();j++;}

printf("\n ************* FIM ");getch();clrscr();}

108

Page 110: ApLP2-2006

11. LINGUAGEM DELPHI

O que é o Delphi ?

O Delphi nada mais é que um simples IDE, IDE voce já deve saber é um ambiente integrado para desenvolvimento composto por compilador, editor de texto, ferramenta de depuração e algumas frescurinhas a mais.Talvez você diga, "háaa mas isso eu já sabia, IDE é aquela Janela com aqueles lindos botaozinhos...".Resposta errada outra vez, um IDE nada tem a ver com Interface Grafica (GUI), é apenas um ambiente composto (voce vai ficar careca de saber) pelo compilador, depurador, editor de textos, etc... e nem sempre esse ambiente é grafico.Quem ai já não viu o Borland C ? Pois é, apesar de ser uma ferramenta que roda do prompt do DOS tem tudo integrado nele mesmo.Possui um IDE, onde se pode abrir varios arquivos simultaneos, um excelente depurador, o editor de texto insuperável e muitas outras coisas extras.Tudo isso, num IDE terminal texto. Incrivel não ?Mudou sua IDEia sobre o IDE ?A diferença entre o IDE DELPHI para os outros IDE's por ai, é que o DELPHI é um IDE RAD.

Um IDE RAD (Rapid Application Development) ?

Sim o DELPHI é RAD, isto é, a medida em que os componentes vão sendo selecionados, o DELPHI escreve o código fonte para você. Os componentes em geral, incluem classes e propriedades muito utilizadas e que se relacionam com outros objetos. Tudo que nele existe foi pensando em Velocidade de Desenvolvimento.Um exemplo típico para o RAD do DELPHI é :Ao colocar um Botao num formulário, veja o que ocorre : - na clausula "uses", acrescenta a lib que contém o objeto TButton.- Tambem é criado um TButton.Create que cria o objeto para ser usado, mas dessa vez fica no arquivo .DFM.- Se o object TButton possuir dependencias de outras classes, o DELPHI se encarrega de encontra-las e inclui-las em sua aplicacao.

Mas o DELPHI é uma linguagem ou não ?

Pois é, se alguem lhe perguntar em que linguagem voce cria seus sistemas, não diga "DELPHI" tão rapidamente.Voce só deve dizer DELPHI, quando estiver em volta de um meio academico onde as pessoas conheçam o DELPHI, tal como, lista de discussão sobre o assunto, forums relacionados, etc... Talvez voce esteja achando que estou sendo purista demais, não ?Veja bem, se você for a uma lista, diga-mos de Linux, e falar que voce escreve programas em DELPHI, os programadores Linux quenormalmente usam C, C++, etc... que não são usuários de DELPHI, mas entendem o que é linguagem, vão entender que você não entende nada sobre programação, pois você não respondeu adequadamente. Na certa, vão achar que você é um daquelesque fica arrastando botõeszinhos, labelzinhos e depois vende um aplicativo quase sem nenhuma programação.

109

Page 111: ApLP2-2006

Conclusão : Se alguem lhe perguntar que linguagem você usa, nunca diga "DELPHI" !Diga : Object Pascal !

ObjectPascal, a liguagem

Quando você está usando o DELPHI, a linguagem gerada por ele é o ObjectPascal. Tanto isso é verdade que é possivel compilar o programa e seu codigo fonte sem a presença do DELPHI. Faça o teste :

dbcc32 [nome-do-dpr] lib [nome-das-libs]

O ObjectPascal, é a linguagem pascal orientado a objetos, com todo o poder do OOP. Se voce for um ótimo programador ObjectPascal, talvez nem precise do DELPHI para escrever seus programas.O pessoal do FreePascal (outra linguagem compátivel com ObjectPascal) já faz isso a bastante tempo.Mas convenhamos, o DELPHI quebra um galhão, com todos aqueles packages e componentes, a linha de comando para se compilar um projeto ObjectPascal na mão (da até friozinho)...certamente não seria das tarefas mais agradáveis.Temos de dar os parabens a Borland, escrever um IDE decente para uma linguagem não é nada fácil.Talvez o tempo de desenvolvimento do IDE (DELPHI), seje igual ou superior ao tempo de desenvolvimento da linguagem.Outras linguagens, mesmos as mais complexas tornam-se fáceis para o iniciante se tivermos um IDE decente, principalmente se for RAD.O pessoal do KDE (Linux) já vem trabalhando há muito tempo no Kdevelopment, um IDE parecido com o DELPHI para a linguagem C++, no entanto, não é um IDE RAD, apenas um IDE. O KDevelopment é um bom IDE, mas acho que não existe interesse em transforma-lo em RAD.

DELPHI e outros RAD's

É comum em nosso meio, de haver comparação entre ferramentas RADs.A principal delas, é o DELPHI(Borland) x VB (Microsoft).Quando comparamos os IDE's não vemos muitas diferenças entre ambos. Ambos são excelentes.Mas quando comparamos as linguagens, digo, ObjectPascal x VisualBasic, então as diferenças são muitas.A comparação do ObjectPascal x VisualBasic não é justa, pois ambos são diferentes num principio básico :O ObjectPascal é uma linguagem totalmente OOP. O VB ainda é orientado a eventos. Alguns programadores VB podem argumentar com certa razão que iniciantes em DELPHI não usam OOP, mas a verdade é que eles usam, mesmo sem saberem disso!Por exemplo, quando um form em branco é criado, o DELPHI acrescenta as linhas "Form1 : TForm1", o que já é uma caracteristica de herança em OOP no ObjectPascal.Outra coisa que torna a comparação impossivel é que o VisualBasic baseia suas soluções em componentes e API, quando voce possui um problema, se voce não tiver um componente adequado ou uma funcao API que resolva o problema, o desenvolvimento fica emperrado. No ObjectPascal e também outras linguagens, elas permitem ao programador intermediario, desenvolver suas próprias soluções sem depender de terceiros.Pode-se criar as mais diversas aplicações : emuladores, device-drivers, comunicação com outros dispositivos, etc...

110

Page 112: ApLP2-2006

11.1 Conceitos básicos

11.1.1 Programação em Windows: Janelas e eventos

Existem muitas diferenças entre a programação em DOS e a programação em Windows. Vejamos a principal: Quando programamos em DOS, nosso programa é responsável pelo fluxo de processamento. Temos que definir claramente não só que instruções, mas também em que ordem devem ser executadas. Em Windows não é bem assim. Nosso programa não controla o fluxo de processamento, ele responde e trata eventos que ocorrem no sistema. Existem muitos eventos que podem ocorrer, sendo que os principais são aqueles gerados pelo usuário através do mouse e do teclado. A coisa acontece mais ou menos assim: O usuário clica o mouse e o Windows verifica que aplicação estava debaixo do mouse no momento em que foi clicado. Em seguida ele manda uma mensagem para a aplicação informando que ocorreu um clique e as coordenadas do cursor do mouse na tela no momento do clique. A aplicação então responde à mensagem executando uma função de acordo com a posição do mouse na tela. É claro que o Delphi toma conta do serviço mais pesado e facilita muito as coisas para o programador. Detalhes como as coordenadas da tela em que ocorreu o clique, embora estejam disponíveis, dificilmente são necessários nos programas.

11.2 Programação Orientada a Objeto (POO)

Embora não seja objetivo ensinar POO, uma breve introdução é necessária, já que o Delphi é essencialmente orientado a objeto.

De maneira prática, podemos pensar no objeto sendo uma estrutura que agrupa dados e funções para manipular estes dados. Como as funções são sempre “íntimas” dos dados, o sistema todo funciona de maneira mais segura e confiável. Além disso, a POO utiliza conceitos como encapsulamento e herança que facilitam muito programação e manutenção dos programas.

Neste ponto é oportuno citar que os dados de um objeto costumam ser chamados de variáveis de instância e as funções de métodos. As variáveis de instância definem as propriedades (as vezes chamada de atributos) do objeto e os métodos definem seu comportamento.

Para programar no nível do designer não é necessário um conhecimento profundo de POO. Mas é preciso conhecer pelo menos a sintaxe. Todas as aplicações para Windows, precisam de pelo menos uma janela, que no Delphi é chamada de Form. Cada form (assim como todos os objetos visuais) tem um objeto associado a ele e sua representação visual, que vemos na tela. Todos os componentes que incluímos no form, passam a fazer parte do objeto que define o form. Exemplo: Se colocarmos um botão no form, a classe deste form será modificada para incluir este botão. Os eventos e métodos deste form, também estão na classe. Assim, supondo que o form se chame Form1 (nome default), para por exemplo desativar o botão que incluímos (de nome Buttom1) escreveríamos:

Form1.Buttom1.Enabled := false;

Note como o Buttom1 faz parte da estrutura que define o form. Mas se quisermos ativar método RePaint (Repintar) do form faríamos:

111

Page 113: ApLP2-2006

Form1.Repaint;

Veja que Repaint, não é uma variável, tecnicamente é uma procedure, mas fazemos referência a ela como parte da estrutura Form1. Pode parecer confuso no início, mas facilita muito a programação.

11.3 O ambiente do Delphi

Quando ativamos o Delphi, a tela inicial tem a barra do menu principal do Delphi, à esquerda a SpeedBar, com as opções mais comuns e à direita a paleta de componentes. Estes componentes são a base da programação visual e é onde o designer vai buscar recursos para sua aplicação. Abaixo da SpeedBar, está a janela do Object Inspector, que permite visualizar e modificar as propriedades e eventos de todos os componentes. É também largamente utilizado pelo designer. Abaixo da paleta ficam a janela de código-fonte e as janelas que estão sendo construídas.

11.3.1 Arquivos que Compõem um Aplicação

11.3.1.1 Arquivos Gerados no desenvolvimento

Ext. Definição Função.DPR Arquivo do Projeto Código fonte em Pascal do arquivo principal do projeto. Lista todos os

formulários e units no projeto, e contém código de inicialização da aplicação. Criado quando o projeto é salvo.

.PAS Código fonte da Unit( Object Pascal)

Um arquivo .PAS é gerado por cada formulário que o projeto contém. Seu projeto pode conter um ou mais arquivos .PAS associados com algum formulário. Contem todas as declarações e procedimentos incluindo eventos de um formulário.

.DFM Arquivo gráfico do formulário

Arquivo binário que contém as propriedades do desenho de um formulário contido em um projeto. Um .DFM é gerado em companhia de um arquivo .PAS para cada formulário do projeto.

.CFG Arquivo de opções do projeto

Arquivo texto que contém a situação corrente das opções do projeto. Gerado com o primeiro salvamento e atualizado em subsequentes alterações feitas para as opções do projeto.

.RES Arquivo de Recursos do Compilador

Arquivo binário que contém o ícone, mensagens da aplicação e outros recursos usados pelo projeto.

.DSK Situação da Área de Trabalho

Este arquivo armazena informações sobre a situação da área de trabalho especifica para o projeto em opções de ambiente( Options Environment).

Obs.: .~DF, .~PA , .~DP são arquivos de backup. Devido a grande quantidade de arquivos de uma aplicação, cada projeto deve ser montado em um diretório específico.

11.3.2 Arquivos Gerados pela Compilação

Ext Definição Função.EXE Arquivo compilado executável Este é um arquivo executável distribuível de sua aplicação. Este arquivo

incorpora todos os arquivos .DCU gerados quando sua aplicação é compilada.

.DCU Código ob-jeto da Unit A compilação cria um arquivo .DCU para cada .PAS no projeto.

Obs.: Estes arquivos podem ser apagados para economizar espaço em disco.

112

Page 114: ApLP2-2006

11.4 Componentes

11.4.1 Nomenclatura

Para nomear os componentes podemos usar uma convenção muito usada, onde as primeiras letras, minúsculas, identificam o tipo do componente e o restante identifica a função deste, assim, btnSair, seria o botão de sair.

Se a função do componente for um nome composto esse nome deve ser escrito com os primeiros nomes abreviados e com letras de caso variável, como em btnRelVendas, que seria o botão do relatório de vendas ou btnRelVenProduto, que seria o botão do relatório de vendas por produto.

11.4.2 Propriedades

As propriedades são características dos componentes, como foi mostrado anteriormente.

11.4.2.1 Propriedades Comuns

Propriedade DescriçãoAlign Determina o alinhamento do componenteCanvas Superfície de desenho, do tipo TCanvas, onde pode se desenhar a imagem do

componenteCaption Legenda do componente (& indica tecla de atalho para alguns componentes)Color Cor do componenteComponentCount O número de componentes possuídosComponents Matriz de componentes possuídosCtl3D Define a aparência 3D do componenteEnabled Define se o componente está ativo, se pode ser usadoFont Fonte utilizada no componenteHeight AlturaHelpContext Número utilizado para chamar o Help on-lineHint String utilizada em dicas instantâneasLeft Posição esquerdaName Nome do componentePopupMenu Menu de contexto do componenteShowHint Define se o Hint será mostradoTabOrder A ordem de tabulação do componente, usada quando o usuário tecla TABTabStop Indica se o componente será selecionado quando o usuário teclar TABTag Propriedade não utilizada pelo Delphi, que pode ser usada como propriedade

personalizadaTop Posição superiorVisible Define se o componente está visívelWidth Largura

11.4.3 Eventos

Os Eventos acontecem em resposta a uma ação do usuário ou do próprio sistema, ao programar um método de evento, devemos levar em consideração que este só será executados quando o evento acontecer. Uma das tarefas mais importantes na programação baseada em eventos é determinar quais eventos serão usados e qual a ordem desses eventos, por exemplo,

113

Page 115: ApLP2-2006

quando o usuário clicar em um botão, qual evento acontecerá primeiro, OnEnter, OnMouseDown ou OnClick?

Os eventos podem ser compartilhados entre componentes, dessa Forma, você pode ter um botão na barra de ferramentas que faz a mesma coisa que uma opção de menu. Para isso, basta escolher o evento na lista em vez de clicar duas vezes no Object Inspector.

Podemos também mudar os métodos de evento em código, pois os eventos também são propriedades e podem ser usados como tal. Você pode atribuir um evento de outro componente ou diretamente o nome do método, como mostrado abaixo.

Button1.OnClick := Edit1.OnExit;Button2.OnClick := Edit2Click;

11.4.3.1 Eventos Comuns

Evento DescriçãoOnChange O conteúdo do componente é alteradoOnClick O componente é acionadoOnDblClick Duplo-clique no componenteOnEnter O componente recebe o focoOnExit O componente perde o focoOnKeyDown Tecla pressionadaOnKeyPress Uma tecla é pressionada e soltaOnKeyUp Tecla é solta

11.4.4 Métodos

Os métodos realizam ações definidas pelo componente, veja os exemplos abaixo e atente para os parâmetros passados. Note que podemos chamar os métodos de evento como qualquer outro método e que os métodos de evento pertencem ao Form, não aos componentes.

Edit1.Clear;Form2.Show;Close;ScaleBy(110, 100);Button1.ScrollBy(10, 10);Button1.OnClick(Sender);Button1Click(Self);Form2.Button1Click(Sender);

11.4.4.1 Métodos Comuns

Método DescriçãoCreate Cria um novo Objeto de uma ClasseFree Destrói um Objeto e libera a memória ocupada por eleShow Torna o componente visívelHide Torna o componente invisívelSetFocus Coloca o foco no componenteFocused Determina se o componente tem o focoBringToFront Coloca o componente na frente dos outrosSendToBack Coloca o componente atrás dos outrosScrollBy Move o componenteScaleBy Gradua o componente em determina escalaSetBounds Muda a posição e o tamanho do componente

114

Page 116: ApLP2-2006

11.4.5 Janelas

Todo aplicativo Windows é composto por janelas, que são o elemento básico no desenvolvimento Delphi, sobre o qual um aplicativo é construído. O tipo TForm é usado no Delphi como classe base para todas as janelas, veja abaixo algumas propriedades, eventos e métodos dessa classe.

Propriedade DescriçãoActive Indica se o Form está ativoActiveControl

Determina o controle que receberá o foco por default

AutoScroll Adiciona barras de rolagem automaticamente, quando necessárioBorderIcons Define quais ícones de controle serão visíveis, quais botões vão aparecer na barra de títuloBorderStyle Estilo da borda do FormFormStyle Tipo de Form, normal, MDI pai, MDI filho ou sempre visívelIcon Ícone do FormMenu Indica qual o menu do FormPosition Permite controlar a posição e tamanho do Form na exibiçãoWindowMenu

Automatiza o item de menu Window (MDI)

WindowState Estado do Form, maximizada, minimizada ou normalEvento DescriçãoOnCreate Quando o Form é instanciadoOnDestroy Quando o Form é liberado da memóriaOnShow Exatamente antes de mostrar o FormOnCloseQuery

É chamada para validar se o Form pode ser fechado

OnClose Quando o Form é fechadoOnActivate Quando o Form recebe o focoOnDeactivate Quando o Form perde o focoOnResize Quando o Form muda de tamanhoMétodo DescriçãoCascade Organiza as Forms filhos em cascata (MDI)Tile Organiza as Forms filhos lado a lado (MDI)ArrangeIcons Organiza os ícones dos Forms Filhos minimizados (MDI)ShowModal Ativa o Form modal, que o usuário tem que fechar para poder continuar a usar a aplicaçãoShow Mostra o FormClose Fecha o FormPrevious Ativa o Form anterior (MDI)Next Ativa a próximo Form (MDI)

11.4.6 TMainMenu

Menu principal de um Form.

Propriedade DescriçãoItems Itens de menu, essa propriedade guarda todas as alterações feitas no Menu Designer

Este componente permite a fácil construção de menus. Após sua colocação no form, basta executar um duplo-click que aparecerá o MenuDesigner, colocando na propriedade Caption o conteúdo do item de menu. Você pode clicar e arrastar os itens do menu para rearranjá-los em seu projeto. Não é necessário “rodar” o projeto para ver os resultados – o menu está sempre visível na janela de formulário, com a aparência que terá durante a execução do programa.

115

Page 117: ApLP2-2006

Para se criar sub-menus, clique com o botão direito do mouse no item que você deseja criar o sub-menu, e escolha a opção Create Submenu (Ctrl+Right); o processo de construção é igual ao descrito acima. Não há limite para os níveis de sub-menu.

Pode-se deletar menus selecionan-dos, e pressinando a tecla Del; e inserir menus clicando-se na tecla Insert - estas operações são igualmente possíveis através do acionamento de speedmenu do MenuDesigner (acessa-se o speedmenu, clicando-se o botão direito do mouse sob o MenuDesigner).

Colocando um & antes de uma letra do menu (capitulação), ela aparece sublinhada. O usuário pode selecionar a opção do menu apenas pressionando a letra quando o menu estiver aberto.

Regras para capitulação:

1º primeira letra;

2º se houver duas letras iniciais iguais, pega-se a primeira consoante; se houver a primeira consoante igual; pega-se o Segunda consoante e assim procede-se até esgortar-se as consoantes;

3º caso os passos 1º e 2º se esgotarem, pega-se a primeira vogal e assim sucessivamente;

4º se não for possível capitular as opções, pode-se diferencia-las com o acréscimo de caracteres extras ou optar-se por não capitulá-las

11.4.7 TPopUpMenu

Menu de contexto de um componente. Cada componente tem uma propriedade PopUpMenu, que indica seu menu de contexto.

11.4.8 TLabel

Utilizado para exibir rótulos

Propriedade DescriçãoAlignment Alinhamento do texto no componenteAutoSize Define se o tamanho do componente será automaticamente ajustado ao tamanho do CaptionWordWrap Retorno automático de linhaTransparent Define se o componente será transparenteFocusControl Componente que receberá o foco quando a tecla de atalho do Caption (&) for pressionadaShowAccelChar Indica se o caractere & será usado para definir tecla de atalho

11.4.9 TEdit

Utilizado para entrada de texto em uma única linha.

Propriedade DescriçãoText Texto do componenteAutoSelect Indica se o texto será ou não selecionado quando o componente receber o foco

116

Page 118: ApLP2-2006

MaxLength Número máximo de caracteres permitidosCharCase Define se as letras aparecerão em maiúsculo, minúsculo ou normalPasswordChar Caractere utilizado para esconder o texto digitado (Senhas)ReadOnly Define se será permitido alterar o textoMétodo DescriçãoClear Limpa o conteúdo do componenteClearSelection Limpa o texto selecionado no componente

11.4.10 TMemo

Permite entrada de dados texto em múltiplas linhas. Contém propriedades e métodos do TEdit.

Propriedade DescriçãoLines Propriedade do tipo TStrings que armazena as linhas de texto do componenteWantReturns Define se a tecla ENTER será tratada como quebra de linhaWantTabs Define se a tecla TAB será tratada como espaço de tabulaçãoScrollBar Define as barras de rolagem

11.4.11 TButton

Componente botão padrão do Windows, utilizado para executar ações.

Propriedade DescriçãoCancel Dispara o evento OnClick do botão quando a tecla ESC é pressionada em qualquer controleDefault Dispara o evento OnClick do botão quando a tecla ENTER é pressionada em qualquer controleModalResult Associa o botão a opção de fechamento de um Form modalMétodo DescriçãoClick Ativa o evento OnClick do botão

11.4.12 TCheckBox

Utilizado para obter inFormações de checagem.

Propriedade DescriçãoAllowGrayed Determina se o checkbox terá três possibilidades de estadoChecked Determina se o checkbox está marcadoState Estado atual do checkbox

A principal propriedade deste componente é a Checked, que indica se o CheckBox está marcado ou desmarcado. Tipicamente, este controle mostra dois tipos de escolha (True ou False). Mas podemos configurar para que ele mostre três estados diferentes. Para isto colocamos a propriedade AllowGrayed para True e passamos a ler o estado do componente pela propriedade State, que pode assumir um dos três valores seguintes: cbUnchecked, cbGrayed, cbChecked.

11.4.13 TRadioButton

Usado em grupo, pode ser utilizado para obter inFormações lógicas mutuamente exclusivas, mas é recomendado usar o RadioGroup em vez de RadioButtons.

11.4.14 TListBox

Utilizado para exibir opções em uma lista.

117

Page 119: ApLP2-2006

Propriedade DescriçãoColumns Número de colunas de texto da listaMultiSelect Define se será permitida a seleção de múltiplos itensExtendedSelect Define se a seleção poderá ser estendida pelo uso das teclas Shift e CtrlIntegralHeight Define se os itens poderão aparecer parcialmente ou somente por completoItems Lista de strings com os itens da listaItemIndex Índice do item selecionado, começando em 0Selected De acordo com o índice indica se um item em particular esta selecionadoSelCount Indica quantos itens estão selecionadoSorted Define se os itens aparecerão ordenados

11.4.15 TComboBox

Caixa combinada com lista suspensa.

Propriedade DescriçãoItems Lista de strings com os itens da listaDropDownCount Número de itens visíveis da lista suspensaStyle Estilo do ComboBox, os principais estilos são csDropDown, csDropDownList, csSimple

11.4.16 TScrollBox

Container com barras de rolagem automáticas.

11.4.17 TGroupBox

Componente container com um título e borda 3D. Utilizado com RadioButtons.

11.4.18 TRadioGroup

Componente que agrupa e controla RadioButtons automaticamente.

Propriedade DescriçãoColumns Número de colunas de RadioButtonsItems Lista de strings com os itens do RadioGroup, cada item da lista representa um RadioButtonItemIndex Item selecionado, iniciando em 0

Para acessar o índice do componente selecionado utilize:

<nome do componente>.ItemIndexEx.: showmessage (‘Selecionada a ‘ + IntToStr(RadioGroup1.ItemIndex) + ‘ ª Opção.’);showmessage (‘Selecionada a ‘ + IntToStr(ComboBox1.ItemIndex) + ‘ ª Opção.’);showmessage (‘Selecionada a ‘ + IntToStr(ListBox1.ItemIndex) + ‘ ª Opção.’);

Para acessar o texto do componente selecionado utilize:<nome do componente>.Items[<nome do componente>.ItemIndex ]showmessage (‘Opção escolhida: ‘ + ListBox1.Items[ListBox1.ItemIndex]);showmessage (‘Opção escolhida: ‘ + RadioGruop1.Items[RadioGroup1.ItemIndex]);showmessage (‘Opção escolhida: ‘ + ComboBox1.Items[ComboBox1.ItemIndex]);showmessage (‘Opção escolhida: ‘ + ComboBox1.Text);

118

Page 120: ApLP2-2006

11.4.19 TPanel

Componente Container utilizado para agrupar componentes em um painel.

Propriedade DescriçãoBevelInner Estilo da moldura interna do painelBevelOuter Estilo da moldura externa do painelBevelWidth Largura das moldurasBorderStyle Estilo da BordaBorderWidth Largura da borda, distância entre as molduras interna e externa

11.4.20 TActionList

Usado para criar lista de ações para serem usadas com SpeedButtons e MenuItems.

11.4.21 TBitBtn

Botão especializado, com Bitmap.

Propriedade DescriçãoGlyph Bitmap exibido pelo botãoLayOut Posição do Bitmap no BotãoMargin Indica o espaço entre a borda do botão e o BitmapSpacing Indica o espaço entre o Bitmap e o texto do botãoKind Seleciona um tipo padrão para o botão, mudando várias propriedades, como Glyph e ModalResult

11.4.22 TMaskEdit

Permite entrada de dados texto em uma linha, utilizando uma máscara de edição. Possui todas as propriedades do componente TEdit.

Propriedade DescriçãoEditMask Máscara de edição

Máscaras

Uma máscara é composta por três partes, a primeira parte é a máscara propriamente dita, a segunda parte indica se os caracteres literais serão salvos e a terceira parte indica qual o caractere utilizado para representar os espaços a serem digitados no texto.

Estes são os caracteres especiais que podem compor a máscara de edição:

Carac-tere

Descrição

! Espaços em branco não serão considerados no texto> Todos os caracteres seguintes serão maiúsculos até que apareça o caractere < < Todos os caracteres seguintes serão minúsculos até que apareça o caractere > \ Indica um caractere literall Somente caractere alfabéticoL Obrigatoriamente um caractere alfabético a Somente caractere alfanuméricoA Obrigatoriamente caractere alfanumérico9 Somente caractere numérico0 Obrigatoriamente caractere numéricoc Permite um caractere

119

Page 121: ApLP2-2006

C Obrigatoriamente um caractere# Permite um caractere numérico ou sinal de mais ou de menos, mas não os requer.: Separador de horas, minutos e segundos/ Separador de dias, meses e anos

11.4.23 TBevel

Moldura ou linha com aparência 3D.

Propriedade DescriçãoShape Tipo de moldura a ser desenhadaStyle Define alto ou baixo relevo para a linha

11.4.24 TShape

Gráfico de uma Forma geométrica.

Propriedade DescriçãoBrush Preenchimento da figura, objeto do tipo TBrushPen Tipo da linha, objeto do tipo TPenShape Forma geométrica

11.4.25 TImage

Componente usado para exibir figuras.

Propriedade DescriçãoCenter Determina de a figura será centralizada no componentePicture Figura a exibida, pode ser BMP, ICO, WMF ou EMFStretch Define se o tamanho da figura deve ser ajustada ao do componente

11.4.26 TPageControl

Usado para criar controles com múltiplas páginas, que podem ser manipuladas, em tempo de projeto, através do menu de contexto. Cada página criada é um objeto do tipo TTabSheet.

Propriedade DescriçãoActivePage Página ativaMultiLine Define múltiplas linhas de guias de páginasTabHeigth Altura das guiasTabWidth Largura das guiasEvento DescriçãoOnChange Após uma mudança de páginaOnChanging Permite a validação de uma mudança de páginaMétodo DescriçãoFindNextPage Retorna a próxima páginaSelectNextPage

Seleciona a próxima página

11.4.27 TTabSheet

Página de um PageControl.

Propriedade DescriçãoPageIndex Ordem da página

120

Page 122: ApLP2-2006

TabVisible Define se a aba da página é visível

11.4.28 TTimer

Permite a execução de um evento a cada intervalo de tempo.

Propriedade DescriçãoInterval Tempo em milissegundos quando o componente irá disparar o evento OnTimerEvento DescriçãoOnTimer Chamado a cada ciclo de tempo determinado em Interval

11.4.29 TStatusBar

Utilizado para criar barras de status para exibir informações.

Propriedade DescriçãoSimplePanel Indica se haverá apenas um panelSimpleText Texto exibido caso SimplePanel seja TrueSizeGrip Define se a alça de redimensionamento padrão deve ser mostradaPanels Propriedade do tipo TStatusPanels, com os painéis do StatusBar. O texto da barra de status é

definido com a propriedade StatusBarX.panels[X].text

11.4.30 TStatusPanels

Lista de panels de um StatusBar.

Propriedade DescriçãoCount Número de panelsItems Lista de panels, cada panel é um objeto do tipo TStatusPanelMétodo DescriçãoAdd Adiciona um novo panel à lista

11.4.31 TStatusPanel

Panel de um StatusBar.

Propriedade DescriçãoText Texto do panelWidth Largura em pixelsBevel Moldura do panelAlignment Alinhamento do texto de um panel

11.4.32 TStringGrid

Componente para exibição e edição de uma tabela de strings. É organizado em linhas e colunas e o elemento básico é a celula.

Propriedade DescriçãoColCount Quantidade de lolunasRowCount Quantidade de linhasDefaultColWidth Altura padrão das colunasDefaultRowHeight Largura padrão das linhasCells Texto das células. É uma matriz em que deve ser especificado linha e coluna.

Exemplo: StringGrid1.cells[2,3] FixedCols Quantidade de Colunas fixas

121

Page 123: ApLP2-2006

FixedRows Quantidade de Linhas fixasRow Linha SelecionadaCol Coluna selecionadaOptions Conjunto de Opções do StringGridLoadFromFile Carrega figura de um arquivoSaveToFile Salva figura para um arquivo

11.5 Caixas de Mensagem

Existem algumas funções que permitem mostrar uma mensagem rapidamente em uma caixa de diálogo. São elas: ShowMessage, MessageDlg e MessageBox.

11.5.1 ShowMessage

Esta função permite colocar uma caixa de diálogo contendo um botão de “OK” e uma mensagem. Não podemos colocar outros botões nem mudar o título, que é sempre o nome do programa.

showmessage(‘Coloque sua mensagem aqui!’);

11.5.2 MessageBox

Esta permite que atribuam valores arbitrários ao título e as mensagens. Existem dois tipos de MessageBox: um da API ( MessageBox ) e um do Delphi ( Application.MessageBox ). Ambos permitem que se atribuam valores tanto ao “recheio” como para o título; também permitem que se acrescentem constantes MB_xxx para mudar o aspecto da caixa de diálogo.

MessageBox retorna um valor dependendo do botão pressionado.

Sintaxe:

MessageBox(‘<Mensagem da caixa>’, ’<Titulo>’, Constantes MB_xxx);

<Mensagem da caixa>: string que será mostrado no interior da caixa.

<Titulo>: string que será mostrado no titulo da caixa.

<Constantes MB_xxx>: concatenação de constantes que mudarão o aspecto da caixa. Podem ser:

Valor SignificadoMB_ABORTRETRYIGNORE A caixa de diálogo conterá três botões: Anular, Repetir e IgnorarMB_APPLMODAL A caixa de diálogo será modal.MB_DEFBUTTON1 O primeiro botão da caixa de diálogo fica como defaultMB_DEFBUTTON2 O segundo botão da caixa de diálogo fica como defaultMB_DEFBUTTON3 O terceiro botão da caixa de diálogo fica como defaultMB_DEFBUTTON4 O quarto botão da caixa de diálogo fica como defaultMB_HELP É adicionado um botão de Ajuda na caixa de diálogo, quando for pressionado

ou a tecla F1 é gerado o evento de Help, válido somente para Windows 95, MB_ICONASTERISK Mostra um “i” azul, minúsculo dentro de um balão

(MB_ICONINFORMATION)MB_ICONERROR Mostra um “X” banco, dentro de um circulo vermelho, o mesmo que

122

Page 124: ApLP2-2006

MB_ICONHAND, somente para windowes 95.MB_ICONEXCLAMATION Mostra um ponto de exclamação, dentro de um triângulo amareloMB_ICONHAND O mesmo que MB_ICONSTOPMB_ICONINFORMATION O mesmo que MB_ICONASTERIXMB_ICONQUESTION Mostra um ponto de interrogação dentro de um balãoMB_ICONSTOP O mesmo que MB_ICONERRORMB_ICONWARNING O mesmo quer MB_ICONEXCLAMATION, válido somente para windows

95.MB_OK A caixa de diálogo conterá um botão de OKMB_OKCANCEL A caixa de diálogo conterá os botões de OK e CancelarMB_RETRYCANCEL A caixa de diálogo conterá botões de Repetir e CancelarMB_YESNO A caixa de diálogo conterá botões de Sim e NãoMB_YESNOCANCEL A caixa de diálogo conterá botões de Sim, Não e Cancelar

Esta função pode retornar valores dependendo do pressionamento dos botões.

Valor Valor numérico

Significado

IDABORT 3 O usário pressionou o botão de AnularIDCANCEL 2 O usário pressionou o botão de CancelarIDIGNORE 5 O usário pressionou o botão de IgnorarIDNO 7 O usário pressionou o botão de NãoIDOK 1 O usário pressionou o botão de OKIDRETRY 4 O usário pressionou o botão de RepetirIDYES 6 O usário pressionou o botão de Sim

Exemplo: O código abaixo:

Application.MessageBox('A terra é azul - tricolor', 'Confirmação', MB_APPLMODAL + MB_ICONWARNING + MB_YESNOCANCEL);

Terá como resultado a seguinte caixa de diálogo:

Exemplo: O código abaixo:

if Application.MessageBox('A terra é azul - tricolor','Confirmação', MB_APPLMODAL + MB_ICONWARNING + MB_YESNOCANCEL) = idyes then

beginshowmessage('Realmente é azul!');

end;

11.5.3 InputBox

Permite que o usuário digite uma string na caixa de diálogo. Possui os botões OK e Cancel. Se o usuário clicar em cancel o texto padrão é retornado.

123

Page 125: ApLP2-2006

Sintaxe:

InputBox(<Título>, <Mensagem da Caixa>, <texto padrão>

var Texto: string;begin Texto:= InputBox('Gerenciador de Aplicativo', 'Informe a Senha', 'Ninguém'); showmessage(texto);end;

11.6 Dicas

Resumo dos componentes com as principais propriedades e métodos:

Componente Propriedades Métodos

Application Initialize;CreateFormRun;Terminate

Form CloseShowShowmodal

Label CaptionEnabledFontName

Edit EnabledFontMaxlengthNamePasswordCharReadOnlyText

Setfocus

Button CaptionEnabledFontNameText

Setfocus

RadioButton CaptionCheckedEnabledFontName

Setfocus

CheckBox CaptionCheckedEnabledFontNameState

Setfocus

Memo EnabledFontLines

ClearLines.AddLines.Count

124

Page 126: ApLP2-2006

MaxlengthNameReadOnlyScrollBars

Setfocus

ListBox EnabledFontItemsMultiSelectNameSorted

ClearItems.AddItems.CountSetfocus

ComboBox EnabledFontItemIndexItemsNameSortedText

ClearItems.AddItems.DeleteItems.CountSetfocus

RadioGroup EnabledFontItemIndexItemsName

Items.AddItems.DeleteItems.CountSetfocus

Para aceitar somente números em campos Edit e ComboBox, Inserir o código abaixo no evento OnKeyPress do controle de edição:

procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);beginif ((key<'0') or (key>'9')) and (key<>#8) and (key<>#13) then begin Messagebeep(0); key:=#0; end;end;

Para saltar de um campo para outro usando a tecla ENTER, Inserir o código abaixo no evento OnKeyPress do controle de edição de cada componente:

procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);beginif Key=#13 thenbeginSelectNext(Sender as TWinControl, True, True);key:=#0;end;end;

Para saltar de um campo para outro usando a tecla ENTER de todos os componentes, Inserir o código abaixo no evento OnKeyPress do Formulário:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);beginif key=#13 then begin key:=#0;PostMessage( handle, WM_KEYDOWN, VK_TAB, 1); end;end;

Atribua true à propriedade KeyPreview do Formulário.

125

Page 127: ApLP2-2006

Esta rotina não funcionará em formulários que tenham TMemo ou TDBMemo. Estes componentes precisam da tecla ENTER para gerar novas linhas. Em formulários assim, a rotina pode ser usada, desde que seja inserido no evento OnEnter do componente Memo o código:

procedure TForm1.Memo1Enter(Sender: TObject);beginForm1.KeyPreview:=false;end;

e no envento OnExit o códigoprocedure TForm1.Memo1Exit(Sender: TObject);beginForm1.KeyPreview:=true;end;

Para pedir confirmação antes de encerrar o programa, inserir o código abaixo no evento OnCloseQuery do Formulário:

if application.messagebox('Encerrar o Programa?', 'Confirmação', MB_APPLMODAL+MB_ICONQUESTION+MB_YESNO) = idyes then canclose:= true

else canclose:= false;

Conversões

Todos os componentes de entrada de dados utilizam a propriedade text que é string. Para manipulação de números é necessário uma conversão do formato.

Função Descrição ExemploDate retorna a data corrente Edit.text := 'Hoje é ' + DateToStr(Date);DateToStr converte um valor data

em string.DecodeDate Separa a data em dia,

mês, anoDecodeDate(Date, ano, mes, dia);

DecodeTime Separa a hora em hora, minutos, segundos, centésimos

DecodeTime(Now, Hora, Min, Seg, cent);

Now Retorna a data e hora do sistema

FloatToStr converte um número float numa string.

Edit1.text:=FloatToStr(x)

FormatFloat formata um número float e retorna uma string. (‘#,##.00’,10000,2) = 10.000,24

formatfloat ('#,##.00', strtofloat(Edit1.text))

IntToStr converte um número inteiro numa string. Edit1.Text := IntToStr(x);

StrToIntDef converte uma string num número inteiro e atribui um valor padrão em caso de erro

x := StrToIntDef(Edit1.text, 0);

Str transforma um número em string com número de casas pré-definido

Str(X:0:2, S);

StrToDate converte uma string em data.

CData := StrToDate(Edit1.Text);

StrToFloat converte uma string num número float.

x:= StrToFloat(edit1.text);

StrToInt converte uma string num número inteiro

i:= x:= StrToInt(edit1.text);

StrToTime converte uma string em hora

ATime := StrToTime(Edit1.Text);

126

Page 128: ApLP2-2006

Time retorna a hora corrente. Edit1.text := 'A hora é ' + TimeToStr(Time)TimeToStr converte a hora corrente

em string.Val Transforma uma string

num número e permite analisar o sucesso desta transformação

var I, erro: Integer;beginVal(Edit1.Text, I, erro);if erro <> 0 then begin Showmessage('Erro’); end;

127

Page 129: ApLP2-2006

BIBLIOGRAFIA

GUEZZI, Carlo & JAZAYERI, Mehdi. Conceitos de Linguagem de Programação. Rio de Janeiro, Ed. Campus. 1985.

KELLY-BOOTLE, Stan. Dominando o Turbo C. Rio de Janeiro, Ed. Ciência Moderna. 1989.

KERNIGHAM, Brian W. & RITCHIE, Dennis M. C: A Linguagem de Programação. Rio de Janeiro, Ed. Campus. 1986.

LONGO, Maurício B.; SMITH Jr., Ronaldo & POLISTCHUCK, Daniel. Delphi 3 Total. Rio de Janeiro, Brasport Livros e Multimídia Ltda. 1997.

MECLER, Ian & MAIA, Luiz Paulo. Programação e Lógica com Turbo Pascal. Rio de Janeiro, Ed. Campus. 1989.

PALMER, Scott D. Guia do Programador - Turbo Pascal for Windows. Rio de Janeiro, Editora Ciência Moderna. 1992.

PAPPAS, Chris H. & MURRAY, Wiliam H. Borland C++. São Paulo, Makron Books. 1995.

RINALDI, Roberto. Turbo Pascal 7.0: Comandos e Funções. São Paulo, Érica. 1993.

SCHILDT, Herbert. Linguagem C: Guia Prático e Interativo. São Paulo, McGraw-Hill. 1989.

WIENER, Richard S. Turbo C Passo a Passo. Rio de Janeiro, Ed. Campus. 1991

128