De Objective Caml para C e C++/Construção de tipos: diferenças entre revisões

Origem: Wikilivros, livros abertos por um mundo aberto.
[edição não verificada][edição não verificada]
Conteúdo apagado Conteúdo adicionado
Linha 78: Linha 78:
Define um tipo equivalente em C/C++.
Define um tipo equivalente em C/C++.


===Tipos arranjos===
===Arranjos===

A linguagem C permite declarar arranjos uni-dimensionais, dando as seguintes informações: o tipo dos elementos, e o tamanho do arranjo. Por exemplo, o seguinte código define uma variável <tt>notas</tt> para guardar quatro valores do tipo <tt>float</tt>, utilizaremos o seguinte código:
float notas [4];
Portanto a sintaxe consiste em identificar o tipo dos elementos, através de uma expressão de tipos, o nome do arranjo, e entre colchetes o tamanho do arranjo.

Opcionalmente, podemos associar um valor inicial aos elementos do arranjo assim definido. Há duas possibilidades
* Para definir o mesmo valor em todas as posições do arranjo, colocamos apenas o valor do primeiro elemento. Por exemplo, o código seguinte corresponde à definição de um arranjo similar ao exemplo anterior, mas onde todas as posições do arranjo armazenam o valor <math>0,0</math>:
float notas [4] = { 0.0f };
Portanto a sintaxe exige que a expressão de inicialização seja colocada entre chaves.
* Também pode-se definir individualmente cada posição do arranjo. Isso é realizado colocando entre chaves, a enumeração dos valores do arranjo. O exemplo seguinte portanto é equivalente ao anterior:
float notas [4] = {0.0f, 0.0f, 0.0f, 0.0f};
A sintaxe exige que os elementos da inicialização sejam separados por vírgulas.

====Operadores sobre arranjos====

C e C++ oferecem a possibilidade de acessar cada posição do arranjo individualmente. Como em Objective Caml, o endereço da primeira posição é <math>0</math> e as demais posições são obtidas somando um à anterior. Por exemplo, o código seguinte declara um arranjo e inicializa todas as suas posições em seqüência.
float notas [4];
notas[0] = 0.0f;
notas[1] = 0.0f;
notas[2] = 0.0f;
notas[3] = 0.0f;
Evidentemente, uma repetição <tt>for</tt> é uma construção particularmente adequada para percorrer todas as posições de um arranjo. Por exemplo:
float notas [4];
for (int i = 0; i < 4; ++i)
notas[i] = 0.0f;
Objective Caml possui uma função que, aplicada a um arranjo, retorna o número de posições do arranjo. Isso não existe nem C nem em C++ (C++ tem uma outra implementação de arranjo, chamada <tt>vector</tt> que tem essa funcionalidade-será apresentada mais adiante).

====Um exemplo mais significativo====

float media (float tab[], int n) // calculo da media de um arranjo tab de floats de tamanho n.
{
float sum = 0.0f;
for (int i = 0; i < n; ++i)
sum += tab[i];
return sum/n;
}
int main()
{
int n;
cin >> n; // o numero de alunos e lido
if (n == 0) return 0;
float notas[3][n];
for (int i = 0; i < n; ++i) // para cada aluno
cin >> notas[0][i] >> notas[1][i] >> notas[2][i]; // ler as tres notas e guardar no arranjo notas
for (int i = 0; i < 3; ++i) { // calculo e impressao da media de cada prova
cout << "A media da " << i << "a prova e " << media(tab[i], n) << endl;
}
}


===Tipos registros===
===Tipos registros===

Revisão das 19h29min de 1 de agosto de 2007

Conceitos iniciais Ficheiro:2de8.png

As linguagens C e C++ possuem muitos mecanismos para construir e estruturar dados complexos. Diferentemente dos tipos básicos, onde há uma forte correspondência entre essas linguagens e a linguagem Objective Caml, a construção de tipos complexos em C e C++ é bem diferente daquela provida por Objective Caml. Esse capítulo não aborda a construção de tipos via classes de objetos, que é um paradigma presente nas linguagens Objective Camle e C++, mas que é ausente da linguagem C.

O sistema de tipos de C e C++ é bastante complexo e, em prol da lisibilidade desse texto, algumas aproximações e simplificações foram realizadas. Apresentaremos as seguintes construções para a criação e manipulação de tipos complexos:

  • Enumerações correspondem a uma forma muito básica de tipos variantes de Objective Caml.
  • Arranjos correspondem aos arranjos de Objective Caml, embora sejam objetos muito mais simples. A linguagem C++ provê, através da sua biblioteca, uma outra implementação de arranjos que tem um nível de abstração mais próximo ao dos arranjos de Objective Caml.
  • Registros correspondem aos tipos registros de Objective Caml.
  • Ponteiros correspondem às referências de Objective Caml.
  • As referências, presentes apenas na linguagem C++, não tem correspondência direta em Objective Caml, embora possam ser simuladas por ponteiros, logo pelas referências de Objective Caml.
  • As uniões correspondem aproximadamente aos tipos variantes de Objective Caml, embora não sejam tão práticas para serem manipuladas.
  • Enfim, terminaremos com a apresentação dos tipos funcionais, que existem em C e em C++. Embora não sejam tão flexíveis quanto os tipos funcionais de Objective Caml, permitem ainda programação de ordem superior.

Vale destacar que em C e em C++, pode-se dar um nome a um tipo, utilizando a seguinte construção, ou alguma variação:

typedef expressaodetipo nome;

Por exemplo, podemos definir um tipo chamado inteiro que é idêntico ao tipo básico int com a seguinte construção:

typedef int inteiro; // exemplo de definição de um tipo chamado "inteiro", que nada mais é que o tipo int

Então a mais simples expressão de tipo que exista é um nome de um tipo básico, ou de outro tipo que já foi definido dessa forma. Uma vez definido um nome para um tipo, ele pode ser usado para declarar variáveis ou funções da mesma forma que os tipos básicos. Por exemplo:

inteiro soma3 (inteiro a, inteiro b, inteiro c) // exemplo (artificial) onde usamos um nome de tipo definido por nós
{
  inteiro resultado = a;
  resultado += b;
  resultado += c;
  return resultado;
}

Também pode ser utilizar uma expressão de tipo diretamente na declaração de uma variável. Assim esse código:

struct Spoint { // nesse exemplo, usamos uma expressão de tipo registro, detalhes sobre essa construção seguem mais adiante
  double x;
  double y;
} point; // point é uma variável cujo tipo é um tipo registro struct Spoint

é equivalente a

typedef struct Spoint {
 double x;
 double y;
} Tpoint; // definimos Tpoint como o nome de um tipo registro struct Spoint
Tpoint point; // point é uma variável cujo tipo é Tpoint, ou seja o tipo registro struct Spoint

Enumerações Ficheiro:3de8.png

Com relação ao sistema de tipos de Objective Caml, os tipos enumerados lembram de forma superficial os tipos variantes. Os tipos enumerados são porém muito mais limitados, e correspondem mais precisamente a tipos variantes onde as alternativas devem ser todas constantes.

Um tipo enumerado contem um número finito de valores. Cada valor tem um nome que o identifica. Por exemplo a seguinte definição:

enum Ecor {vermelho, azul, amarelo};

introduz um tipo enumerado, que possui como rótulo Ecor, e três enumeradores, que são valores inteiros constantes com identificadores vermelho, azul, amarelo.

Pode-se dar um nome a esse tipo, utilizando uma definição de tipo:

typdef enum Ecor {vermelho, azul, amarelo} Tcor;

Em seguida, podemos declarar e utilizar variáveis com esse tipo, e os valores que foram introduzidos na operação podem também aparecer no programa, onde serão consideradas como valores inteiros. Segue um trecho de programa que utiliza a definição acima:

void imprime_cor_em_ingles (Tcor c) // o parâmetro poderia também ter sido declarado como enum Ecor c
{
  switch (c1) {
    case vermelho:
      printf("red");
      break;
    case azul:
      printf("blue");
      break;
    case vermelho:
      printf("amarelo");
      break;
  }
}

Afirmamos que um valor inteiro é associado a cada valor de uma enumeração. Podemos realizar essa associação de forma implícita ou explícita. A forma explícita é realizada associando o número inteiro na definição da enumeração, como demostrado no seguinte exemplo:

enum Edirecao { norte = 0; oeste = 90; sul = 180; leste = 270 };

Caso não aparece associação explícita, a associação é realizada de maneira implícita, utilizando as seguintes regras: o primeiro valor da enumeração recebe o valor zero, e um valor que não está na primeira posição é associado com a soma de um com o inteiro associado ao valor anterior.

Finalmente, podemos também misturar as associações explícitas e implícitas, como no seguinte exemplo:

enum Ecodigo { NO_ERROR = 0; IO_ERROR = 10; FORMAT_ERROR; TIMEOUT_ERROR };

Nesse exemplo, FORMAT_ERROR e TIMEOUT_ERROR denotam respectivamente os inteiros e .

Exercício

Considere o seguinte tipo de dados definido em Objective Caml

type card_suit_t = Spades | Hearts | Diamonds | Clubs

Define um tipo equivalente em C/C++.

Arranjos

A linguagem C permite declarar arranjos uni-dimensionais, dando as seguintes informações: o tipo dos elementos, e o tamanho do arranjo. Por exemplo, o seguinte código define uma variável notas para guardar quatro valores do tipo float, utilizaremos o seguinte código:

float notas [4];

Portanto a sintaxe consiste em identificar o tipo dos elementos, através de uma expressão de tipos, o nome do arranjo, e entre colchetes o tamanho do arranjo.

Opcionalmente, podemos associar um valor inicial aos elementos do arranjo assim definido. Há duas possibilidades

  • Para definir o mesmo valor em todas as posições do arranjo, colocamos apenas o valor do primeiro elemento. Por exemplo, o código seguinte corresponde à definição de um arranjo similar ao exemplo anterior, mas onde todas as posições do arranjo armazenam o valor :
float notas [4] = { 0.0f };

Portanto a sintaxe exige que a expressão de inicialização seja colocada entre chaves.

  • Também pode-se definir individualmente cada posição do arranjo. Isso é realizado colocando entre chaves, a enumeração dos valores do arranjo. O exemplo seguinte portanto é equivalente ao anterior:
float notas [4] = {0.0f, 0.0f, 0.0f, 0.0f};

A sintaxe exige que os elementos da inicialização sejam separados por vírgulas.

Operadores sobre arranjos

C e C++ oferecem a possibilidade de acessar cada posição do arranjo individualmente. Como em Objective Caml, o endereço da primeira posição é e as demais posições são obtidas somando um à anterior. Por exemplo, o código seguinte declara um arranjo e inicializa todas as suas posições em seqüência.

float notas [4];
notas[0] = 0.0f;
notas[1] = 0.0f;
notas[2] = 0.0f;
notas[3] = 0.0f;

Evidentemente, uma repetição for é uma construção particularmente adequada para percorrer todas as posições de um arranjo. Por exemplo:

float notas [4];
for (int i = 0; i < 4; ++i)
  notas[i] = 0.0f;

Objective Caml possui uma função que, aplicada a um arranjo, retorna o número de posições do arranjo. Isso não existe nem C nem em C++ (C++ tem uma outra implementação de arranjo, chamada vector que tem essa funcionalidade-será apresentada mais adiante).

Um exemplo mais significativo

float media (float tab[], int n) // calculo da media de um arranjo tab de floats de tamanho n.
{
  float sum = 0.0f;
  for (int i = 0; i < n; ++i)
    sum += tab[i];
  return sum/n;
}
int main()
{
  int n;
  cin >> n; // o numero de alunos e lido
  if (n == 0) return 0;
  float notas[3][n];
  for (int i = 0; i < n; ++i) // para cada aluno
    cin >> notas[0][i] >> notas[1][i] >> notas[2][i]; // ler as tres notas e guardar no arranjo notas
  for (int i = 0; i < 3; ++i) { // calculo e impressao da media de cada prova
    cout << "A media da " << i << "a prova e " << media(tab[i], n) << endl;
  }
}

Tipos registros

Um tipo em c++ é parecido com o tipo registro em ocaml e sua sintaxe è:

struct NOME {
 Corpo
 };

Onde NOME é o nome do tipo a ser criado e Corpo será oque ele deverá armazenar exemplo:

struct ponto {
 int x;
 int y;
 }

Isso criaria um tipo ponto que armazanaria 2 valores inteiros e equivaleria ao seguinte codigo escrito em ocaml:

type ponto = { x : int ; y : int };;

E para acessar os campos é a mesma coisa que em ocaml nome do tipo seguido do campo exemplo :

ponto a;
a.x = 3;
a.y = 4;

Isso faria uma varivel a do tipo ponto com x = 3 e y = 4.

Ponteiros

Tipos referências

Tipos uniões

Tipos funções