fp registros

6
Fundamentos de Programac ¸ ˜ ao Tipos de Dados Compostos Heterog ˆ eneos Depto. de Estat´ ıstica e Matem´atica Aplicada Universidade Federal do Cear´ a Semestre 2015.1 Profssor: Tib´ erius O. Bonates ([email protected]) 1 Registros O registro (ou tipo composto heterogˆ eneo) ´ e um recurso da linguagem que permite a cria¸c˜ ao de um novo tipo de dados, al´ em dos tipos primitivos (por exemplo, bool, float) e do tipo composto homogˆ eneo (vetor). O registro permite ao programador agregar duas ou mais vari´ aveis (cujos tipos podem ser tipos b´ asicos da linguagem ou outros tipos compostos) que possuem alguma rela¸ ao l´ ogica entre si. Em geral, um registro ´ e utilizado com o prop´ osito de armazenar conjuntamente duas ou mais vari´ aveis que possuem uma rela¸c˜ ao l´ ogica entre si. Como exemplo, considere o armazenamento de dois n´ umeros reais que representam um par ordenado. Uma op¸c˜ ao ´ e proceder da seguinte forma: int main() { float x; // valor da abcissa float y; // valor da ordenada return 0; } Contudo, neste caso, as duas vari´ aveis n˜ ao est˜ ao formalmente associadas entre si no programa. unica associa¸ ao existente entre as mesmas ´ e uma associa¸ ao informal, feita mentalmente pelo programador. Este tipo de situa¸c˜ ao ´ e uma porta de entrada para erros no programa, especialmente quando temos muitas vari´ aveis e um c´ odigo longo. Afinal, ap´ os algumas p´ aginas de c´ odigo, pode ser dif´ ıcil lembrar que x e y ao eram vari´ aveis individuais, mas duas vari´ aveis que estavam intrinsica- mente ligadas para formar um par ordenado. O registro ´ e um recurso de C/C++ que oferece uma alternativa para essa situa¸ ao. O registro ´ e um novo tipo de vari´ avel que passa a estar dispon´ ıvel para o programador, da mesma forma que um int, um float, etc. No caso de um par ordenado, podemos chamar este novo tipo de ParOrdenado, a que este nome remete diretamente ao conceito que desejamos representar. O registro ´ e uma entidade ´ unica, que cont´ em duas vari´ aveis de ponto flutuante como partes integrantes. Eis sua defini¸c˜ ao e uma declara¸ ao de vari´ avel do novo tipo: // Definicao do novo tipo: struct ParOrdenado { float x; // valor da abcissa float y; // valor da ordenada }; 1

Upload: daniel-nunes

Post on 17-Dec-2015

3 views

Category:

Documents


2 download

DESCRIPTION

FP

TRANSCRIPT

  • Fundamentos de ProgramacaoTipos de Dados Compostos Heterogeneos

    Depto. de Estatstica e Matematica AplicadaUniversidade Federal do Ceara

    Semestre 2015.1

    Profssor: Tiberius O. Bonates ([email protected])

    1 Registros

    O registro (ou tipo composto heterogeneo) e um recurso da linguagem que permite a criacao deum novo tipo de dados, alem dos tipos primitivos (por exemplo, bool, float) e do tipo compostohomogeneo (vetor). O registro permite ao programador agregar duas ou mais variaveis (cujos tipospodem ser tipos basicos da linguagem ou outros tipos compostos) que possuem alguma relacao logicaentre si. Em geral, um registro e utilizado com o proposito de armazenar conjuntamente duas oumais variaveis que possuem uma relacao logica entre si. Como exemplo, considere o armazenamentode dois numeros reais que representam um par ordenado. Uma opcao e proceder da seguinte forma:

    int main() {

    float x; // valor da abcissa

    float y; // valor da ordenada

    return 0;

    }

    Contudo, neste caso, as duas variaveis nao estao formalmente associadas entre si no programa.A unica associacao existente entre as mesmas e uma associacao informal, feita mentalmente peloprogramador. Este tipo de situacao e uma porta de entrada para erros no programa, especialmentequando temos muitas variaveis e um codigo longo. Afinal, apos algumas paginas de codigo, pode serdifcil lembrar que x e y nao eram variaveis individuais, mas duas variaveis que estavam intrinsica-mente ligadas para formar um par ordenado.

    O registro e um recurso de C/C++ que oferece uma alternativa para essa situacao. O registro eum novo tipo de variavel que passa a estar disponvel para o programador, da mesma forma que umint, um float, etc. No caso de um par ordenado, podemos chamar este novo tipo de ParOrdenado,ja que este nome remete diretamente ao conceito que desejamos representar. O registro e umaentidade unica, que contem duas variaveis de ponto flutuante como partes integrantes. Eis suadefinicao e uma declaracao de variavel do novo tipo:

    // Definicao do novo tipo:

    struct ParOrdenado {

    float x; // valor da abcissa

    float y; // valor da ordenada

    };

    1

  • int main() {

    // Declaracao de uma variavel do novo tipo ParOrdenado

    ParOrdenado par; // "par" e uma variavel do tipo ParOrdenado

    return 0;

    }

    Naturalmente, ao se criar um registro e desejavel se acessar as variaveis individuais que o consti-tuem, que sao chamadas de campos ou atributos do registro. Este acesso acontece por meio deum deslocamento relativo a` posicao inicial onde o registro esta armazenado, similar ao que acontecedurante o acesso a`s posicoes de um vetor. Na definicao de um registro, os identificadores e os tiposde todos os campos que compoem o registro sao especificados. Na manipulacao de um registro, oscampos constituintes podem ser acessados por meio de seus identificadores. Em C/C++, a sintaxee: .. A seguir, mostramos uma versaomais elaborada do exemplo acima:

    struct ParOrdenado {

    float x; // valor da abcissa

    float y; // valor da ordenada

    };

    int main() {

    ParOrdenado par; // "par" e uma variavel do novo tipo ParOrdenado

    par.x = 5.2; // identificador da variavel: "par"

    // identificador do campo: "x"

    par.y = 3.01; // identificador da variavel: "par"

    // identificador do campo: "y"

    cout

  • Embora nao seja possvel realizar operacoes de soma, produto, etc, automaticamente com regis-tros, e sempre possvel realizar explicitamente a operacao desejada, utilizando-se de acesso direto aoscampos do registro. No codigo a seguir, por exemplo, mostramos como armazenar em um registroParOrdenado P3 o resultado da soma de dois outros registros do tipo ParOrdenado, P1 e P2. Nesteexemplo, estamos considerando que a soma de dois pares ordenados, p1 e p2, e um par ordenado p3obtido a partir da soma das coordenadas correspondentes de p1 e p2.

    struct ParOrdenado {

    float x; // valor da abcissa

    float y; // valor da ordenada

    };

    int main() {

    ParOrdenado P1, P2, P3;

    P1.x = 5.2; P1.y = 3.01;

    P2.x = 0.7; P2.y = 12.0;

    P3.x = P1.x + P2.x;

    P3.y = P1.y + P2.y;

    cout

  • 1.1 Inicializacao

    Ate agora, atribuimos valores aos campos de um registro utilizando o operador ponto (.), ou porintermedio do operador de atribuicao (=). E possivel fazer a inicializacao de um registro de umaso vez, fornecendo uma lista de valores, de forma similar ao que aprendemos a fazer com vetores.Os valores de tal lista sao atribudos aos campos do registro em questao na mesma ordem em que oscampos sao definidos, conforme exemplo a seguir. Note que a linguagem verifica se os valores em tallista sao compatveis com os tipos dos respectivos campos do registro. Portanto, e importante teratencao a` ordem em que os campos sao especificados na definicao do registro e aos tipos dos valoresque colocamos nesta lista. A inicializacao via lista de valores funciona apenas no ato da criacao davariavel; nao depois. O exemplo da variavel beltrano abaixo ilustra esse caso.

    struct Pessoa {

    int idade;

    string sobrenome;

    };

    int main() {

    Pessoa fulano = {19, "Andre"};

    Pessoa ciclano = {"Barnabe", 20}; // Isso resulta em erro!

    Pessoa beltrano;

    beltrano = {19, "Andre"}; // Isso tambem resulta em erro!

    return 0;

    }

    1.2 Registros Auto-Referenciados

    Um registro pode conter, como um de seus campos, outro registro. No entanto, em C++ nao epermitida a declaracao de um registro que contenha um campo do mesmo tipo do registro (ou umcampo de um tipo que contenha uma variavel do tipo do registro). A razao para este fato e quenao haveria uma forma razoavel de se representar uma estrutura desta natureza em memoria. Noentanto, e possvel se construir registros que possuem ponteiros para registros do mesmo tipo.

    Um registro com esta caracterstica e conhecido como um registro auto-referenciado. Registrosauto-referenciados sao muito comuns nas definicoes de estruturas de dados dinamicas, tais comolistas encadeadas, arvores, grafos, etc. A seguir, fornecemos um exemplo de um registro que poderiaser utilizado para a implementacao de uma lista simplesmente encadeada, conforme veremos maisadiante.

    struct Objeto {

    int dado;

    Objeto * proximo;

    };

    O campo proximo possui uma variavel do tipo ponteiro que aponta para outro registro do tipoObjeto. Desta forma, embora o registro nao possua, de fato, uma variavel do tipo Objeto dentrode si, ele possui uma referencia a um registro Objeto externo. Este artifcio permite a definicaode uma sequencia de registros, na qual um registro faz referencia a outro registro, que por sua vezreferencia outro registro, e assim por diante. Varias estruturas de dados sao definidas por meio douso de registros auto-referenciados similares a Objeto.

    4

  • No caso de um registro X possuir um membro do tipo registro Y, e de o registro Y conter comomembro um ponteiro para um registro do tipo X, temos uma situacao conhecida como referenciacircular, onde X precisa conhecer a definicao de Y, e Y precisa conhecer a declaracao1 de X. Isto e, Ynao precisa conhecer os campos de X, mas precisa saber que existe um tipo de registro com o nomeX. Isto e feito atraves da declaracao do nome de um registro de forma antecipada a` sua definicao.Desta maneira, durante a definicao do registro Y o compilador ja conheceria o nome do registro Xpara o qual Y conteria um ponteiro. O codigo abaixo exemplifica a situacao:

    struct X; // declaracao antecipada

    struct Y {

    int dado;

    X *ponteiro;

    };

    struct X {

    int informacao;

    Y outro;

    };

    Note aqui a diferenca entre a inclusao de um membro que e um registro de certo tipo e a inclusaode um ponteiro para um registro daquele tipo. No primeiro caso, o compilador precisa conhecera exata definicao do registro para reservar o espaco de memoria necessario para a criacao de umavariavel daquele tipo de registro. No segundo caso, nao e necessario conhecermos exatamente adefinicao do tipo (apenas a declaracao de seu nome), ja que ponteiros possuem um tamanho fixo,independente do tipo de estrutura para onde apontam.

    2 Enumeracoes (leitura opcional)

    Uma enumeracao e um tipo de dado que contem um conjunto de valores nominais. O proposito dese utilizar uma enumeracao e o de permitir a escolha de um valor constante dentre um conjuntolimitado de opcoes. Como exemplo, considere o conjunto de naipes em um baralho. O seguinteexemplo ilustra o conceito:

    enum Naipe { OUROS, PAUS, COPAS, ESPADAS };

    int main() {

    Naipe x = COPAS;

    }

    Internamente, cada item em um tipo enumeracao e representado como um valor inteiro, comecandoa partir do valor 0 (zero). Desta forma, no codigo acima, OUROS e igual a 0, PAUS e igual a 1, eassim por diante. O seguinte codigo imprimiria a mensagem COPAS igual a 2 na tela:

    Naipe x = COPAS;

    if (x == COPAS)

    cout

  • Um valor do tipo enumeracao Naipe pode ser utilizado como inteiro para proposito de atribuicoes,comparacoes ou mesmo operacoes aritmeticas.

    enum Naipe { OUROS = 1, PAUS = 3, COPAS = 5, ESPADAS = 7 };

    int main() {

    Naipe x = OUROS;

    int y = x + 4;

    if (y == COPAS) cout