quarta-feira, 31 de outubro de 2007

Tipos de dados Compostos

Tipo Array

Arrays são matrizes, isto é, coleções ordenadas de elementos de um mesmo tipo de dados, que faz uso de um índice para dar acesso aos itens da coleção. Como array já é um tipo, basta declarar uma variável como array, da seguinte forma:

var
Dia_da_semana: array [1..7] of string;
Dia_do_mês: array [1..31] of integer;

Note que separamos os valores mínimo e máximo de um array por dois pontos. Os arrays declarados acima são unidimensionais, isto é, seus elementos podem ser dispostos formando uma única linha. Para atribuir valores a um array proceda da seguinte forma:

begin
Dia_da_semana [1] := ‘Domingo’;
Dia_da_semana [2] := ‘Segunda-feira’;
Dia_da_semana [3] := ‘Terça-feira;
Dia_da_semana [4] := ‘Quarta-feira’;
Dia_da_semana [5] := ‘Quinta-feira’;
Dia_da_semana [6] := ‘Sexta-feira’;
Dia_da_semana [7] := ‘Sábado’;
end;

Para armazenar valores de um array em outra variável, podemos escrever:

var
Dia : string;

begin
Dia := Dia_da_semana [1];
end;

e assim por diante. A declaração de arrays multidimensionais é semelhante à de arrays unidimensionais. Por exemplo, para declarar um array a ser usado como uma tabela 30x30, escrevemos:

var
Bi_array: array [1..30,1..30] of currency;

Note que os elementos de um array podem pertencer a qualquer tipo de dados pré-definido ou definido pelo usuário.

- Arrays Dinâmicos

Uma novidade no Delphi 4 são os arrays dinâmicos. Arrays Dinâmicos são arrays alocados dinamicamente em dimensões que não são conhecidas em tempo de compilação. Para declarar um array dinâmico, apenas declare um array sem incluir as dimensões:

var
// array dinâmico de string:
SA: array of string
;

Antes de poder usar um array dinâmico, você deve usar o procedimento SetLength() para alocar memória para o array:

begin
// aloca lugar para 33 elementos:
SetLength(SA, 33);

Depois que a memória foi alocada, você pode acessar os elementos do array dinâmico como um array normal:

SA[0] := 'O urso parece feliz';
OutraString := SA[0];

Nota: Arrays Dinâmicos sempre iniciam no zero.

Arrays dinâmicos são auto-suficientes, assim não é necessário liberá-los quando você deixar de usá-los; eles serão liberados quando deixarem o escopo. Entretanto, pode haver uma hora que você queira remover o array dinâmico da memória antes que ele saia do escopo (se ele usa muita memória, por exemplo). Para fazer isso, você apenas precisa atribuir ao array dinâmico um nil:

SA := nil; // libera SA

Arrays dinâmicos são manipulados utilizando semanticas de referência similares à AnsiStrings


Tipo Enumerado

Este tipo permite que você crie uma lista organizada de itens. Para usar um tipo você deve antes declará-lo com a palavra reservada type. Por exemplo, um tipo enumerado que descreve os dias da semana pode ser declarado da seguinte maneira:

type
Semana = (Segunda, Terça, Quarta, Quinta, Sexta, Sábado, Domingo);

Espaços em branco não são permitidos dentro de um elemento. Uma vez declarado um tipo, você deve declarar uma variável pertencente a este tipo. Não usamos o tipo diretamente, mas sim uma variável deste tipo. Por exemplo, vamos supor que queiramos construir um programa que forneça o nome da pessoa escalada para um plantão semanal. Poderíamos declarar uma variável Plantao da seguinte forma:

var
Plantao : Semana;

Para atribuir valores à variável Plantao escreva simplesmente:

Plantao := Segunda;
Plantao := Terça;
etc.


Tipos Registro(Record)

O tipo de dados Record provavelmente é o mais versátil à disposição, pois pode conter tipos de dados heterogêneos. Por exemplo, a folha de pagamento de uma empresa conterá dados do tipo string (nome, endereço, etc), dados do tipo currency (salário), dados do tipo TDateTime (data de contratação) e assim por diante. Não poderíamos usar um array, pois este tipo só pode conter dados de um mesmo tipo. O tipo Record resolve o problema e, mais uma vez, devemos declarar o tipo de dados antes de usá-lo:

type
Folha_Pgto = Record
Nome: String;
Data_Cont : TDateTime;
Salario: currency;
end;

var
Folha_Abril: Folha_Pgto;

begin

Folha_Abril.Nome := ‘Ana Paula Magalhães’;
Folha_Abril.Data_Cont := 10/02/1998;
Folha_Abril.Salário := 2200;

end;

Note que você deve usar um ponto para separar o nome do Record do nome do campo a que você está se referindo. O Object Pascal, e várias linguagens modernas fornecem uma maneira mais fácil de executar esta operação, usando a instrução With:

begin

With Folha_Abril do begin

Nome := ‘Ana Paula Magalhães’;
Data_Cont := 10/02/1998;
Salário := 2200;

end;

end;

Aqui, o primeiro "end" é da instrução With. A documentação do Object Pascal sugere que você use With quando for possível, pois isto diminui o tempo de execução.

Os tipos Record também podem conter arrays e são bastante usados quando se requer bancos de dados simples. Veremos que o Delphi permite a implementação de estruturas de dados bastante complexas, usando bancos de dados Dbase, Paradox, Access, etc. Contudo, vez por outra não é necessária toda esta sofisticação e é conveniente optar pelos tipos Record. Além disso, nesses casos simples não será necessário instalar os drivers de bancos de dados.


Tipo Subintervalo

O tipo subintervalo permite que você defina um intervalo válido de respostas que um usuário pode inserir em um programa, tal como o número de horas trabalhadas em um mês, a faixa de idade dos membros de um clube, etc. Um subintervalo pode conter os seguintes tipos: boolean, char, integer e tipos enumerados.

A declaração de um tipo subintervalo é similar àquela de um tipo enumerado:

type
Salario_faixa1 = 500 .. 1000;

Note que usamos dois pontos para separar os limites do subintervalo, e não vírgulas. Isto permite que o compilador identifique o tipo como um subintervalo e não um tipo enumerado. A seguir, devemos declarar uma variável como pertencente ao tipo declarado anteriormente:

var
Salario_Ana : Salario_faixa1;

Quando um programa usando subintervalos é executado, e se um valor atribuído a um tipo subintervalo estiver fora do intervalo, o programa gerará um erro de tempo de execução. Para que o teste de intervalo seja executado, você deve antes incluir a diretiva de compilação {$R+} no programa, da seguinte forma:

procedure Tform1.ButtonClick (Sender : Tobject);
{$R+}

type
Salario_faixa1 = 500 .. 1000;

var
Salario_Ana : Salario_faixa1;


Tipo Conjunto

Os conjuntos são ainda mais interessantes que os subintervalos. Os conjuntos podem usar intervalos em suas definições. Um conjunto é um grupo de elementos que você quer associar a um nome e que pode comparar com outros valores para a inclusão ou exclusão do conjunto. Um exemplo poderia ser um conjunto contendo todas as respostas de um caractere possíveis para uma pergunta do tipo SIM/NÂO. As quatro respostas são y , Y, n e N. você poderia criar um conjunto que abrangesse as quatro: [ ‘y’, ‘Y’, ‘n’, ‘N’]. uma vez definido esse conjunto , você pode então usá-lo para ver se algo está nele ou não.

Você procura inclusão de um conjunto chamando a instrução in. Por exemplo, a instrução :

Myinput in [‘y’, ‘Y’, ‘n’, ‘N’] then

Está dizendo que, se o valor da variável, Myinput é um dos itens do conjunto, então essa expressão é valida como TRUE booleano. Se o valor de Myinput não esta no conjunto, então essa instrução é FALSE. Um conjunto pode conter quase tudo, desde que seus membros sejam do mesmo tipo ordinal ou de tipos ordinais compatíveis.

Constantes Tipadas

Na verdade, constantes tipadas são variáveis inicializadas com valor persistente, que podem ser alteradas normalmente, como qualquer variável. A única diferença de sintaxe entre constantes tipadas e simples é que o tipo da constante é indicado explicitamente na declaração. Se uma constante tipada for declarada localmente, ela não será destruída quando o método for encerrado


Tipo Variant

O tipo Variant pode assumir tipos como SmallInt (inteiro de 16 bits), Integer(inteiro de 32 bits), Strings, Single (ponto flutuante de precisão simples), Double (ponto flutuante de precisão dupla), Boolean(lógico de 16 bits)... Bem como também assumir tipos como Null (para nulo), e Empty (para nunca atribuído, vazio). As conversões de tipos acontecem automaticamente (na medida do possível), e a atribuição de tipos para uma variável do tipo Variant pode mudar em modo de execução, observe o exemplo abaixo:

procedure TForm1.Button1Click(Sender: TObject);
var m_valor1,

m_valor2,

m_valor3 : Variant;

m_Str1 : String;

Begin

m_valor1 := 12; // atribui valor inteiro

m_valor2 := 5.2; // atribui um ponto flutuante

m_valor3 := m_valor1 * m_valor2;

m_Str1 := m_valor3;
// atribui resultado(já convertendo)

End;

Como pode notar, temos em mãos uma flexibilidade ímpar no trabalho com variáveis. Todavia, como nem tudo são rosas, existem desvantagens com o uso de Variant, entre elas, o tamanho mínimo de 16 bits para as variáveis (tornando-as mais lentas), e também o fato de não haver verificações em modo de compilação quando usamos Variant, podendo surgir Bugs que daremos conta somente em modo de execução.


Tipo Ponteiros

Os ponteiros em Object Pascal têm o mesmo poder dos ponteiros em C / C++, porém são muito menos utilizados.

Vejamos algumas comparações de sintaxe de ponteiros em Delphi e C.

Linguagem

C

Delphi (pascal)

Declaração

tipo * apontador;

var apontador: ^tipo;

Exemplos

int * PointerPara_int;
char * string;

var PointerPara_integer: ^integer;
Mensagem: ^String[40];


Para usarmos apontadores é necessário fazê-los apontar para a referência correta. Um apontador nulo ou inválido faz com que o programa aborte. Para usar o valor referenciado por um apontado, utilizamos a seguinte sintaxe:

Linguagem

C

Delphi

Sintaxe

* apontador

apontador^

Exemplos

a = *b;
*a = *a + 1;

a := b^;
a^ := a^ + 1;


Para inicializar apontadores, é necessário "apontá-lo" para o endereço de memória no qual se deseja referenciar. Isso pode ser feito através do operador "cria pointer". Veja os exemplos abaixo:

C

Delphi

int main() {

int dia = 5;

int mes = 1;

int *ap;

ap = &dia;

*ap --;

ap = &mes;

*ap ++;

}

var dia, mes: integer;

ap: ^integer;

begin

dia := 5;

mes := 1;

ap := @dia;

dec(ap^);

ap := @mes;

inc(ap^);

end;

Para usar a memória dinâmicamente, ela precisa ser alocada. A alocação de memória reserva um bloco de memória e armazena o seu endereço em um apontador, para futuras referências. Existem várias formas para se alocar memória. Abaixo estão algumas:

Linguagem

C

Delphi

Declaração

char *buffer;

type tBuffer = array[0..1023] of char;
var Buffer: ^tBuffer;

Alocação

buffer = (char *)malloc(1024);

buffer = (char *)calloc(1024,1);

getmem(Buffer, 1024);

Liberação

free(buffer);

freemem(Buffer, 1024);


Um apontador pode referenciar outro apontador ao invés de uma variável. Esse recurso é em geral utilizado quando um apontador é passado para uma função, por referência. A função abaixo, por exemplo, aloca memória e testa se a alocação foi bem sucedida:

C

Delphi

void aloca(void **apont, int tamanho) {

*apont = (void *) malloc(tamanho);

if (*apont == NULL) {

printf(stderr, "Erro alocando buffer!\n");

exit(-1);

}

}

type tBuffer = array[0..1000] of char;

pBuffer = ^tBuffer;

procedure aloca(var apont: pBuffer; tamanho: integer);

begin

getmem(apont, tamanho);

if (apont = nil) then begin

writeln('Erro alocando buffer!');

halt(-1);

end;

end;

A linguagem pascal usa a palavra reservar "var" para indicar que a passagem de parâmetros foi feita por referência e evita a necessidade de se tratar o apontador para apontador diretamente na linguagem.

Nenhum comentário: