Guia Delphi

Arrays Dinâmicos no Delphi

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (15)  (0)

Veja neste artigo como trabalhar com arrays dinâmicos no Delphi, uma forma de manipular essas estruturas de dados sem que seja necessário definir suas dimensões no momento da declaração.

As variáveis são os elementos básicos que um programa manipula e representam espaços reservados na memória do computador para armazenar valores de um determinado tipo de dados.

O tipo de dados para uma variável é escolhido de acordo com a natureza da informação analisada e define que valores a variável pode assumir (representação interna da memória desses valores) e que operações podem ser realizadas com essa variável.

De forma resumida, os tipos de dados podem ser classificados em dois grupos:

  • tipos de dados simples (numérico: inteiro e real, literal e lógico);
  • tipos de dados estruturados (vetor, cadeia de caracteres, registro, entre outros).

Em uma variável declarada a partir dos tipos de dados simples é permitido o armazenamento de um único valor por vez. Para agrupar e manipular diversos valores em uma mesma estrutura deve-se utilizar os tipos de dados estruturados, como por exemplo, os vetores.

Vetores (ou arrays)

Os vetores são estruturas de dados que armazenam usualmente uma quantidade fixa de valores do mesmo tipo (estrutura homogênea). Em variáveis do tipo vetor podem ser armazenados um grupo de valores, cada um associado a um número que se refere à posição de armazenamento. O número de posição do valor é conhecido como índice ou subscrito do valor. Portanto, os vetores são estruturas indexadas, em que cada valor que pode ser armazenado em certa posição (índice) é chamado de elemento do vetor.

Aplicações que utilizam vetores implementam uma forma de agrupar e manipular diversos valores (ou elementos) em uma mesma estrutura de dados. A individualização é feita associando a cada elemento do vetor um número que se refere à posição de armazenamento (variáveis indexadas), por exemplo: a[i], de forma geral se refere ao i-ésimo elemento do vetor a.

Na declaração de vetores deve-se obedecer a seguinte sintaxe:

var nomeDaVariável: array[dim1, dim2, ...] of TipoDeDados;

Onde:

  • nomeDaVariável: é o nome simbólico pelo qual o conjunto é identificado.
  • array: palavra reservada seguida das dimensões da variável entre colchetes "[" e "]", determina que se trata de uma variável indexada.
  • dim1, dim2, ...: são os intervalos dos índices da variável em cada uma das dimensões, definem a quantidade de elementos do conjunto.
  • of: palavra reservada que indica o tipo de dados do conjunto.
  • TipoDeDados: é o tipo de dados dos elementos da variável indexada.

Na Listagem 1 pode-se observar as declarações das seguintes variáveis do tipo vetor:

  • vetorA: conjunto com 10 números inteiros indexados de 1 até 10.
  • vetorB: conjunto com 11 números reais indexados de 10 até 20.
  • vetorC: conjunto com n (100) registros do tipo rg.
  • matrizA: conjunto bidimensional (3 X 3) com capacidade para armazenar um total de 3 X 3 = 9 números inteiros.
  • matrizB: conjunto bidimensional (nl X nc) com capacidade para armazenar um total de 4 X 5 = 20 números inteiros.

Listagem 1: Declarando variáveis do tipo vetor

const n = 100; // tamanho da variável "vetorC"
      nl = 4;	// número de linhas da variável "matrizB"
      nc = 5;	// número de colunas da variável "matrizB" 

type rg = record
            campo1: integer;
            campo2: string[35];
          end;

// vetores unidimensionais 
var vetorA: array[1..10] of integer;
    vetorB: array[10..20] of real;
    vetorC: array[1..n] of rg;
// vetores bidimensionais (matrizes)
    matrizA: array[1..3, 1..3] of integer;
    matrizB: array[1..nl, 1..nc] of integer;
// índices ou subscritos
    i, j: integer;

// Fazendo referência a um determinado elemento:
vetorA[i]: i-ésimo elemento do vetor "vetorA"

vetorC[3].campo1: denotando o campo "campo1" do 3º registro do vetor "vetorC"
vetorC[3].campo1: denotando o campo "campo2" do 3º registro do vetor "vetorC"

matrizA[i, j]: elemento da i-ésima linha e j-ésima coluna da matriz "matrizA"

Vetores dinâmicos

Na declaração de um tipo de dados usando a construção de arrays, é necessário especificar o número de elementos do array. Para criar um vetor dinâmico também deve-se utilizar a declaração array, informando o tipo dos elementos do vetor (ou tipo base). A diferença é que, neste caso, não é necessário informar os índices que definem o tamanho. Essa informação é fornecida em tempo de execução, fazendo alocação dinâmica de memória, através do procedimento SetLength como pode ser observado na Listagem 2.

Listagem 2: Declarando e criando arrays dinâmicos

// Na declaração dos arrays dinâmicos não é necessário informar os índices
var vetor: array of integer;
    matriz: array of array of integer;

// 1. Criando um vetor com 10 elementos indixados de 0 até 9
SetLength(vetor, 10);

// 2. Redimensionando o vetor para 20 elementos indexados de 0 até 19. 
// Neste caso, os 10 elementos anteriores do vetor são mantidos.
SetLength(vetor, 20);

// 3. Criando uma matriz 2 X 4
SetLength(matriz, 2);
SetLength(matriz[0], 4);
SetLength(matriz[1], 4);

Como na criação de um array dinâmico especifica-se apenas o tamanho do vetor, os índices por default são definidos sempre no intervalo do 0 (zero) até tamanho do vetor menos 1.

Outro aspecto importante na utilização de arrays dinâmicos diz respeito à liberação da memória alocada que deve ser realizada usando o procedimento Finalize.

Para obter informações sobre uma estrutura de dados array tem-se as seguintes funções:

  • Low: retorna o limite inferior do array (posição do primeiro elemento). No caso de arrays dinâmicos, retorna sempre 0 (zero).
  • High: retorna o limite superior do array (posição do último elemento). No caso de arrays dinâmicos, retorna tamanho do array menos 1.
  • Length: retorna o número de elementos do array (tamanho do array).

Estudo de caso 1- Vetor e Matriz

Nesta primeira aplicação, apresentada na Figura 1, o usuário final escolhe através de um componente RadioGroup o tipo do array (vetor ou matriz), informa o tamanho do vetor e através do botão com a legenda "Criar o Vetor" ou "Criar a Matriz", definida conforme a escolha. Será criado o array dinamicamente.

Criando dinamicamente uma matriz

Figura 1: Criando dinamicamente uma matriz

A Listagem 3 apresenta o código completo da unit do formulário da aplicação (Figura 1) desenvolvida para demonstrar a utilização de arrays dinâmicos (variáveis "vetor" e "matriz").

Listagem 3: Aplicação para criar arrays dinâmicos

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Buttons;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    RadioGroup1: TRadioGroup;
    Memo1: TMemo;
    procedure RadioGroup1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var  vetor: array of integer;
    matriz: array of array of integer;
         n: integer; // tamanho do vetor

// RadioGroup para selecionar o "Tipo do Array"
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
  if (RadioGroup1.ItemIndex = 0)
     then begin
            Button1.Caption := 'Criar o Vetor';
            Label1.Caption := 'Tamanho do Vetor:';
          end
  else begin
         Button1.Caption := 'Criar a Matriz';
         Label1.Caption := 'Ordem da Matriz:';
       end;
end;

// Botão "Criar Vetor"
procedure TForm1.Button1Click(Sender: TObject);
var i, j: integer;
       s: string;
begin
  try
    n := StrToInt(Edit1.Text);

    randomize;

    if (RadioGroup1.ItemIndex = 0)
       then begin
              SetLength(vetor, n); // cria o vetor dinamicamente
              for i:=low(vetor) to high(vetor) do
              begin
                vetor[i] := random(100);
                Memo1.Lines.Add(Format('vetor[%2d] = %2d', [i, vetor[i]]));
              end;
            end
    else begin
           SetLength(matriz, n); // cria a matriz dinamicamente
           for i:=low(matriz) to high(matriz) do
           begin
             s := Format('%2da. linha = ', [i+1]);
             // cria a i-ésima linha da matriz dinamicamente
             SetLength(matriz[i], n);
             for j:=low(matriz[i]) to high(matriz[i]) do
             begin
               matriz[i, j] := random(100);
               s := s + Format('%2d ', [matriz[i, j]]);
             end;
             Memo1.Lines.Add(s);
           end;
         end;

    Button1.Enabled := False;
    Button2.Enabled := True;
  except
  end;
end;

// Botão "Liberar Memória"
procedure TForm1.Button2Click(Sender: TObject);
begin
  if (RadioGroup1.ItemIndex = 0)
     then Finalize(vetor)
  else Finalize(matriz);

  Button1.Enabled := True;
  Button2.Enabled := False;

  Memo1.Clear;
end;

end.

Estudo de caso 2- Controle de Notas Escolares

Nesta segunda aplicação, apresentada na Figura 2, é possível realizar um controle de notas escolares. O usuário final deverá informar o nome do aluno e suas respectivas notas escolares. O botão "Gravar Aluno" adiciona o aluno informado no final do array. Já o botão "Limpa Campos" deverá ser utilizado para limpar os componentes de entrada de dados. Para mostrar todos os alunos do conjunto no componente Memo deve-se pressionar o botão "Ler Alunos".

Realizando um controle de notas escolares

Figura 2: Realizando um controle de notas escolares

A Listagem 4 apresenta o código completo da unit do formulário da aplicação (Figura 2) desenvolvida para realizar o controle de notas escolares a partir das informações "nome", "nota1" e "nota2", previstas no registro de dados "rgAluno". No vetor dinâmico "aluno" será armazenado os registros de alunos informados pelo usuário.

Listagem 4: Aplicação para realizar um controle de notas escolares usando arrays dinâmicos

unit unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    BitBtn1: TBitBtn;
    edAluno: TEdit;
    edNota1: TEdit;
    edNota2: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    Memo1: TMemo;
    Button2: TButton;
    Button3: TButton;
    procedure edNota1KeyPress(Sender: TObject; var Key: Char);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type rgAluno = record
                 nome: string[35];
                 nota1: real;
                 nota2: real;
               end;

var aluno: array of rgAluno;
        n: integer = 0; // tamanho do vetor
        x: rgAluno;

// Evento "OnKeyPress" dos Edits "1a. Nota" e "2a. Nota"
// Verificando e aceitando somente valores numéricos do tipo real
procedure TForm1.edNota1KeyPress(Sender: TObject; var Key: Char);
begin
  if (Key in ['.', ','])
     then if (pos(',', (Sender as TEdit).Text) = 0)
             then Key := ','
          else Key := #7
  else if (not(Key in ['0'..'9', #8]))
          then Key := #7;
end;

// Botão "Gravar Aluno"
procedure TForm1.Button1Click(Sender: TObject);
begin
{ verifica se todos os campos foram informados }
  if ((edAluno.Text <> '') and (edNota1.Text <> '') and
      (edNota2.Text <> ''))
     then begin
            x.nome := edAluno.Text;
            x.nota1 := StrToFloat(edNota1.Text);a
            x.nota2 := StrToFloat(edNota2.Text);

            n := n + 1;
            // redimensiona o vetor "aluno" aumentando uma posição
            // para adicionar o novo aluno no final do conjunto
            SetLength(aluno, n);
            aluno[n-1] := x;

            Memo1.Lines.Add(x.nome + ', gravado com sucesso.');
          end;
end;

// Botão "Ler Alunos"
procedure TForm1.Button2Click(Sender: TObject);
var  nreg, i: integer;
       media: real;
begin
  Memo1.Lines.Add('');

  nreg := 0;
  for i:=0 to n-1 do
  begin
    x := aluno[i];
    nreg := nreg + 1;
{ processando e exibindo os dados recuperados }
    media := (x.nota1 + x.nota2) / 2;
    Memo1.Lines.Add('Registro Nro.: ' + IntToStr(nreg));
    Memo1.Lines.Add('Nome do Aluno: ' + x.nome);
    Memo1.Lines.Add('1a. nota.....: ' + Format('%.2f', [x.nota1]));
    Memo1.Lines.Add('2a. nota.....: ' + Format('%.2f', [x.nota2]));
    Memo1.Lines.Add('Média........: ' + Format('%.2f', [media]));
    if (media >= 6.0)
       then Memo1.Lines.Add('Situação.....: Aprovado')
    else Memo1.Lines.Add('Situação.....: Reprovado');
    Memo1.Lines.Add('');
  end;
end;

// Botão "Limpar Campos"
procedure TForm1.Button3Click(Sender: TObject);
begin
  edAluno.Clear;
  edNota1.Clear;
  edNota2.Clear;
end;

end.

O código fonte das aplicações encontra-se disponível para download no topo dessa página.

Obrigado e um abraço.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?