MC102
Algoritmos e Programação de Computadores
Parte XXI



Norton Trevisan Roman




REGISTROS

Registros são variáveis que podem guardar mais de um dado, inclusive de tipos diferentes. Por exemplo, suponha que queremos trabalhar com datas, no formato dia, mês e ano. Como faríamos? Uma alternativa é transformar nossa data em dias (ou meses ou anos) e então, após termos trabalhado com ela, transformar novamente para dia, mês e ano. Trabalhoso, não? Seria muito mais fácil se pudéssemos trabalhar no formato dia, mês e ano. Como fazemos isso?

  TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez);
       dias  = 1..31;

  VAR data : RECORD
               dia : dias;
               mes : meses;
               ano : integer
             END;
	

Aqui definimos uma variável do tipo "data", que é um registro composto de 3 campos: dia, do tipo "dias"; mes, do tipo "meses" e ano, do tipo integer.

Assim, quando temos várias variáveis que dizem respeito à mesma coisa, as agrupamos em um registro.

Também, podemos criar um tipo com registros:

  TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez);
       dias  = 1..31;
       datas = RECORD
                 dia : dias;
                 mes : meses;
                 ano : integer
               END;

  VAR data : datas
	

Como sempre esse segundo enfoque é melhor, pois se precisarmos passar uma data como parâmetro de função ou procedimento ou como retorno de função fazemos

  PROCEDURE Q(d : datas);

  FUNCTION F1(l : datas) : boolean;

  FUNCTION F2(l : datas) : datas;
	

uma vez que o seguinte não é permitido

  PROCEDURE Q(d : RECORD dia : dias; mes : meses; ano : integer END;);

  FUNCTION F1(l : RECORD dia : dias; mes : meses; ano : integer END;) : boolean;

  FUNCTION F2(l : RECORD dia : dias; mes : meses; ano : integer END;) :
    RECORD dia : dias; mes : meses; ano : integer END;
	

Como foi dito, os campos de um registro podem ser de qualquer tipo, inclusive outro registro.

A forma geral de um registro é:

  RECORD
    campo1 : tipo1;
    campo2 : tipo2;
    campo3 : tipo1;
    ...
    campon : tipon
  END;
	

Voltando à nossa data, como carregamos um valor na nossa variável? O segmento a seguir inicializa data com 26 de outubro de 2002:

  data.dia := 26;
  data.mes := out;
  data.ano := 2002;
	

Ou seja, acessamos o campo de uma variável do tipo record fazendo:

  nome_da_variável.campo
	

E para ler o valor de um registro? Fazemos da mesma forma que atribuímos, o conjunto nome_da_variável.campo pode ser usado como uma variável comum de tipo igual ao tipo do campo:

  PROGRAM P;

  TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez);
       dias  = 1..31;
       datas = RECORD
                 dia : dias;
                 mes : meses;
                 ano : integer
               END;

  VAR data : datas;

  BEGIN
    data.dia := 26;
    data.mes := out;
    data.ano := 2002;

    write(data.dia,'/',Ord(data.mes)+1,'/',data.ano);

    IF data.ano>0 THEN writeln(' d.C.')
    ELSE writeln(' a.C.')
  END.
	

O programa acima escreve "26/10/2003 d.C.". Viu? Podemos usar o conjunto nome_da_variável.campo como variáveis comuns.

Um outro detalhe, como o campo "ano" é integer, ele é tratado como integer:

  PROGRAM P;

  TYPE meses = (jan, fev, mar, abr, mai, jun, jul, ago, set, out, nov, dez);
       dias  = 1..31;
       datas = RECORD
                 dia : dias;
                 mes : meses;
                 ano : integer
               END;

  VAR data : datas;

  FUNCTION quad(x : integer) : integer;
  BEGIN
    quad := x*x
  end;

  BEGIN
    data.dia := 26;
    data.mes := out;
    data.ano := 2002;

    write(data.dia,'/',Ord(data.mes)+1,'/',data.ano);

    IF data.ano>0 THEN writeln(' d.C.')
    ELSE writeln(' a.C.');

    data.ano := quad(data.ano) {data.ano recebe 4008004 (2002 × 2002)}
  END.
	

Vejamos alguns exemplos:

Somar tempos: suponha que tenhamos dois tempos no formato hora, minuto e seguindo e queiramos somá-los, dando a resposta em hora, minuto e segundos, como faremos?

Primeiro criamos um registro para o tempo:

  TYPE tempo = RECORD
                 hora : integer;
		 min  : word;
		 seg  : word
               END;
	

Quem é esse word? Word é um tipo inteiro do Pascal, que vai de 0 a 65535.

Agora, fazemos o programa:

  PROGRAM P;

  TYPE tempo = RECORD
                 hora : integer;
		 min  : word;
		 seg  : word
               END;

  VAR t1 : tempo;
      t2 : tempo;
      t3 : tempo;

  BEGIN
    write('hora: ');
    readln(t1.hora);
    write('minuto: ');
    readln(t1.min);
    write('segundo: ');
    readln(t1.seg);
    write('hora: ');
    readln(t2.hora);
    write('minuto: ');
    readln(t2.min);
    write('segundo: ');
    readln(t2.seg);

    {calculo o número total de segundos}
    t3.seg := t1.seg + t2.seg;

    {calculo a soma dos minutos mais o número de segundos que virou minuto}
    t3.min := t1.min + t2.min + t3.seg DIV 60;

    {somo as horas mais o número de minutos que virou hora}
    t3.hora := t1.hora + t2.hora + t3.min DIV 60;

    {como seg não pode ser >60, guardo a parte menor, pois o resto
    transformei em min}
    t3.seg := t3.seg MOD 60;

    {como min não pode ser >60, guardo a parte menor, pois o resto
    transformei em hora}
    t3.min := t3.min MOD 60;

    {escrevo o resultado}
    writeln(t3.hora,':',t3.min,':',t3.seg)
	

Agora, e se quisermos fazer uma função que retorne a soma? Como definimos um tipo com o RECORD, podemos fazer tal função:

  PROGRAM P;

  TYPE tempo = RECORD
                 hora : integer;
		 min  : word;
		 seg  : word
               END;

  VAR t1 : tempo;
      t2 : tempo;
      t3 : tempo;

  FUNCTION soma(t1,t2:tempo) : tempo;
  BEGIN
    {calculo o número total de segundos}
    soma.seg := t1.seg + t2.seg;

    {calculo a soma dos minutos mais o número de segundos que virou minuto}
    soma.min := t1.min + t2.min + soma.seg DIV 60;

    {somo as horas mais o número de minutos que virou hora}
    soma.hora := t1.hora + t2.hora + soma.min DIV 60;

    {como seg não pode ser >60, guardo a parte menor, pois o resto
    transformei em min}
    soma.seg := soma.seg MOD 60;

    {como min não pode ser >60, guardo a parte menor, pois o resto
    transformei em hora}
    soma.min := soma.min MOD 60
  END;

  BEGIN
    write('hora: ');
    readln(t1.hora);
    write('minuto: ');
    readln(t1.min);
    write('segundo: ');
    readln(t1.seg);
    write('hora: ');
    readln(t2.hora);
    write('minuto: ');
    readln(t2.min);
    write('segundo: ');
    readln(t2.seg);

    t3 := soma(t1,t2);

    {escrevo o resultado}
    writeln(t3.hora,':',t3.min,':',t3.seg)
	

Vale lembrar que nem todos os compiladores aceitam tipos assim como retorno de uma função. Para esses compiladores, uma saída é definir um procedimento:

  PROGRAM P;

  TYPE tempo = RECORD
                 hora : integer;
		 min  : word;
		 seg  : word
               END;

  VAR t1 : tempo;
      t2 : tempo;
      t3 : tempo;

  PROCEDURE soma(t1,t2:tempo; VAR t3:tempo);
  BEGIN
    {calculo o número total de segundos}
    t3.seg := t1.seg + t2.seg;

    {calculo a soma dos minutos mais o número de segundos que virou minuto}
    t3.min := t1.min + t2.min + t3.seg DIV 60;

    {somo as horas mais o número de minutos que virou hora}
    t3.hora := t1.hora + t2.hora + t3.min DIV 60;

    {como seg não pode ser >60, guardo a parte menor, pois o resto
    transformei em min}
    t3.seg := t3.seg MOD 60;

    {como min não pode ser >60, guardo a parte menor, pois o resto
     transformei em hora}
    t3.min := t3.min MOD 60
  END;

  BEGIN
    write('hora: ');
    readln(t1.hora);
    write('minuto: ');
    readln(t1.min);
    write('segundo: ');
    readln(t1.seg);
    write('hora: ');
    readln(t2.hora);
    write('minuto: ');
    readln(t2.min);
    write('segundo: ');
    readln(t2.seg);

    soma(t1,t2,t3);

    {escrevo o resultado}
    writeln(t3.hora,':',t3.min,':',t3.seg)
	

Números complexos: Sabemos que um número complexo possui sua parte real e imaginária. Assim, em (2+3i), 2 é a real e 3 a imaginária.

Como podemos, então, fazer procedimentos ou funções que executem as quatro operações em complexos? Antes de mais nada, vamos definir um tipo complexo:

  TYPE complexo = RECORD
                   re : real;
		   im : real
                  END;
	

Agora, vejamos como são calculadas as 4 operações:

  (a + bi) + (c + di) = (a + c) + (b + d)i
  (a + bi) - (c + di) = (a - c) + (b - d)i
  (a + bi) × (c + di) = (ac - db) + (bc + ad)i
  (a + bi) ÷ (c + di) = (ac + bd)/(c² + d²) + ((cb - ad)/(c² + d²))i

	

Vejamos como ficam a soma e a multiplicação. A subtração e a divisão ficam como exercício para você.

  PROGRAM P;

  TYPE complexo = RECORD
                   re : real;
		   im : real
                  END;

  VAR n1, n2, n3 : complexo;

  FUNCTION soma(n1,n2:complexo) : complexo;
  BEGIN
    soma.re := n1.re + n2.re;
    soma.im := n1.im + n2.im
  END;

  FUNCTION mult(n1,n2:complexo) : complexo;
  BEGIN
    mult.re := n1.re*n2.re - n1.im*n2.im;
    mult.im := n1.im*n2.re + n1.re*n2.im
  END;

  BEGIN
    {faço n1 := 2 + 3i}
    n1.re := 2;
    n1.im := 3;

    {faço n2 := 4 - 2.3i}
    n2.re := 4;
    n2.im := 2.3;

    n3 := soma(n1,n2);
    writeln(n3.re,' + ',n3.im,'i'); {escreve 6 + 0.7i}

    n3 := mult(n1,n2);
    writeln(n3.re,' + ',n3.im,'i') {escreve 14.9 + 7.4i}
  END.
	

Observações:

Comparação entre registros: No caso dos números complexos, como faço para verificar se um complexo é igual a outro? Infelizmente não há como fazer isso em Pascal:

  TYPE complexo = RECORD
                    re : real;
                    im : real
                  END;

  VAR t1,t2 : complexo;

  BEGIN
    {abasteço t1 com 2-3i}
    t1.re := 2;
    t1.im := -3;

    {abasteço t2 com 4+2.3i}
    t2.re := 4;
    t2.im := 2.3;

    IF t1 = t2 THEN
      {faz algo}

  END.
	

Como fazemos para testar registros então? Testamos campo a campo:

  TYPE complexo = RECORD
                    re : real;
                    im : real
                  END;

  VAR t1,t2 : complexo;

  BEGIN
    {abasteço t1 com 2-3i}
    t1.re := 2;
    t1.im := -3;

    {abasteço t2 com 4+2.3i}
    t2.re := 4;
    t2.im := 2.3;

    IF (t1.re = t2.re) AND (t1.im = t2.im) THEN
      {faz algo}

  END.
	

Pronto. Testado.

Registro dentro de registros: Vejamos agora, um exemplo de registro dentro de registro. Suponha que teremos que trabalhar com uma estrutura que deve conter uma data e um horário. O horário é algo assim:

  TYPE horario = RECORD
                   hora : integer;
                   min  : word;
		   seg  : word
                 END;
	

Então, nossa estrutura seria algo assim:

  TYPE horario = RECORD
                   hora : integer;
                   min  : word;
		   seg  : word
                 END;

  TYPE data = RECORD
                  dia : 0..31;
		  mes : 1..12;
		  ano : integer
              END;

  TYPE tempo = RECORD
                   dia  : data;
		   hora : horario
                 END;
	

Note que posso por nomes duplicados de campos (como "dia" e "hora"), desde que pertençam a registros diferentes.

Agora, como fazemos para armazenar uma data? E para ler?

  TYPE horario = RECORD
                   hora : 0..23;
                   min  : 0..60;
		   seg  : 0..60
                 END;

  TYPE data = RECORD
                  dia : 0..31;
		  mes : 1..12;
		  ano : integer
              END;

  TYPE tempo = RECORD
                   dia  : data;
		   hora : horario
                 END;

  VAR t : tempo;

  BEGIN
    {vou armazenar 12 de janeiro de 2002, 14h:05':30''}
    t.dia.dia := 12;
    t.dia.mes := 1;
    t.dia.ano := 2002;
    t.hora.hora := 14;
    t.hora.min := 5;
    t.hora.seg := 30;

    {imprimo "12/1/2001 - 14:5:30"}
    writeln(t.dia.dia,'/',t.dia.mes,'/',t.dia.ano,' - ',t.hora.hora,':',t.hora.min,':',t.hora.seg)
  END.
	

Viu como funciona? Ao fazer t.dia estou acessando o campo "dia" do registro "t". Mas esse campo, por sua vez, é um registro também, então, não posso acessá-lo diretamente, tenho que acessar seus registros. Assim, para acessar o campo "mes" do registro correspondente ao campo "dia" do registro "t" faço "t.dia.mes".





‹— Parte XXPágina da disciplinaParte XXII —›