/**********************************************************************

Exemplo de ponteiros para complexos.  Neste programa, a declaracao

  Complexo z;

declara z como ponteiro para um complexo.  Desta forma, a sua parte 
real 'e

  z->Re

e sua parte imaginaria 'e

  z->Im

O uso de ponteiros para estruturas, ao inves de variaveis do tipo da
estrutura, 'e muitas vezes mais eficiente.  

Este programa tambem ilustra o uso de malloc().  

Este programa 'e uma versao alternativa de vetor_complexo.

**********************************************************************/
#include <stdio.h>
#include <stdlib.h>

#define DEBUG 0

typedef struct {
  double Re;
  double Im;
} sComplexo, *Complexo; /* Agora Complexo 'e um tipo ponteiro. */

void imprima_complexo(Complexo z)
{
  printf("Parte real = %.5lf\n", z->Re);
  printf("Parte imaginaria = %.5lf\n", z->Im);
}

Complexo soma(Complexo z1, Complexo z2)
{
  Complexo z;

  /* Alocamos memoria para a estrutura a ser apontada por z. */
  z=(Complexo)malloc(sizeof(sComplexo));
  if (z==NULL) {
    fprintf(stderr, "Erro na alocacao de memoria!\n");
    exit(1);
  }

  z->Re=z1->Re+z2->Re;
  z->Im=z1->Im+z2->Im;

  return z;
}  

Complexo complexo_aleatorio()
{
  Complexo z;

  /* Alocamos memoria para a estrutura a ser apontada por z. */
  z=(Complexo)malloc(sizeof(sComplexo));
  if (z==NULL) {
    fprintf(stderr, "Erro na alocacao de memoria!\n");
    exit(1);
  }

  z->Re=(double)rand()/RAND_MAX; 
  z->Im=(double)rand()/RAND_MAX; 
  /* RAND_MAX e o maior valor que rand() */
  /* pode devolver. */

  if (rand()%2) z->Re=-z->Re;
  if (rand()%2) z->Im=-z->Im;

  return z;
}

void leia_entrada(int *n, unsigned int *s)
{
  printf("Entre o numero de complexos a serem gerados: ");
  scanf("%d", n);
  printf("Entre uma semente (um inteiro nao-negativo): ");
  scanf("%ud", s);
}
     
main()
{
  int k, n;
  unsigned int s;
  Complexo *z,       /* z 'e um ponteiro para ponteiros! */
            z_total;

  leia_entrada(&n, &s);
  srand(s); /* Inicializa o gerador de numeros aleatorios */

  /* Alocamos agora espaco para n ponteiros do tipo Complexo. */
  z=(Complexo *)malloc(n*sizeof(Complexo));
  if (z==NULL) {
    fprintf(stderr, "Erro na alocacao de memoria!\n");
    exit(1);
  }

  for (k=0; k<n; ++k) {
    z[k]=complexo_aleatorio();
    if (DEBUG) {
      printf("z[%d]->Re=%.3f\n", k, z[k]->Re);
      printf("z[%d]->Im=%.3f\n\n", k, z[k]->Im);
    }
  }

  /* Alocamos memoria para a estrutura apontada por z_total. */
  z_total=(Complexo)malloc(sizeof(sComplexo));
  if (z==NULL) {
    fprintf(stderr, "Erro na alocacao de memoria!\n");
    exit(1);
  }

  z_total->Re=0.0;
  z_total->Im=0.0;

  for (k=0; k<n; ++k) {
    z_total->Re+=z[k]->Re;
    z_total->Im+=z[k]->Im;
  }

  z_total->Re=z_total->Re/n;
  z_total->Im=z_total->Im/n;;
  
  imprima_complexo(z_total);

  return 0;
}
