2014

Clase 7

Menu Principal | Clase 1 | Clase 2 | Clase 3 | Clase 4 | Clase 5 | Clase 6

Arreglos y Punteros

Esta vez comenzaremos con dos problemas que usted deberá intentar por sí mismo. Al final de la clase o al comenzar la siguiente podemos ver una solución como referencia. Cualquier duda de implementación (es decir, cómo se programa determinada cosa) la veremos caso a caso, pero es fundamental que ustedes mismos piensen los algoritmos, es decir, paso a paso lo que el programa debe hacer, para ambos problemas.

Ordenamiento sencillo de un arreglo

Usted deberá escribir un programa que:

  1. Llene un arreglo de enteros de tamaño 50 con números aleatorios entre 1 y 100.
  2. Copie en un segundo arreglo (obviamente también de tamaño 50) los valores contenidos en el primer arreglo, pero ordenados de menor a mayor. Este arreglo ordenado es el que debe mostrarse en pantalla.

Hints:

  1. El programa deberá recorrer el primer arreglo completo varias veces, buscando el menor de los números para copiarlo al segundo arreglo.
  2. Debe invalidar el valor en el primer arreglo que fue recién copiado, para evitar copiarlo de nuevo en el ciclo siguiente. Una buena forma de invalidar el valor es copiar un valor fuera de rango (fácilmente reconocible), como -1.
  3. Para encontrar el menor de los elementos de un arreglo, guarde el mínimo actual en una variable aparte, y compare cada uno con ese mínimo actual. Si encuentra un elemento menor que ese mínimo, reemplace el mínimo actual con ese nuevo elemento.

Una posible solución

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int main()
{
//arreglo random con 5 valores
  int arreglo[5];
//arreglo ordenado con 5 valores
  int ao[5];
//generando semillas al azar
  srand(time(NULL)+getpid());
  int e=0;
//inicializando los arreglos
  for(int i=0;i<5;i++)
   {
     arreglo[i]=0;
     ao[i]=0;
   }
  printf("Imprimiendo el arreglo al azar\n");
//dando valores random entre 1 y 100 al arreglo[]
  for(int i=0;i<5;i++)
   {
     e=1+(rand()%100);
     arreglo[i]=e;
     printf("%d\n",arreglo[i]);
   }
  int menor;
  int indice;
  printf("Imprimiendo el arreglo ordenado de menor a mayor\n");
  for(int j=0; j<5;j++)
  {
   menor = 101;
   for(int k=0; k<5;k++)
   {
     if(arreglo[k]<menor)
      {
       menor=arreglo[k];
       indice=k;
      }
   }
   arreglo[indice]=101;
   ao[j]=menor;
   printf("%d\n",ao[j]);
  }
return 0;
}

Cálculo de un histograma

Ahora, usted deberá escribir un programa que, dado una distribución aleatoria de números reales generada por la siguiente función (que ud. deberá copiar y pegar en su programa),

float DistProb()
{
 float x;
 x = 0.999999*pow(cos(2.0*3.14159*drand48()),2.0);
 return x;
}

que genera números aleatorios en el intervalo [0, 1) de manera no uniforme, calcule el histograma y lo muestre en pantalla como una tabla, donde la primera columna es x y la segunda la probabilidad de que aparezca el valor x. Para conseguir esto, dividiremos el intervalo [0, 1) en N segmentos, y debemos tener un arreglo de tamaño N donde ir "contando" la aparición de cada número que cae en un cierto segmento. Un buen valor para N puede ser 200.

Genere histogramas para 10000, 100000 y 1 millón de muestras (este NO es el valor de N!) y vea cómo el histograma se va "suavizando" cada vez más.

Hints:

  1. Para saber en qué segmento (numerados entre 0 y N-1) cae un determinado valor x, multiplíquelo por N y redondee hacia abajo, usando para ello la función floor de la librería matemática (math.h)
  2. No se olvide de inicializar el generador de números aleatorios. Para esto, basta usar srand48(time(NULL)) al principio de main().
  3. El histograma será un arreglo de enteros de tamaño N, inicializados a cero, y la casilla k del arreglo se incrementará en uno cada vez que se detecte un valor x que cae en el segmento k.

Lista mixta utilizando punteros

Compile y ejecute el siguiente programa:

#include <stdio.h>

int counter;

void VaciaLista(void ** lista, int largo)
{
 int i;
 for (i=0;i<largo;++i)
     lista[i] = NULL;
}

void AgregarEntero(void ** lista, int * tipo, int * valor)
{
 lista[counter] = valor;
 tipo[counter] = 1;
 counter++; 
}

void AgregarString(void ** lista, int * tipo, char * str)
{
 lista[counter] = str;
 tipo[counter] = 2;
 counter++; 
}

void AgregarReal(void ** lista, int * tipo, float * valor)
{
 lista[counter] = valor;
 tipo[counter] = 3;
 counter++; 
}

void MostrarLista(void ** lista, int * tipo)
{
 int i;
 for (i=0;((i<counter) && (lista[i] != NULL));++i)
 {
  if (tipo[i] == 1)
  {
   int * p = lista[i];
   printf("Entero: %d\n", *p);
  }
  else if (tipo[i] == 2) 
  {
   char * p = lista[i];
   printf("String: %s\n", p);
  }
  else if (tipo[i] == 3)
  { 
   float * p = lista[i];
   printf("Real: %f\n", *p);
  }
  else printf("Tipo incorrecto: %d\n", tipo[i]);
 }
}

int main()
{
 void * lista[10];
 int tipo[10];
 counter = 0;
 int x = 42;
 float y = 2.71828;
 VaciaLista(lista, 10);
 AgregarEntero(lista, tipo, &x);
 AgregarString(lista, tipo, "hola mundo");
 AgregarReal(lista, tipo, &y);
 MostrarLista(lista, tipo);
 return 0;
}

Luego:

  1. Estudie muy bien lo que hace, comenzando por entender main() y luego cada una de las funciones (definidas al comienzo del programa) que son llamadas en main().
  2. Por qué se usan punteros a void?
  3. Por qué en las declaraciones de las funciones se declara lista como void ** lista?
  4. Por qué es necesario tener además de lista un arreglo adicional, tipo?
  5. Por qué en MostrarLista el ciclo for tiene una doble condición de parada?
  6. Cómo modificaría el programa para usar dos listas en vez de una? Inténtelo y agregue distintos elementos en cada lista.
  7. Intente implementar una función que devuelva la longitud (número de elementos en uso) de la lista. Esto es, en el programa actual, devolvería 3, no 10.

University

Personal

edit SideBar