Delphi - Segredos e Solues
 
CAPTULO 5
 
Tcnicas de Programao Avanada

O ltimo captulo mostrou-lhe os fundamentos da linguagem de programao
interna do Delphi. Este captulo leva voc mais adiante para domin-la.
Ns comeamos por  lhe mostrar como ampliar os tipos internos do Delphi,
construindo seus prprios tipos. Em seguida, trata-se de listas,
matrizes e registros. Esses so utilizados  quando voc precisa
trabalhar com grupos de dados ao mesmo tempo. Depois h um tratamento
curto sobre ponteiros e gerenciamento de memria. Segue uma discusso
rpida  a respeito das funes e procedimentos internos do Delphi e,
depois disso, uma seo sobre como escrever suas prprias funes e
procedimentos. Terminamos o captulo  gastando um pouco de tempo na
anatomia de um projeto e de uma unidade, o que voc precisa saber para
utilizar com mais eficincia o compilador do Delphi ao gerar  programas
independentes e o infame goto.

Reviso de Tipos

A linguagem de programao do Delphi  um exemplo de uma linguagem
fortemente tip ficada. Isso significa que todas as variveis tm de ter
tipos e que, ao contrrio  do, digamos, Visual Basic, o compilador
realizar apenas converses limitadas entre tipos. Por exemplo, se uma
varivel  declarada como sendo Real, ento voc no  pode especific-la
como Integer. (Por outro lado, voc pode atribuir valores do tipo Char a
uma varivel do tipo String, ou atribuir um valor do tipo Integer a um
tipo Floating Point, ou fazer atribuies entre duas variveis do tipo
Floating Point ou duas variveis do tipo Integer quando os valores so
compatveis. )

NOTA: Veja os tpicos de ajuda on-line "Assignment Compatibility" e
"Type Compatibility", para saber exatamente as atribuies entre tipos
que voc pode fazer.

        Alguns programadores encaram com convico as linguagens
tipificadas do tipo do Delphi como camisas-de-fora, mas o consenso 
que, a longo prazo, o cdigo   de fcil manuteno e menos sujeito a
erros em linguagens fortemente tipificadas do que  voc pode ou no
concordar). De qualquer forma, uma vez que o Delphi  fortemente
tipificado e no h como se livrar disso, voc tem de tornar seu estilo
de programao  compatvel com essa situao.

Tipos de Dados Ordinais

Os tipos de dados internos do Delphi, como String ou Integer, podem ser
refinados ou combinados para criar novos tipos de dados. Embora voc
possa criar muitas espcies  diferentes de tipos de dados no Delphi, ns
comeamos com as tcnicas necessrias para a criao de exemplos novos
de tipos de dados ordinais. Embora ainda no utilizamos o termo tipo de
dado ordinal, voc j viu os exemplos mais comuns deles: Integer e Char
so ambos tipos de dados ordinais.  As caractersticas que definem tipos
de dados ordinais so
       
        *Eles tm de ser formados por um nmero finito de elementos.
        *Eles tambm tm de ser ordenados de alguma forma.

        Em particular, em quaisquer tipos ordinais, tem de fazer sentido
a movimentao para frente ou para trs at o prximo elemento. Os tipos
Floating Point  no so ordinais porque a movimentao para frente ou
para trs no faz sentido: a pergunta "

Tipos de Dados Enumerados

A maneira mais fcil de criar um exemplo novo de um tipo ordinal 
relacionar um grupo de elementos em alguma ordem. Ao fazer isso, voc
ter o que  chamado de  tipo de dado enumerado. Eis alguns exemplos de
como criar tipos de dados enumerados:
        
        type
            Clone = (Compaq, Dell, Gateway, Packard, Micron, Zeos,
Outro);
          DiasTrabalho = (Segunda, Tera, Quarta, Quinta, Sexta);

        Assim que definir um tipo de dado enumerado, voc poder
declarar variveis para que sejam daquele tipo utilizando a sintaxe
padro, um exemplo do qual mostramos  aqui:
        
        var
            SeuComputador: Clone;

        O objetivo primrio de um tipo de. dado enumerado  deixar claro
quais os dados seu programa manusear. Em geral, um tipo de dado
enumerado:
        
        *No  formado por mais de 256 elementos.
        *Tem um identificador nico para cada elemento no tipo.

       O Delphi permite-lhe trabalhar com os elementos em um tipo de
dado enumerado utilizando um ndice que se origina da ordem em que eles
foram relacionados.  O Delphi indexa os elementos em um tipo de dado
enumerado comeando em 0 (no l ). Assim, em  ndice 6. As funes
relacionadas na Tabela 5.1 permitem-lhe se movimentar pelos elementos em
um tipo de dado enumerado.

Tabela 5.1 Funes para Trabalhar com Tipos de Dados Ordinais.

        Pred(X) - Vai at o elemento relacionado antes de X no tipo
Succ(X) - Vai at o elemento relacionado depois do X no tipo Dec(X;n) -
Volta n elementos para trs. (Se omitir o n, volta 1.) Inc(X;n) - Move n
elementos para frente. (Se omitir o n, anda 1.)
        Ord(X) - Fornece-Ihe o ndice do elemento

NOTA: Se voc tentar avanar quando os elementos terminarem (utilizando
Succ quando estiver no ltimo elemento), ento, desde que a verificao
de limite esteja  ativada, o Delphi gerar um erro em tempo de execuo.
(Veja no Captulo 7 como tratar erros em tempo de execuo.)

DICA: Voc pode utilizar essas funes com qualquer tipo ordinal.

        Voc realmente j viu tipos de subfaixas em operao na
declarao case (conforme discutido no Captulo 4). Quando tnhamos uma
declarao como
       
        case NotaMedia of
             90..99

ns estvamos utilizando uma subfaixa dos inteiros que consiste dos
nmeros 90 at 99. Em geral, voc pode definir qualquer subfaixa
comeando com um tipo ordinal  (incluindo um tipo enumerado
anteriormente definido) e utilizando um ponto duplo. Por exemplo:
       
        type
          CarControle = #0..#31; {utilizando # para um caractere ASCII}
          Maiscula = #65..#90;

        Novamente, o ponto de um tipo de subfaixa consiste em tornar
claro qual dado seu cdigo est manuseando.

Conjuntos

Os conjuntos funcionam de forma muito semelhante aos tipos de dados
enumerados, mas no so tipos de dados ordinais porque a ordem dos
elementos no  mais importante.  Voc utiliza um conjunto quando est
mais preocupado com quais elementos que se encontram no conjunto do que
com a sua ordem. Da mesma forma que os tipos enumerados,  os conjuntos
podem conter at 256 elementos mas todos os elementos tm que ser
tomados do mesmo tipo de dado ordinal e, se os elementos so numricos,
tm Rue estar entre 0 e 255. Em particular, voc no pode formar um
conjunto que consiste de caracteres e inteiros ou um contendo  elementos
como 20.000. Aqui mostramos o exemplo de uma declarao de conjunto:
                 
                 type
                    Caracteres = set of Char;
                    Primos = set of Integer;

        Para realmente criar o conjunto, utilize colchetes e separe os
itens por vrgulas:
                   
                var
                     PrimosPequenos: Primos;
                     Vogais: Caracteres;
                   begin
                     PrimosPequenos := [2, 3, 5, 7,11,13,17];
                    Vogais := ['a', 'e', 'i', 'o', 'u'1;

        Os operadores para tratar de conjuntos so descritos na Tabela
52. Eis o exemplo de como funcionam os operadores utilizados com
conjuntos.
                 
                Se
                 
                Vogais:= ['A', 'a', 'E', 'e', 'I', 'i', 'O', 'o', 'U',
'u']

          e
                 VogaisCaixaB := ['a', 'e', 'i', 'o', 'u']
                 VogaisCaixaA := ['A', 'E', 'I', 'O', 'U'1

 ento

        VogaisCaixaB + VogaisCaixaA = Vogais
        Vogais - VogaisCaixaA = VogaisCaixaB

        Os conjuntos podem tornar a codificao muito mais clara - e at
mesmo mais curta - ao evitar declaraes confusas sobre caixas. Por
exemplo, uma linha de  cdigo como
        
        if SeuCaractere in Vogais then ...

 mais clara e mais curta do que seria a declarao sobre caixas
correspondentes.

Tabela 5.2 Operadores Utilizados com Conjuntos.

        Operador - Funo
        =(igualdade) - Utilizado para determinar se dois conjuntos so
iguais. Devolve um resultado Booleano (Verdadeiro/Falso).
        < > (no igual) - Utilizado para determinar se dois conjuntos
no so iguais. Devolve um resultado Booleano (Verdadeiro/Falso).
        <=(incluso) - Verifica se todos os elementos de um conjunto se
encontram (incluidos) em outro. Tambm devolve um resultado Booleano
(Verdadeiro/Falso).  (Essa condio normalmente  chamada de ser um
subconjunto.)
        >=(conteno) - Verifica se um conjunto contm todos os
elementos de outro. (Isso com freqncia  chamado de ser um
super-conjunto.)
        +(unio) - Devolve um conjunto formado de todos os elementos dos
dois conjuntos
        *(interseo) - Devolve um conjunto formado pelos elementos
comuns aos dois conjuntos
        -(diferena de conjuntos) - Devolve um conjunto obtido pela
remoo dos elementos de um conjunto do outro
        in - Testa para ver se o valor de uma expresso ou constante se
encontra em um conjunto. Devolve um valor Booleano (Verdadeiro/Falso).

Vetores

Voc utiliza um vetor varivel (a maioria das pessoas simplesmente dizem
"um vetor") quando precisa reservar espao na memria do computador para
um grupo de valores  relacionados que so do mesmo tipo de dados. Voc
pode utilizar vetores para armazenar strings grandes assim como listas e
tabelas. Os vetores so o primeiro exemplo  que voc viu daquilo que 
chamado de tipos estruturados em Pascal. A caracterstica que define um
tipo estruturado  que voc pode manipular o objeto como um todo  e
trabalhar com os elementos individuais dele. Um tipo estruturado no
pode ocupar mais do que 65.520 bytes de memria.

Vetores Unidimensionais

Para o Delphi, um vetor unidimensional (freqizentemente chamado
simplesmente de lista)  apenas uma coleo de valores, cada um dos
quais  identificado por duas  coisas:

        *O nome da lista.
        *A posio do item na lista.

        Por exemplo, vamos supor que voc esteja escrevendo um programa
que permite ao um usurio entrar com uma "lista de compromissos" no
comeo de cada dia. Provavelmente  voc optaria por armazenar a
informao em uma lista. Voc poderia chamar essa l Compromisso[2], e
assim por diante.
       O nmero entre colchetes  normalmente chamado de subscrito ou
ndice. O termo "subscrito" vem da matemtica, onde o item M[5]
normalmente seria escrito como  M5. Para o Delphi, M5  o nome de uma
nica varivel, mas M[5]  o nome de um elemento em

DICA VISUAL BASIC: Lembre-se de que os ndices de vetores utilizam
colchetes, e no parnteses.

        Para utilizar uma lista, ela tem que ser declarada primeiro.
Aqui esto alguns exemplos de como ficariam as declaraes para duas
listas, uma para strings  e outra para inteiros:
       
        var
             NomesEstados: arrayfl..50) of String;
             FaixaDelnteiros: arrayf-100..1001 of Integer;


DICA: Normalmente voc deveria criar um tipo para cada vetor, em lugar
de declarar de forma implcita o tipo como parte da declarao da
varivel. Isso torna possvel  passar esses vetores como parmetros a um
subprograma (veja a seguir).

        O formato geral da sintaxe para declarar um vetor 
     
        NomeVetor: array[Tipo ndice] of Tipo;

onde Tipo ndice  qualquer tipo de dado ordinal (ou subconjunto de um
ordinal), exceto Longint.
      Voc tambm pode ter vetores de constantes tipificadas quando quer
especificar os valores iniciais (e fazer com que os valores persistam -
sejam variveis  estticas, como com constantes do tipo comum). Um
exemplo disso seria
       
                NotasdeCorte: array of Integer = (90, 80, 70, 60);

        (Observe os parnteses para os valores iniciais.)
      
        Strings no Delphi so, na verdade, vetores de caracteres
comeando em zero e continuando at a dimenso da string. Por exemplo,
se
       
        var
             s: String[80];

ento s  realmente armazenado em um vetor de caracteres do seguinte
tipo
       
        array[0..80] of Char

A posio de ordem 0  utilizada para armazenar o tamanho da string. A
string em si seria armazenada em s[1] para o primei;ro caractere, s[2]
para o segundo e assim  por diante. Pelo fato do Delphi no distinguir
entre um vetor de################################ ### ###########
########################################################################
###
###!###"###&###%###'###(###)###*###+###,###-###.###/###0###1###2
###3###4###5###6###7###8###9###:
###;###<###=###>###?###@###A###B###C###D###E###F###G###H###I###J###K###L
###M###N###O###P###Q###R###S###T###U###V###W###X###Y###Z###[###\###]###


 caracteres e uma string, voc pode
isolar caracteres individuais  de uma string da mesma forma que isola o
elemento de um vetor. Por exemplo, uma linha de cdigo como:
       
 s I371:= ' ';

mudaria o 37u caractere da string para um ponto de exclamao.
       Voc pode contomar as limitaes de 255 caracteres em uma string
noDelphi formando um vetor de caracteres maior do que 255. Entretanto,
conforme voc ver  na seo sobre "Strings de Terminao Nula e Pchar"
mais adiante, neste captulo, voc se sa ndice nulo (voc utilizar o
espao extra para controle). Por exemplo, se voc precisa de uma string
que contm 20.000 caracteres, utilize
         TextoNoMemo: array[0..20000] of Char;

o que aloca 20.001 espaos (um espao para controle) em vez de utilizar
um ndice de 1 at 20.000.

 CUIDADO: Se voc comea a manusear strings muito grandes, o
gerenciamento de memria torna-se mais importante. Veja a seo
"Ponteiros", neste captulo, para obter  mais informaes sobre isso.

Listas de Strings

O Delphi mantm muita informao a respeito de certos componentes, como
os itens em uma lista ou caixa combinada, as fontes disponveis ou as
linhas de texto em  uma caixa de memo, naquilo que  chamado listas de
strings. Essencialmente, uma lista de strings  um vetor de strings
mantidas pelo Delphi, de modo que so fceis  de manusear.

  DICA:Voc pode dizer se uma propriedade est armazenada em uma lista
de strings verificando se h um TString na coluna de valor do Object
Inspector. (TString   o nome do objeto lista de strings. Haver mais
sobre o objeto Tstring no Captulo 6. Voc ve
 
Por exemplo,  possvel copiar uma lista de strings em outra
simplesmente por meio de uma declarao de atribuio. Se voc quer que
as linhas de uma caixa memo  apaream na caixa combinada, a linha de
cdigo mostrada aqui seria suficiente!
       
 ComboBox1:ltem := Memo1.Lines;

        (Tanto a propriedade Items de uma caixa combinada como a
propriedade Lines de um campo memo so do tipo TString. )


DICA: O Delphi tem a aptido para manter uma lista de objetos em
paralelo com uma lista de strings. Uma utilizao comum disso , por
exemplo, associar uma figura  a cada item em uma lista de strings. Para
mais informaes a esse respeito, veja as entradas de ajuda on-line em
"Adding Objects to a String List" e "Adding Graphical  Objects to a
String List".

         O que segue  uma pequena discusso a respeito das operaes
mais comuns nas listas de strings.
        Strings - Qualquer lista de strings tem uma propriedade Strings
que  melhor encarada como um vetor das strings a serem armazenadas. A
lista comea em zero. Por  exemplo, uma caixa memo mantm as linhas que
h nela em uma lista de strings chamada (naturalmente) de Lines. Assim
        Memo 1. Lines. Strings [ 1 ]

 a segunda linha da caixa memo. (Memol.Lines.Strings[0]  a primeira.)

NOTA: Uma vez que String  a propriedade padro de uma lista de strings,
voc na verdade no precisa utiliz-la. O compilador tambm compreende
uma linha como Memo1.Lines[1]  como sendo a (segunda) linha no
componente Memo.

Count - A propriedade Count fornece-lhe o nmero de itens na lista. Isso
significa que o ltimo item em uma lista de strings tem um ndice
Count-1. Por exemplo:
          Memo1.Lines.String[Count-11 {ltima linha da caixa);

ou
         Screen.Fonts.Count {nmero de fontes de tela disponveis);

         Em geral, uma vez que as listas de string so de base 0, para
iterar todos os itens utilize a seguinte sintaxe:
        for Index :=0 to Str-ing.List.Count -1 do
        IndexOf - Essa funo pega uma string e devolve o ndice de onde
a string est localizada. Se a string no  encontrada, o Delphi devolve
-1. Por exemplo:
        if Memol.Lines.lndexOf('String de teste') = -1 then
             ShowMessage('String no encontrada')
         else
             ShowMessage('String encontrada'); 

Add - O mtodo Add coloca uma string no final de uma lista de strings se
a propriedade Sorted  False, e na posio de ordenao correta se a
propriedade Sorted   True. Por exemplo, a propriedade Items em uma
caixa de lista  uma lista de strings que contm os itens. Se voc
quisesse acrescentar os nomes dos presidentes  em uma caixa de lista, o
cdigo poderia ficar assim:
        PresidentListBox.Item.Add('George Washington');
         PresidentListBox.Item.Addl'John Adams');

       Voc tambm pode utilizar Add como uma funo. Nesse caso, ela
vai lhe informar o ndice no qual a string foi colocada. Por exemplo:
          ndicedaltimaEntrada:= ListBox1.Item.Add('Esta  a ltima
entrada');

Insert - O mtodo Insert permite-lhe acrescentar uma entrada em um
determinado lugar em uma lista de strings no-ordenada. Por exemplo, se
voc deixasse de fora  o nono presidente dos Estados Unidos, William
Henry Harrison (um engano comum, j que ele foi presidente apenas por
nove meses), voc utilizaria o seguinte cdigo.  (Lembre-se que as
listas de strings so de base 0, de modo que a entrada nove est no
ndice 8. )
     President.ListBox.lnsert8, 'William Henry Harrison');

Em geral, a primeira entrada  um inteiro para o ndice e a segunda  a
string a ser inserida.
     Move - O mtodo Move permite-lhe rearranjar os itens em uma lista
de strings. Por exemplo, para tornar o dcimo item em uma caixa de lista
o primeiro, utilize
     ListBox1.Items.Move(9, 0);

Em geral, a primeira entrada  o ndice do item a ser movido; a ltima
entrada  o local para onde ele  movido.
        Clear,Delete - O mtodo Clear apaga todas as strings da lista. O
mtodo Delete pega um determinado ndice e apaga aquela entrada. Por
exemplo,
        PresidentListBox.Items.Delete(0);

apagaria o nome de George Washington.

Vetores de Vrias Dimenses

Voc tambm pode ter vetores com mais do que uma dimenso; normalmente
so chamadas de matrizes. Da mesma forma que a lista de dados levaram a
uma nica subscrio  (vetores de uma dimenso), tabelas de dados levam
a subscries duplas (matrizes de duas dimenses). Por exemplo, vamos
supor que voc queira armazenar uma tabela  de multiplicao na memria
- como uma tabela. Voc poderia fazer isto como:

var
             I, J: Integer;
             TabelaMulti: array[1..12,1..12] of Integer;
        begin
             for I :=1 to 12 do
             for J :=1 to 12 do
                TabelaMulti[I, J] := I"J;
        end;

        Para determinar o nmero de itens que h em uma matriz,
multiplique o nmero de ndices. A declarao da varivel acima separou
144 entradas ( 12 * 12) e  h 12 linhas e 12 colunas. Em geral, o nmero
de entradas  o produto dos nmeros especifica
       Quando voc utiliza um vetor de duas dimenses para representar
uma matriz, a conveno matemtica consiste em referir-se  primeira
entrada como sendo o  nmero de linhas e  segunda, como o nmero de
colunas. De acordo com essa conveno, diramo coluna, antes de
prosseguir para a prxima linha. (Observe que isso  o contrrio da
conveno utilizada pelo Delphi para a propriedade Cells de uma grade.)

NOTA: Utilizar mais do que duas dimenses em um vetor  possvel, mas
bastante incomum.




Registros

Vamos supor que voc utilize trs vetores de uma dimenso para as
informaes a respeito de 100 funcionrios de uma empresa. O primeiro
vetor  para os nomes, o  segundo para os salrios, e o terceiro para o
nmero da carteira de identidade. Cada lista teria ndices que combinam,
e seria necessrio muito cdigo adicional  para manter todas essas
listas em paralelo. A maneira de contornar esse trabalho adicional 
utilizando uma estrutura nova denominada registro. Essencialmente, um
registro  um tipo novo que pode misturar  qualquer um dos tipos do
Delphi (incluindo qualquer tipo que voc possa criar). O cdigo no
exemplo mostrado aqui define o tipo Record para o nosso funcionrio
hipottico:

 type
              InfoVital = Record
                 Nome: String;
                 Salrio : Longint;
                 RG: Stringfl2];
         end;

        Normalmente as pessoas dizem que esse registro tem trs campos
(Nome, Salrio e RG so partes deste registro). Assim que voc
estabelecer o tipo de registro  ento, a partir desse ponto do programa,
 possvel declarar uma varivel como sendo do t para variveis como
qualquer um dos tipos internos ao Delphi, como Integer ou String. 
evidente que para realmente criar uma varivel como InfoVital, voc tem
que  declarar o seguinte:
       
         var
            Seu Nome: InfoVital;

Assim que voc tiver um registro, utilize um ponto para separar os
campos desse registro:
         SeuNome.Nome :='Howard';
        SeuNome.Salrio :=100000;
        SeuNome.RG :='36.789.987-0';

        A palavra-chave with que voc aprendeu, e que opera em
propriedades aninhadas, tambm funciona para registros, conforme voc
pode ver no cdigo a seguir.
         with SeuNome do
             begin
                 SeuNome.Nome :='Howard';
                 SeuNome.Salrio :=100000;
                 SeuNome.RG :='36.789.987-0';
            end;

        Voc tambm pode estabelecer um vetor de variveis de registro:

        Empregados: array f1..100] of InfoVital;

Da mesma forma que com matrizes e outras variveis, tambm  possvel
ter digitados os registros de constantes onde voc inicializa o registro
separando as entradas,  como no prximo exemplo:
       
 const
              RegistrodoChefe: InfoVital = (Nome: 'Big Cheese';
Salrio:1000000;
             RG: '1.101.001-1');

Uma vez que o tipo Record tem a mesma legitimidade que qualquer outro
tipo Delphi, voc pode fazer com que o componente de um registro seja
ele mesmo um registro.  Por exemplo, voc poderia fazer um tipo
RegistroDe-Salrio para controlar salrios mensais juntamente com o
salrio do ano anterior:
         type
          RegistroDeSalario = record
             SalEmJan: Integer;
             Sal EmFev: Integer;
             SalEmMar: Integer;
             SalEmAbr: Integer;
             SalEmMaio: Integer;
             SalEmJun: Integer;
             SalEmJul: Integer;
             SalEmAgo: Integer;
             Sal EmSet: Integer;
             SalEmOut: Integer;
             SalEmNov: Integer;
             SalEmDez: Integer;
             SaINoAnoAnt: Longlnt;
        end;

        Agora voc pode estabelecer um registro de registros:

        type
          InfoVitalExpandida: record
          Nome: String;
          Salrio: RegistroDeSalrio;
          RG: String[12];
        end;

 Evidentemente que preencher todas as informaes necessrias para um
nico registro agora  muito mais difcil e voc vai apreciar ainda mais
a palavra-chave with.  Tambm fica um pouco confuso referir-se 
informao em registros como InfoVitalExpandida Depois de utilizar um
cdigo como o seguinte:
         var
          DadosGary: InfoVitalExpandida;

para especificar uma varivel desse tipo novo, utilize uma declarao
como
        ShowMessage(IntToStr(DadosGary.Salrio.SaINoAnoAnt)

para exibir informaes que h em um dos campos aninhados.

DICA PASCAL: O Delphi sustenta registros variveis, mas voc normalmente
se sai melhor utilizando um objeto herdado. (Veja o Captulo 6.)
 
Ponteiros

Embora os ponteiros sejam considerados um conceito delicado, voc pode
torn-los muito mais concretos se lembrar sempre de que:

*Tudo o que  utilizado em um programa  armazenado em algum lugar na
memria do computador. *Um ponteiro para aquele item simplesmente
fornece (aponta para!) ao compilador aquela posio de memria.

Da mesma forma que com todos os tipos Pascal, voc tem de declarar um
ponteiro antes de poder utiliz-lo em seu programa. A sintaxe utiliza um
circunflexo ( ^ ).  Na maioria das vezes, os ponteiros em Delphi apontam
para um determinado tipo. Por exemplo:

Ponteirolnt: ^Integer;
         PonteiroReal: ^Real;

        Uma vez que o ponteiro  um endereo n a memria, voc tem de
informar ao compilador a posio daquele endereo. Isso  feito com o
operador @ (ou de  maneira equivalente, com a funo Addr).
         type
          Foo: Integer;
          PointerToFoo: ^Integer;
        begin
          Foo := 2;
          PointerToFoo := @ Foo {ou addrFoo};

        J que Foo  uma varivel, seu valor tem de ser guardado em
algum lugar. Depois dessas linhas de cdigo, PointerToFoo conteria
aquele endereo. Em particular,  isso significa que o valor de
PointerToFoo no  2;  o endereo de memria onde o valo
       Ponteiros sem atribuio so perigosos. A sua utilizao pode
levar a erros de programa espetaculares. Isso acontece porque os
ponteiros deixam voc trabalhar  direto com posies de memria e se
inadvertidamente voc escrever em uma posio de mem das hipteses, ou
um travamento de sua mquina, no pior caso. Por esse motivo, voc
deveria inicializar um ponteiro sempre com um valor especial nil.
(Utilizar nil  significa que o ponteiro no est atualmente se referindo
a uma determinada posio de memria.) Assim, quando voc utilizar um
ponteiro, verifique primeiro se   nil.
         if Ponteirolnt = nil then
          (no faa nada}
        else

DICA PASCAL: Embora o Delphi sustente a funo Ptr, que lhe permite
trabalhar com uma posio de memria absoluta, a utilizao de uma
posio de memria absoluta   uma idia muito ruim em programao
Windows!

         Uma vez que voc tem um ponteiro, voc utiliza o circunflexo
depois dele para obter os dados naquele local. Por exemplo:
        PointerToFoo^ + Foo = 4;

mas
         PointerToFoo + Foo;

no faz sentido - voc no pode acrescentar um ponteiro a um inteiro.
        Voc tambm pode apontar para matrizes e registros. Se
especificar
         type
          Vetorlnteiro: array: [1..100) of Integer;

ento
         var
          ExempIoDeVetor: Vetorlnteiro;
          PonteirodeVetor: ^Vetorlnteiro;

fornece para voc um vetor inteiro e um ponteiro para um vetor inteiro.
Para realmente "apontar para um ponteiro", voc utiliza novamente o
operador @:
         PonteiroVetor := @ExempIoDeVetor;
         PonteiroVetor^[99) := 37 {deixa a entrada 99 = a 37}

        A possibilidade de ter ponteiros para vetores e registros
facilita muito a especificao de estruturas de dados complicadas como
listas ligadas e rvores.  (Se voc no sabe o que so, ento consulte
qualquer livro sobre estrutura de dados.) Eis o
       
 type
              ProximoltemLista: ^ItemLista;
              ItemLista = record
                 Primeiroltem: String;
                 Segundoltem: String;
                 ProximoRegistro: ProximoltemLista;
              end;

A idia, evidentemente,  que voc possa utilizar o ponteiro contido no
campo ProximoRegistro para lhe dar o (endereo) do prximo item ligado.

NOTA: Esse  o nico caso em que voc pode referenciar um identificador
antes de fazer sua declarao.

Ponteiros e Gerenciamento de Memria

At agora utilizamos os ponteiros apenas para fazer referncia a locais
de objetos que j existem. O poder real dos ponteiros vem da aptido de
alocar memria durante  a execuo do programa. A maneira mais fcil
para fazer isso  com o procedimento New. Eis um exemplo de como
utilizar esse procedimento:
         var
          Ponteirodelnteiro: ^Integer;
        begin
          New(Ponteirodelnteirol;
          Ponteirodelnteiro^ := 37;
        end;

        Assim que voc informa ao Delphi para reservar memria aos dados
do ponteiro utilizando o procedimento New,  possvel utilizar uma linha
como PonteirodeInteiro  ^ .= 37; para preencher a posio de memria com
o valor correto.
       Se voc alocar memria utilizando New, dever ter certeza de
liberar a memria com a utilizao do procedimento Dispose. (Normalmente
isso  feito em um bloco  try/finally, conforme descrito no Captulo 7.
) A sintaxe para o procedimento Dispose 
          Dispose(ponteiro);

         Por exemplo, se voc alocar a memria duas vezes para a mesma
varivel sem dispor dela primeiro, nunca poder recuperar a memria
reservada na primeira  vez.

NOTA:  extremamente importante que voc sincronize a utilizao de New
e Dspose.

DICA PASCAL: O Delphi tambm suporta o par de procedimentos MarWRelease
para alocao de memria.

Alocando e Desalocando Blocos de Memria

Os procedimentos New e Dispose so utilizados quando voc quer alocar
espao para um nico objeto. Se quiser alocar (e depois desalocar) um
bloco de memria para  um objeto, como uma matriz que pode variar de
tamanho durante o projeto, voc utiliza o par de procedimentos Getmem e
Freemem.

DICA: Antes de alocar memria, verifique se h memria suficiente
utilizando a funo MaxAvail.

(O mximo de memria que voc pode alocar  64IC = 65.528 bytes.)

NOTA: Normalmente voc desalocar a memria no bloco finally, conforme
descrito no Captulo 7.

Eis um exemplo de como utilizar Getmem:

         type
           StringGrande: array [0...20000] of Char;
         var
           PonteiroString: ^StringGrande;
         begin
           Getmem(PonteiroString, 20001);
         end;

NOTA: A memria para as variveis  armazenada em uma parte especial da
memria reservada pelo Delphi e chamada de heap e, infelizmente,  bem
possvel que o heap  se esgote antes que a memria seja realmente
esgotada. (O Windows tambm mantm seu prprio heap.)  possvel tornar
o heap local do Delphi maior utilizando a pgina  Linker da caixa de
dilogo Project Options. Se voc precisa redefinir os padres do Delphi
para o heap, consulte a ajuda on-line para mais informaes sobre a
maneira  como o Delphi gerencia o heap.

Strings de Terminao Nula e PChar

A estrutura de uma string normal no Delphi  simplesmente uma seqncia
de bytes. O problema  que o Delphi utiliza o primeiro byte dessa
seqncia para informar  quantos caracteres esto armazenados. J que um
byte pode conter apenas os inteiros de 0 at 255, isso limita o nmero
de caracteres em uma string normal em 255.
       A Verso 7 do Turbo Pascal (seguindo a orientao do C)
acrescentou um tipo novo chamado de string de terminao nula que
(finalmente) venceu essa limitao.  Agora voc pode tratar at 65.535
caracteres de uma nica vez. O Delphi tambm Ihe permit uma seqncia de
at 65.535 caracteres que termina com um ASCII 0 (#0). (O Delphi utiliza
o caractere ASCII 0 para determinar o limite da string.)
       No h essencialmente nenhuma diferena entre uma string de
terminao nula e um vetor de caracteres do formato:
vetor[O..NumeroDeCaracteres] de Char, onde  o final da string  marcado
por um ASCII 0.

NOTA: Assegure-se de que a opo de compilador da sintaxe estendida (que
est disponvel na pgina Compiler da caixa de dilogo Project Options)
est ativada antes  de voc trabalhar com strings de terminao nula.
(Ela est ativada por padro.)

O Delphi permite-Ihe evitar a necessidade de ficar mexendo com vetores
de base zero ao tratar com strings de terminao nula pela utilizao do
tipo predefinido  PChar. voc pode pensar em PChar como sendo um
ponteiro para uma string de terminao nula. (O que ele realmente faz 
apontar para o primeiro caractere na string  de terminao nula. Em
seguida, o Delphi utiliza ASCII 0 para encontrar o fim da string.)
       Na prtica, PChar comporta-se como se fosse declarado para se
parecer com o seguinte:
        type
          StringGrande: array [0..65534) of Char;
          Pchar: ^StringGrande;

        Se a opo de sintaxe estendida est ativada, voc pode manusear
strings utilizando PChar de forma muito parecida com a que voc manuseia
strings comuns.  Voc pode at mesmo atribuir uma string comum (limitada
em 255 caracteres) a uma varivel PC
         var
          PonteiroCar: PChar;
          VetorDeCar: array[0..10001 of Char;
        begin
          PonteiroCar := VetorDeCar[os dois apontam ao mesmo local da
memria};
          StrPCopy(PonteiroCar, 'Estou atribuindo uma string a um
PChar'I;
          ShowMessage ('O oitavo caractere  ' + PonteiroCar[7];

DICA: StrPCopy permite-Ihe converter uma string normal em uma string de
terminao nula, StrPas reconverte uma string de terminao nula
(suficientemente pequena)  em uma string normal. Para mais informaes
sobre funes que funcionam com PChar, veja o tpico "String Handling
Routines (Null-terminated)" na ajuda on-line. (Embora  talvez elas
tenham de trabalhar com ponteiros, muitas das funes normais para
manuseio de strings, como Pos, tm contrapartes PChar.)

Funes e Procedimentos

A diferena normal entre uma funo e um procedimento  que uma
funopode devolver um valor e um procedimento geralmente no far isto.

DICA PASCAL: No Delphi, as diferenas entre procedimentos e funes
tornaram-se um pouco mais sutis do que eram no Pascal "padro". Um
procedimento  sempre chamado  de uma declarao independente. Uma
funo normalmente  chamada como parte de uma expresso, de modo que
pode devolver um valor, mas tambm pode ser chamada como  um
procedimento (onde o valor de retorno  ignorado quando voc est com a
opo de sintaxe estendida ativada).

        Como voc viu no ltimo captulo, a informao com que uma
funo ou um procedimento trabalha  chamada de parmetro ou argumento.
Por exemplo, vamos olhar  mais de perto a funo InputQuery que voc viu
no ltimo captulo. A sua sintaxe na ajuda 
         function InputQueryconst ACaption, APrompt: String; var
Value:String: Boolean;

        Conforme indicado por esse exemplo, o tipo de parmetro segue
seu nome e dois-pontos. Mostra tambm que voc pode utilizar vrios
parmetros do mesmo tipo  separando-os com vrgula. Declaraes de
parmetros so separados entre si por ponto-e-vrg - todos do tipo
String.
       ACaption e APrompt so o que chamamos parmetros constantes
(indicados pela palavra-chave const). Os parmetros constantes no podem
ser alterados pela funo  ou procedimento. O parmetro Value por outro
lado  passado como um parmetro var (ou va
       Com um parmetro var, voc pode fazer com que mudanas a ele
persitam simplesmente por t-lo do lado esquerdo de uma declarao de
atribuio.

NOTA: Os nomes dos parmetros em uma funo ou procedimento so
reservas-de-posio. Embora tenham de seguir as convenes para os nomes
de variveis Delphi, no  tm existncia independente.

Procedimentos de eventos tambm podem utilizar parmetros const ou var.
Por exemplo, considere o procedimento de evento OnICeyPress cujo
cabealho para uma caixa  de edio pode ter a seguinte aparncia:
         procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char;

        Quando o usurio pressiona uma tecla, o cdigo ASCII do
caractere  enviado como o valor do parmetro ICey. Uma vez que  um
parmetro varivel (var), voc  pode fazer mudanas nela dentro do
procedimento de evento e fazer com que sejam refletidas como a seguinte:

        if Key = '!' then Key = #0;

o usurio ter quaisquer pontos de exclamao que digitar apagados.

 NOTA: H dois outros procedimentos de eventos de tecla disponveis.
Eles lhe permitem tratar de teclas tais como teclas de controle ou
combinao de teclas que  no tm cdigos ASCII padro. Verifique a
ajuda on-line que diz respeito a OnKeyDown e OnKeyU

DICA PASCAL: Por motivos de compatibilidade, o Delphi ainda suporta os
antigos parmetros value que indicam um parmetro passado por valor
(isto , o compilador  faz uma cpia da varivel e assim memria e
velocidade so itens a considerar). Entretanto, os parmetros const tm
todas as vantagens de velocidade dos parmetros  var e nenhuma das
desvantagens de memria dos parmetros value. So utilizados pelas
funes e procedimentos internos em lugar dos parmetros value mais
antigos.

       Os parmetros var so passads por referncia (isto , o
compilador passa a posio. de memria da varivel). Ocorre que isso
tambm  o que acontece para  parmetros const, mas com um passo
adicional adiante. O que o compilador faz  verificar se  compilador
gera um erro de compilao. Isso evita o trabalho adicional que est
envolvido na realizao de uma cpia, como seria feito se voc
utilizasse o parmetro  value.

NOTA: Como  mostrado pelos prprios procedimentos de eventos, voc pode
ter parmetros que so objetos Delphi. Voc tambm pode chamar um
procedimento de evento  diretamente em vez de permitir que ele seja
acionado por um evento (por exemplo em uma verso de demonstrao). Veja
no Captulo 6 mais a respeito destas duas tarefas.
 
Subprogramas Internos

A Tabela 5.3 fornece descries curtas dos subprogramas mais comuns que
voc ainda no viu. (Para rotinas de manuseio de arquivos, veja o
Captulo 9.) J que h  centenas de subprogramas internos, sugerimos que
voc trabalhe com a ajuda on-line para obter maiores detalhes. (Tente
iniciar no tpico "Procedures and Functions  Categorial List".)

Tabela 5.3 Os Subprogramas Internos mais Comuns.

Subprograma  Descrio

Abs - Fornece o valor absoluto do argumento. AppendStr. - Adiciona uma
string a outra string. ArcTan - Resulta o arco tangente do argumento em
radianos. Chr - Resulta um caractere com um cdigo ASCII/ANSI
especfico. CompareStr - Realiza uma comparao sensvel--caixa de duas
strings. CompareText - Realiza uma comparao no-sensvel--caixa de
duas strings. Concat- Junta uma seqncia de strings. Copy - Faz uma
cpia de parte (uma substring) de uma string. Cos - Resulta o cosseno do
argumento (o argumento  presumido como sendo em radianos).

 Tabela 5.3 Os Subprogramas Internos mais Comuns (continuao).

Subprograma - Descrio

Date - Fornece a data atual conforme armazenado no relgio do sistema.
DateTimeToStr - Converte um valor do formato de horrio para uma string.
DateToStr - Converte um valor do formato de data para uma string.
DayOfWeek - Resulta o dia atual da semana. Delete - Remove uma substring
de uma string. Exp - Eleva e (a base dos logaritmos naturais, e vale
aproximadamente 2.718...) a uma potncia especificada pelo argumento.
Frac - Resulta a parte fracionria do argumento. Insert - Insere uma
string em outra string. Int - Resulta a parte inteira do argumento,
devolve algo do tipo Integer. IntToHex - Converte um inteiro em uma
representao hexadecimal. Length - Resulta o comprimento de uma string.
Ln - Resulta o logaritmo natural do argumento. LowerCase - Muda a string
para minsculas. Now - Resulta a data e horrio atuais conforme
armazenado no relgio do sistema. Pi - Fornece a voc o valor de  com
14 casas decimais (3,14159...). Pos - Permite-lhe procurar pela posio
de uma substring dentro de uma string. Random - Devolve um nmero
(pseudo)-randmico. Randomize - Utilizando o relgio de sistema reinicia
o gerador interno de nmeros randmicos. Round - Arredonda um valor do
tipo Ponto Flutuante (Floating Point) para resultar em um valor do tipo
Inteiro (Integer).

Tabela 5.3 Os Subprogramas Internos mais Comuns (continuao).

         Subprograma - Descrio 

Sin - Resulta o seno do argumento (o argumento  presumido como sendo em
radianos). Sqr - Fornece uma maneira rpida de elevar um argumento ao
quadrado. Sqrt - Fornece a maneira mais rpida para extrair a raiz
quadrada do argumento. StrPas - Converte uma string de terminao nula
em uma string de estilo Pascal. Pode ser utilizado apenas se a string de
terminao nula tem menos do que 256 caracteres. StrPCopy - Copia uma
string de estilo Pascal em uma string de terminao nula StrToDate -
Converte uma string em um formato de data. StrToDateTime - Converte uma
string para um formato data/horrio. StrToTime - Converte uma string
para um formato de horrio. Time - Fornece o horrio atual conforme
mostrado no relgio do sistema. Trunc - Trunca um valor Floating Point
(Ponto Flutuante) e devolve um valor do tipo Integer (Inteiro). UpCase -
Converte um caractere em maisculo. UpperCase - Coloca a string dada em
maisculas.

 NOTA: Conforme indicado pela Tabela 5.3, h vrios subprogramas
internos (como Round) que obtm argumentos de um tipo e devolvem valores
de outro tipo. Voc achar  estes subprogramas de converso de tipo
muito teis em uma linguagem fortemente tipificad

 Utilizando a API do Windows

Embora elas no sejam, estritamente falando, funes construdas no
Delphi, voc tambm tem acesso total s mais de 600 funes
especializadas que formam o prprio  Windows. Essas funes normalmente
so chamadas de funes de Interface de Programao de Aplicativos
(API).

CUIDADO: Se voc utilizar as funes API de forma descuidada, seu
sistema vai travar e voc ser obrigado a reinicializar. Sugerimos com
nfase que voc ative as  opes Autosave na pgina Preferences da caixa
de dilogo Environment Options antes de experimentar as chamadas do API
de Windows.

Na maioria das vezes, o Delphi  suficientemente rico em funcionalidade
para que voc no precise se preocupar com as funes API. Mas algumas
tarefas, como conhecer  qual "chip" (como 80286 ou 80386) um computador
est utilizando ou se um computador tem um co-processador numrico (como
um 80287 ou 80387), tm de ser feitas com  uma funo API. Voc pode at
mesmo utilizar uma funo API ExitWindows, para terminar o prprio
Windows. (Entretanto, voc deve estar ciente de que se precisar
utilizar extensivamente a API do Windows, prepare-se para um estudo
demorado  as referncias padres para a API giram em torno de 2000
pginas! )

DICA: O Delphi  fornecido com uma verso das referncia Windows API
adaptada para a sintaxe do Delphi (em lugar da sintaxe C). Voc pode
copiar e colar os cabealhos  das funes API livremente dentro de seu
programa.

Uma das funes API teis mais simples  a funo GetWinFlags, que
devolve um inteiro longo. Voc pode utilizar esse inteiro para
determinar que tipo de processador  o computador est utilizando. Eis o
exemplo do cdigo que voc precisa para fazer isso:
        var
          Analise: Longint;
        begin
          Analise := GetWinFlags;
          if (Analise and WF 50x87) = WF 80x87 then
             ShowMessage/'Voc tem um co-processador matemtico');
          if (Analise and WF CPU2B6) = WF CPU286 then
             ShowMessage('Voc ainda tem um chip 286?');

        Como outro exemplo da utilizao da funo Windows API,
considere a funo GetSystemMetrics. A sintaxe dessa funo  assim:

        function GetSystemMetrics(Index: Integer): Integer;

        Nesse caso, voc envia para essa funo um valor inteiro que diz
a ela qual a informao que voc quer que seja relatada. (A maioria das
constantes que voc  precisa esto disponveis como constantes internas
no Delphi - verifique a existncia del muito detalhadas a respeito do
sistema utilizado pelo seu aplicativo. Por exemplo, voc pode utilizar
essa funo API para descobrir se o Windows est informando  que um
mouse est sendo utilizado. Aqui est um fragmento que faz isso:

        if GetSystemMetrics(SM MOUSEPRESENT)<> 0 then
          ShowMessage('Voc tem um mouse.');

NOTA: As chamadas Windows API com freqncia requerem que voc envie
para elas as alas do objeto. No Delphi esse  o valor da propriedade
(de processamento), chamada,  naturalmente, de Handle. A propriedade
Handle est disponvel para todos os componentes colocados em janelas.




Funes e Procedimentos Definidos pelo Usurio

Como com qualquer linguagem de programao sofisticada, o Delphi
permite-lhe desdobrar o cdigo de seu programa em pedaos
administrveis. Da mesmaforma que o Visual  Basic (mas ao contrrio de
C), o Delphi distingue entre as funes, que devolvem valores, e
procedimentos, que no devolvem. No Delphi, as pessoas se referem aos
subprogramas quando querem falar a respeito de funes e de
procedimentos ao mesmo tempo. A terminologia  til se nos ajuda a
lembrar que, para todos os propsitos  particulares, as funes e os
procedimentos se comportam como miniprogramas. Em particular, eles podem
ter seu tipo prprio, constante, constantes tipificadas e  declaraes
de variveis definidas em seu interior. Eles podem at ter subprogramas
prprios aninhados dentro deles. (O motivo de se aninhar' um subprograma
dentro  de outro se deve s regras de escopo para os subprogramas. Um
subprograma aninhado  considerado local ao subprograma container e no
pode ser utilizado por outras  partes do programa. Igualmente, as
variveis declaradas em um subprograma aninhado so locais quele
subprograma.)

NOTA: Quanto um programa deve ser modulado , evidentemente, uma questo
de gosto. Ns gostamos de manter os procedimentos de eventos e
subprogramas com o tamanho  de uma tela aproximadamente.

        Por exemplo, aqui est uma funo que conta o nmero de vezes
que um caractere aparece em uma string e devolve este valor (inteiro):

        function ContaOcorrencias(const Foo: string; const QualCaract:
Char): Integer;
       var
         i, Cont, TamString: Integer;
       begin
         TamString := Length/Foo);
         Cont := 0;
         for i := 1 to TamStrinng do
             begin
              if foo[i] = QuaICaract then Cont := Cont + 1;
             end;
         ContaOcorrencias := Cont;
       end;

        A idia dessa funo ilustra muitos conceitos padres. Primeiro,
observe o cabealho de funo:

      function ContaOcorrencias(const Foo: string; const QuaICaract:
Char): Integer;

         Um subprograma tem de comear com um cabealho. O cabealho
comea especificando se  uma funo ou um procedimento. O cabealho
tambm tem que dar nome  ao subprograma e a uma lista de parmetros. O
nome de um subprograma tem de seguir as regras tipos dos ,parmetros tm
que ser declarados utilizando dois-pontos, e so separados run do outro
utilizando ponto-e-vrgula. De fato, a sintaxe geral para os parmetros
nas funes e procedimentos definidos pelo usurio  a mesma que para
subprogramas internos. Por exemplo, voc pode ter parmetros var,
parmetros const ou parmetros  value. (Para a funo ContaOcorrencias
dada acima, os parmetros so todos eles parmetros const - porque ns
no queremos que os valores originais dos parmetros  mudem.)
        As funes, uma vez que devolvam valores, tm de ter um tipo de
retorno declarado no final do cabealho. (Em nossso exemplo, o tipo de
retorno  Integer.)  Finalmente, o valor de retorno de uma funo  dado
pela atribuio (final) ao seu nome. Em

        ContaOcorrencias := Cont;

        (Voc tambm pode utilizar a varivel local Result
implicitamente definida para capturar o valor final de uma funo. Por
exemplo, acrescentar esta linha   funo acima,

        Result := Cont;

seria uma outra maneira para capturar o valor final da funo.)
      
         Como exemplo de um procedimento, vamos escrever um que pega uma
string e dois caracteres diferentes e muda todas as ocorrncias do
primeiro caractere para  o segundo. Ele pode ser assim:

         procedure MudaCaract(var Foo: string; const CaractVelho,
CaractNovo: Char );
         var
           i, TamString: Integer;
         begin
           TamString := Length(Foo);
           for i :=1 to TamString do
               begin
                if Foo[i] = CaractVelho then Foo[i] := CaractNovo;
               end;
         end;


        Observe que neste caso queremos mudar a string original, de modo
que a transformamos em um parmetro var, mas, uma vez que no queremos
mudar os outros dois  parmetros, ns os deixamos como parmetros const.

Posicionando Subprogramas

Voc coloca todos os subprogramas na seo de implementao da unidade.
Esses subprogramas podem ser utilizados (o jargo  "chamados") por
qualquer procedimento  de evento ou subprograma na mesma unidade que 
definida depois dela. (Voc pode contornar esta limitao. Veja a seo
"Recurso" mais adiante, neste captulo.  )
       Lembre-se de que a clusula uses de uma unidade diz a voc qual
unidade ela pode chamar. Entretanto, se voc quer que um determinado
subprograma em uma unidade  (digamos uma unidade denominada Unitl) seja
utilizvel pelos subprogramas em uma outra  clusula uses de Unit2
(acrescente uma Unitl  clusula uses da Unit2), voc precisa colocar
uma cpia do cabealho do subprograma na seo interface da unidade
original (Unit 1, em nosso caso).
       Os subprogramas cujo cabealho  dado na seo interface so
globais no escopo. Por exemplo, cabealhos de procedimentos de eventos
so sempre colocados na  seo interface e, dessa forma, podem ser
utilizados por outras unidades depois da modifica

Utilizando Subprogramas

Quando voc consegue chamar um procedimento de dentro de sua prpria
unidade, voc utiliza seu nome e coloca quaisquer que sejam os
parmetros necessrios entre  parnteses. Por exemplo, vamos supor que
queremos um boto de comando que mude todas as ocorrncias de "U" na
caixa Edit 1 para "W". Adicione o procedimento MudaCaractVelhoParaNovo

 definido acima da seo implementation do formulrio e utilize um
cdigo que pode ser assim:

        procedure TForm1.UParaW(Sender: TObject)
        begin
           MudaCaracVeIhoParaNovo(Ed'rtl.Text, 'U', 'W');
        end;

        Porm, se voc chama uma funo, normalmente atribui a ela um
valorou utiliza-a em uma expresso. Por exemplo:

        procedure TForm1.UParaW(Sender: TObject)
        begin
          if ContaOcorrencias(Edit1.Text, 'U') = 0 then
             ShowMessage ('Nenhum u para ser alterado')
          else
              MudaCaractVeIhoParaNovo(Editl.Text, 'U', 'W');
          end;
        end.

NOTA: Se a opo de compilao de sintaxe estendida estiver ativada,
voc pode utilizar uma funo como um procedimento e desconsiderar o
valor de retorno.

        Finalmente, se voc precisa chamar um subprograma global (um
declarado na seo interface) a partir de uma outra unidade, utilize o
nome da unidade seguido  de um ponto. Por exemplo, assim que voc
acrescentar Unit2  clusula uses de Unitl, voc  tem esta aparncia:

        Unit2.NomeDoProcedimento(parmetros)

        Por exemplo, uma vez que os procedimentos de eventos so sempre
definidos na seo interface da unidade do formulrio, voc pode chamar
um procedimento de  evento utilizando o nome dele e o nome do
componente. Se voc utilizasse uma linha de cdig

        Unitl.TForml.Button1 Click/Button1);

ento poderia chamar o procedimento de evento clique para Button 1 de
qualquer unidade que tivesse Unitl em sua clusula uses.


Passando Vetores para Subprogramas

O Delphi, seguindo o Turbo Pascal 7, permite-lhe utilizar parmetros
abertos para passar vetores aos subprogramas. Os parmetros abertos
fornecem-lhe a flexibilidade  para passar qualquer vetor a um
subprograma sem precisar declarar antecipadamente o limite do vetor.
Para utilizar um parmetro aberto em um subprograma, declare  uma
varivel na lista de parmetros para que seja do tipo mostrado na
sintaxe a seguir:
      
         NomeVetor: array of Tipo;
       
        Assim que voc tiver feito isso, poder utilizar as funes
internas Low e High para determinar o primeiro e ltimo ndices do
vetor. Por exemplo, se quisesse  escrever uma funo geral para calcular
a mdia de um vetor de inteiros, voc poderia u

        function ValorMedio(Vetorlnteiro: Array Of Integer): Real;
        var
           NumEntradas, i: Integer;
           Total: Longlnt;
        begin
          Total := 0;
          NumEntradas := High(Vetorlnteiro) - Low/Vetorlnteiro) + 1;
          for i := Low(Vetorlnteiro) to High(Vetorlnteiro) do
             Total := Total + Vetorlnteiro[I];
          ValorMedio := Total/NumEntradas;
        end;


Recurso

Recurso  um mtodo geral para resolver problemas reduzindo-os a
problemas mais simples do mesmo tipo. A estrutura geral de uma soluo
recursiva de um problema   assim:
       
       Resolva de forma recursiva (um problema)
         Se o problema  trivial, faa o bvio
         Simplifique o problema
         Resolva de forma recursiva (um problema mais simples)
         Combine (na medida do possvel) a soluo do(s) problema(s)
           mais simples
         em uma soluo do problema original

        Um subprograma recursivo chama a si prprio constantemente, cada
vez em uma situao mais simples, at chegar ao caso trivial, quando
pra. Ao programador  experiente, pensar de forma recursiva apresenta
uma perspectiva nica de certos problemas,  programas igualmente
sofisticados. (Por exemplo, a maioria das classificaes muito rpidas,
como QuickSort,  recursiva.)
       Para os programadores Delphi, alm de classificar rotinas, um uso
comum de recurso  quando voc precisa tratar com a estrutura de
subdiretrio de um disco.  Por exemplo, se voc quisesse apagar um
arquivo mas no soubesse onde ele se encontrava,  os subdiretrios
naquele disco.
       H realmente dois tipos de recurso possveis. O primeiro  onde
o subprograma chama apenas a si prprio. Isso  chamado de recurso
direta. Utilizar a recurso  direta no Delphi  simples. Basta chamar o
subprograma da forma que voc chamaria qual Isso ocorre, por exemplo,
quando um subprograma chama um outro subprograma que por sua vez chama o
primeiro subprograma.
        Para ilustrar, vamos dar uma olhada no exemplo padro do mximo
divisor comum (MDC) de dois inteiros. (Para aqueles que esqueceram a
matemtica do colegial,  ele  definido como o maior nmero que divide
dois inteiros.  utilizado quando voc tem 
        MDC(4,6)=2(porque 2  o maior nmero que divide 4 e 6)
         MDC( 12,7)=1 (porque nenhum inteiro maior do que 1 divide 12 e
7)
       
        H cerca de 2000 anos, Euclides determinou o seguinte mtodo
para determinar o MDC entre dois inteiros, a e b:
       
        Se b divide a, ento o MDC  b. Caso contrrio,
         MDC(a,b)=MDC(b,a mod b)

(Lembre-se do Captulo 4 que a funo mod fornece o resto de uma diviso
de inteiros.) Por exemplo,
        MDC(126,12)=MDC(12,126 mod 12)=MDC(12,6)=6

         Eis o cdigo para uma funo MDC recursiva:

     function MDC (Const P, Q: Integer): Integer;
     begin
       if Q mod P = 0 then
          MDC := P
       else
          MDC := MDC(Q, P mod Q);
     end;

        Aqui, o padro consiste em cuidar primeiro do caso trivial. Se
voc no est no caso trivial ento o cdigo o reduz a um caso mais
simples, porque a funo  mod leva a nmeros menores. (Nesse exemplo,
no h necessidade de combinar resultados como
       O segundo tipo de recurso, a recurso indireta, acontece quando
uma funo ou um procedimento se chama via um intermedirio. Por
exemplo, a funo A chama  a funo B, mas B tambm chama A. O problema
em utilizar esse tipo de recurso no Delphi   definido aps ele.
        A maneira para contornar isso  com um tipo especial de
declarao chamado declarao forward. Para fazer uma declarao
forward, adicione a chave forward  e um ponto-e-vrgula no final do
cabealho do subprograma. Em seguida, coloque o cabealho  o outro
programa, ainda no escrito. (Depois, voc pode colocar o cdigo :do
subprograma em si em qualquer lugar que quiser dentro de sua unidade,
embora a maioria  das pessoas continue colocando o cdigo do subprograma
;na seo de implementao. )
       Eis um exemplo da utilizao de uma declarao forward:
       
       procedure Segundo(foo: Integer); forward;
       procedure Primeiro(bar: Integer);
       begin
         Segundo(1);
       end;
       procedure Segundo(foo: Integer);
       var
         i: integer;
       begin
         for i = 1 to foo do
         ShowMessage(';Agora est OK');
       end;

NOTA: Se voc utilizar procedimentos recursivos muito complicados,
talvez tenha de ampliar o tamanho da pilha padro do Delphi (16.384
bytes). Isto pode ser realizado  pela pgina Linker da caixa de dilogo
Project Options. O tamanho mximo da pilha  65.536 bytes.

Gerenciando Projetos e Unidades

Os projetos armazenam toda informao de seu aplicativo enquanto ele
est sendo desenvolvido. A maioria das opes para um projeto 
especificada nas diversas pginas  da caixa de dilogo Project Options.
Por exemplo, conforme visto no ltimo captulo, voc utiliza a pgina
Forms para determinar quais formulrios o Delphi criar
automaticamente. Como outro exemplo, voc pode escolher na pgina
Application dessa caixa de dilogo o cone que o Delphi utilizar para o
executvel independente.  (Ns abordamos a pgina Compiler mais adiante,
neste captulo, na seo "Fundamentos do Compilador". Para as partes
dessa caixa de dilogo Project Options que ns  no abordamos, consulte
a ajuda on-line.)
        Um projeto  formado por um nico arquivo Project (.DPR) que
relaciona todos os formulrios e unidades no projeto. Embora voc possa
ver o arquivo Project  pela escolha de View(Project Source, falando
genericamente, deixe o prprio Delphi manter o criando um DLL em lugar
de um aplicativo independente. )

DICA:  uma boa idia utilizar um diretrio separado para cada projeto
normalmente voc armazenar ali todos os arquivos de cada projeto. Caso
contrrio, o Delphi  faz seu armazenamento em seu prprio diretrio
\DELPHI por padro, o que ficar bastante confuso.

        Esteja voc processando um projeto a partir do ambiente de
desenvolvimento ou transformando-o em um arquivo independente, o Delphi
utiliza o nome do arquivo  Project como o nome do arquivo .EXE que ele
cria. Voc pode controlar onde o Delphi coloc na caixa de dilogo
Project Options (o padro  o diretrio\BIN do Delphi).

 DICA: J que o Delphi realmente cria um arquivo .EXE todas as vezes em
que voc processa um programa a partir do ambiente de desenvolvimento,
voc talvez tenha  que limpar o diretrio \BIN do Delphi periodicamente
dos arquivos .EXE - caso no mude essa o

Mais sobre Unidades

Uma vez que as unidades armazenam o cdigo de seu projeto, elas
representam a base da programao Delphi. Quando voc comea a construir
bibliotecas de rotinas teis,  provavelmente vai armazen-las como uma
unidade. A possibilidade de construir um projeto a partir de unidades
facilita o acrscimo de uma biblioteca de rotinas testadas  ao seu
projeto. Por exemplo, quando voc compra uma ferramenta de terceiros,
ela provavelmente  fornecida como uma unidade.

DICA: Se voc precisa compartilhar unidades entre projetos com
freqncia, considere a colocao das unidades que voc compartilhar em
um diretrio especial e especifique  a caixa Search Path na pgina
Directories/Conditionals da caixa de dilogo Project Options de acordo.

        Todas as vezes em que voc criar um formulrio novo, o Delphi
cria automaticamente a sua unidade associada. Escolha New Unit do menu
File para criar uma  unidade apenas para cdigo. Todas as unidades podem
ter tipos definidos pelo usurio, varive voc cria uma unidade, o
Delphi acrescenta automaticamente  sua definio o seguinte:

        *Cabealho da unidade
        *Seo interface
        *Seo implementation

       Uma quarta parte, chamada de seo inicialization  opcional.

NOTA: Uma unidade tem de terminar com a palavra-chave end seguida de um
ponto.

        As prximas sees descrevem rapidamente as partes de uma
unidade.

O Cabealho da Unidade

O cabealho da unidade comea com a palavra-chave unit e, em seguida, d
o nome da unidade. Os nomes de unidade padro so Unit 1, Unit2 e assim
por diante. Voc  tem de utilizar o nome da unidade quando se refere a
ela na clusula uses de outra unidade. A melhor maneira para mudar o
nome de uma unidade  utilizar a opo  Save File no menu File. Qualquer
que seja o nome que voc utiliza para salvar a unidade torna-se o nome
da unidade. Evidentemente que o nome tem de ser nico, e  o Delphi no
lhe permitir utilizar duas unidades com o mesmo nome ao mesmo tempo nem
um projeto com o mesmo nome de uma unidade. As regras para o nome de uma
unidade  tm que seguir a conveno de nomenclatura padro de
oito-caracteres para os arquivos DOS e tm de ter a extenso .PAS.

A Seo da Interface

A seo interface contm a clusula uses que relaciona as outras
unidades que sero utilizadas pelo seu projeto. O Delphi acrescenta
automaticamente as unidades  padres, como SysUtils e Controls, 
clusula uses da unidade do formulrio.  medida que voc acrescenta
componentes novos a um formulrio, o Delphi tambm acrescenta
automaticamente os nomes apropriados  clusula uses do formulrio.

NOTA: O Delphi no acrescenta uma clusula uses  seo interface das
unidades de cdigo que voc cria -  preciso fazer isso manualmente.


        Como voc viu antes, a seo interface  onde voc declara
constantes globais, tipos, variveis, procedimentos e funes (isto ,
coisas que voc quer que  sejam visveis a todas as unidades que
utilizam a unidade.) Como voc tambm viu antes, ape seo interface.


DICA PASCAL: Se voc quer utilizar novamente uma unidade criada com uma
verso mais antiga do Borland Pascal para Windows, que utiliza Wincrt,
esteja certo de que  acrescentou a unidade Wincrt  clusula uses
daquela unidade. (Wincrt no  acrescentado automaticamente  clusula
uses da unidade de um formulrio, embora algumas  verses anteriores da
documentao digam que seja.)

        Voc tambm deve estar ciente de que o Delphi acrescenta
automaticamente as declaraes necessrias s partes visuais de seu
formulrio  seo interface  da unidade associada ao formulrio (veja
maiores detalhes no Captulo 6). Quase nunca voc v de uma unidade de
formulrio.

A Seo de Implementao

 aqui que voc coloca o cdigo para os procedimentos e funes (sejam
elas declaradas ou no na seo interface). Qualquer objeto Delphi
declarado aqui estar disponvel  apenas ao cdigo dentro da unidade. A
seo implementation de uma unidade de formulrio comea com uma
diretriz de compilador que se parece com a seguinte:

        {$R '".DFM}

        No apague isso acidentalmente, uma vez que  a linha de cdigo
que informa ao Delphi para conectar a parte visual (.DFM) do formulrio.

A Seo de Inicializao

Essa seo  opcional. Ela no  gerada automaticamente quando voc cria
uma unidade. Voc tem que inserir a palavra-chave inicialization,
seguida por quaisquer  declaraes que voc quer que sejam executadas
para poder inicializar a unidade. (O Delphi inicializa unidades na ordem
em que elas aparecem na clusula uses do  formulrio principal.)

DICA PASCAL: O Delphi reconhece desde a palavra-chave mais velha begin
at a palavra-chave mais nova initialization.

Fundamentos do Compilador

Quando voc compila o seu projeto em um aplicativo independente, pode
mudar o tipo de cdigo gerado pelo Delphi utilizando opes de
compilador. As opes de compilador  utilizadas com mais freqncia
esto disponveis na pgina Compiler da caixa de dilogo Project Options
(Options ( Project Options). Algumas das opes, como Pentium Safe FDIV
(diviso), tm seus apreciadores, enquanto outros, como a sintaxe
Extended, so teis quando voc sabe que seu programa  funcionar com
PChar e strings (grandes) de terminao nula. Muitas opes (por
exemplo, aquelas relacionadas na seo Debugging dessa caixa de dilogo)
normalmente  so ativadas ao desenvolver um projeto, mas desativadas
para a compilao final porque incham e atrasam seu cdigo.

NOTA: Voc tambm pode conseguir com que o Delphi compile seu cdigo em
uma biblioteca de ligao dinmica (DLL) para que possa ser utilizado
por outros programas  Windows. Para ver os detalhes de como fazer isso,
consulte o tpico de ajuda on-line "Compiling a Project into DLL" ou o
"Component Writers Guide" fornecido com  o Delphi.

       A seguir, apresentamos uma discusso breve das diversas opes de
compilao que h na pgina Compiler da caixa de dilogo Project
Options.
       
        Default Check Box - Se voc escolher essa caixa, o Delphi
salvar as opes do projeto atual para que sejam utilizadas em cada
projeto novo.
        Force Far Calls - Essa  uma chave bastante esotrica necessria
apenas por causa da arquitetura segmentada do chip Intel. Essencialmente
no h nenhuma  circunstncia em que voc queira que essa opo seja
ativada. Normalmente, o compilador Delph Far. Corresponde a {$F}.
        Word Align Data - Essa aumenta seu programa, tornando os dados
acessveis com maior facilidade. (Acrescenta cdigo extra para garantir
que seus dados estejam  armazenados em endereos de nmero par.). Por
causa de certas peculiaridades na arquitet acelerar seu programa. Voc
pode querer experimentar as duas possibilidades antes de realizar a
compilao final. Corresponde a {$A}.
        Pentium-Safe FDIV - Essa gera um cdigo que detecta o famoso
erro de ponto flutuante do Pentium! Corresponde a f $U}.
        Smart Callbacks - Deixe essa opo sempre ativada! Caso
contrrio voc realmente ter que comear a lidar com as mensagens do
Windows. Corresponde a {$R}.
        Windows Stack Frame - Deixe essa opo desativada a no ser que
voc realmente precise gerar um cdigo que ir (poder?) processar em
Windows 3.0. (Dizemos  "poder" porque no achamos que foi gasto muito
tempo verificando a aptido do Delphi em g
        Range Checking - Essa opo verifica se os subscritos de vetores
e strings esto dentro dos limites. Essa opo ativada atrasa seu
cdigo, de modo que na  maioria das vezes  utilizada apenas durante o
ciclo de desenvolvimento. Corresponde a {$R}.
        Stack Checking - Essa opo verifica se h espao disponvel
para variveis locais quando voc chama um procedimento ou utiliza
recurso. De novo atrasa  o cdigo, de modo que ela freqentemente
tambm  utilizada apenas durante o desenvolvimento.
        I/O Checking - Essa opo verifica a existncia de erros de
entrada/sada (E/S) depois de cada chamada de E/S.  melhor utilizar
excees (veja o Captulo  7). Corresponde a {$I}.
        Overflow Checking - Essa opo verifica "overflow" para as
operaes de inteiros. Novamente, essa  uma opo muito til para ter
durante o teste do programa.  Corresponde a {$Q}.
        Strict Var-Strings - Quando essa opo est ativada, o Delphi
deixa voc, por exemplo, passar uma string de tamanho 20 a um
procedimento esperando uma string  de tamanho 255. Essa opo no se
aplica quando voc est com os parmetros Open selecio
        Complete Boolean Eval - Normalmente voc quer essa opo
desativada. Quando ela est ativada, o Delphi verifica todas as
expresses em uma expresso Booleana  em vez de parar ao saber o
suficiente. (Por exemplo, se voc utiliza o operador and em d a
seguinte.) Corresponde a {$B}.
        Extended Syntax - Essa  necessria para utilizar PChar (veja a
seo "Strings de Terminao Nula e PChar" anteriormente, nesse
captulo). Essa tambm deixa  voc chamar uma funo da mesma forma que
um procedimento, ignorando o resultado da fun
        Typed @ Operator - Essa controla se o Delphi verifica se a
atribuio de ponteiro faz sentido. Controla o tipo de ponteiro
devolvido pelo operador @. Corresponde  a {$T}.
        Open Parameters - Essa opo  boa para se ter ativada. Ela
deixa voc utilizar parmetros de vetores abertos em declaraes de
procedimentos e de funes.  Corresponde a {$P}.
        Debugging Information Options - Essas opes so abordadas com
maiores detalhes no Captulo 8. Geralmente, porm, elas deveriam estar
ativadas durante o  desenvolvimento e desativadas para a compilao
final.

NOTA: Voc tambm pode inserir opes de compilao diretamente no
cdigo utilizando a chave certa. Para utilizar uma dessas diretrizes no
cdigo, coloque a letra  correspondente ao parmetro (conforme dado
acima ou na ajuda on-line) dentro de chaves, como se fosse um
comentrio, precedida do sinal "$". Normalmente as diretrizes  de
compilao precisam ser colocadas antes do trecho de declarao da
unidade que voc est compilando. Utilize um sinal de mais (+) para
ativ-la e um sinal de  menos (-) para desativ-la. Por exemplo, {$X+}
ativa a sintaxe estendida, enquanto {$X-} a desativa.



O Goto

Como a maioria das linguagens de programao, o Delphi contm o desvio
incondicional ou goto. Para repetir a velha piada a respeito de dividir
os infinitos - os  programadores modernos podem ser divididos em trs
grupos: aqueles que no sabem nem querem saber quando deveriam utilizar
goto, aqueles que no sabem mas parecem  se preocupar bastante, e
aqueles que sabem guando utiliz-lo.
       Evidentemente que uma utilizao rotineira de goto tem como
conseqncia um cdigo espaguete: um cdigo de leitura difcil e mais
difcil ainda de depurar.  Por outro lado, h ocasies em que a
utilizao de goto realmente deixa seu cdigo mais lim quando voc est
bem enterrado em um lao aninhado e alguma condio o obriga a deixar
todos os laos simultaneamente. No  possvel utilizar break porque
tudo  o que ele faz  tirar voc do lao em que voc se encontra no
momento. )
       Para utilizar goto no Delphi, voc primeiro tem que declarar um
rtulo utilizando a palavra-chave label seguido pelo identificador do
rtulo (separe os identificadores  por vrgulas se houver mais do que
um). Da mesma forma que qualquer declarao,

        label
          EntradaRuim, SaidaRuim;

(Os rtulos tm de seguir as regras das variveis Delphi, embora voc
possa utilizar numerais entre 1 e 9999. Evidentemente que voc deveria
utilizar um rtulo o  mais descritivo possvel. )
        Voc pode utilizar um rtulo anteriormente declarado em qualquer
ponto da unidade depois de sua declarao (voc no pode pular fora de
uma unidade). Para  fazer isso, coloque o identificador de rtulo em sua
prpria linha seguido por dois-pontos:

        EntradaRuim:
          {O cdigo que queremos processar pode ser colocado aqui}:

        Por exemplo, vamos supor que estamos utilizando um lao For
aninhado para entrar com dados e queremos deixar o lao se o usurio
digitar `ZZZ'.

        var
        i, j: Integer;
        ObtemDados: String
        label
          EntradaRuim;
        begin
         for1=1to10do
            for j = 1 to 100 do
                 begin
                  ObtemDados := InputBox('Entrada de dados','Coloque os
dados, ZZZ para terminar', ' ')
                  if ObtemDados = 'ZZZ' then
                    goto EntradaRuim
                  else
                    cells(i,j) := ObtemDados;
                 end;
        Application.Terminate;
        EntradaRuim:
           ShowMessage('Entrada de dados terminou com solicitao do
usurio';

        Observe como a utilizao da palavra-chave break no daria certo
aqui. Por exemplo, seria necessrio um cdigo adicional para sair
completamente do lao  aninhado. Observe tambm o comando
Application.Terminate que impede o programa de cair no com
