Noticias:

Corolario #1 de internet: En internet toda mujer es hombre, todo hombre es niño y todo niño es un agente del FBI, hasta que se demuestre lo contrario.

Menú Principal

Curso de iniciación en programación C

Iniciado por Thylzos, 23 de Junio de 2008, 09:26

0 Miembros y 2 Visitantes están viendo este tema.

Thylzos

12- Estructuras dinámicas

La memoria, como todo recurso, es escaza. De este modo, cuando por ejemplo definimos un array de tamaño 7 y usamos sólo 3 de sus celdas, estamos desperdiciando memoria. De la misma manera, se puede dar el caso en que definamos uno de 7 y necesitemos 10, entonces nos falta memoria. Para esto existe la designación dinámica de memoria, es decir, reservamos memoria en un momento de la ejecución para el programa que estamos haciendo. Igualmente, cuando ya no necesitamos dicha memoria, tenemos que liberarla para que pueda ser usada por otro programa y que no haya errores en el sistema (sí, como los ficheros).

12.1- Definiciones

-Nodo: Unidad de una colección de estructuras dinámicas. Además de sus datos correspondientes, tienen una variable puntero que apunta hacia el siguiente elemento

- Lista: Colección de elementos. Conjunto de elementos asignados mediante estructuras dinámicas (nodos) encadenados entre sí (cada uno tiene la dirección de memoria del siguiente). La dirección de memoria del primer nodo la tiene una variable puntero independiente. De este modo queda: un puntero que apunta al primer nodo, un puntero del primer nodo que apunta al segundo, un puntero del segundo nodo que apunta al tercero... y un puntero del último que apunta a NULL.

- Pilas: Variable de las listas en las que las inserciones de nodos en ella son siempre al principio y que las consultas y borrados son siempre del primer nodo. Para entender su funcionamiento, sepamos que se comporta así: primero en entrar, último en salir.

- Cola: Variable de las listas en las que las inserciones de nodos en ella son siempre al final y que las consultas y borrados son siempre del primer nodo. Para entender su funcionamiento, sepamos que se comporta así: primero en entrar, primero en salir.

12.2- Reserva y liberación de memoria.

Para reservar memoria para un puntero, tenemos la función malloc de stdlib.h. Su forma de uso general es la siguiente:

puntero = (tipo *) malloc (bytes);

Donde puntero es el puntero para el que queremos reservar memoria. Después, tipo es el tipo de dato que vamos a almacenar en dicho espacio de memoria. Por último, bytes es el número de bytes que queremos reservar.

Después de esto, todo sigue como siempre, podemos usar los operadores de punteros y dicho puntero con total normalidad para trabajar con la porción de espacio de memoria que hemos reservado. Pero como todo, acaba y cuando dejemos de usar el puntero en cuestión, debemos liberar la memoria. Para ello tenemos la función free de stdlib.h, cuyo modo de uso es:

[code]free (puntero);


Donde, logicamente, puntero es el puntero donde anteriormente reservamos memoria con malloc. Veamos un ejemplo:

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

struct t_ficha {
   int numero;
   char palabra [30]; }

int main (void) {
struct t_ficha *mi_ficha;

mi_ficha = (struct *) malloc (sizeof(struct t_ficha));

printf ("Escriba un número : ");
scanf ("%d", &mi_ficha->numero);

fflush (stdin);

printf ("Escribe una palabra: ");
gets (mi_ficha->palabra);

free (mi_ficha);
}


No recuerdo si Master lo explicó en el capítulo de las estrcturas, pero por si acaso aclaro que para acceder a los elementos de un puntero a estructura no se usa el ., sino que una flechita: ->.

12.3- Listas

Las operaciones básicas que podemos hacer sobre una lista de estructuras dinámicas son: insertar un nodo al principio de la lista, insertar un nodo de forma ordenada según los datos que contiene, insertar un nodo al final y borrar un nodo. Para estudiarlas usaremos nodos que contendrás como dato propio sólo un número. Así:

struct t_nodo {
int numero;
t_nodo *siguiente; }


Numero es el número, *siguiente es el puntero al siguiente nodo. Iremos haciendo funciones que manejen la lista (una que añada elementos, una que los busque...) para entender todos los conceptos de éstas.

12.3.1- Insertar al principio

Para realizar esta función, en primer lugar crearemos el nodo y le daremos valores. Luego nos fijamos en el puntero que apunte al primer elemento de la lista, si su valor es NULL, quiere decir que la lista está vacía. En dicho caso, le daremos al puntero el valor de la dirección de memoria del nuevo nodo. Si no, ponemos en la variable "siguiente" la dirección a la que apunta el puntero que apunta al principio (apartir de ahora lo llamaremos "primero") y a dicho puntero le ponemos como valor la dirección de memoria donde está el nuevo nodo. Quizá sea algo difícil de comprender en principio, así que veamos un ejemplo:

void insertar_al_principio (struct t_nodo *p) { /**p es primero (el puntero que apuntaba al primer nodo*/
/*Creamos el nuevo nodo*/
struct t_nodo *nuevo_nodo;
nuevo_nodo= (struct *) malloc (sizeof (struct t_nodo));

/*Le damos un valor*/
printf ("Introduzca un número: ");
scanf ("%d", &nuevo_nodo->numero);

/*Insertamos el nodo al principio*/

/*Hacemos que el campo "siguiente" del nuevo nodo apunte a p (el anterior primer nodo)*/
nuevo_nodo->siguiente = p;
/*Ahora p, es decir, el puntero que apunta al principio, pasa a apuntar al nuevo nodo*/
p = nuevo_nodo;
}


12.3.2- Insertar al final

Para hacer esta función, empezamos como la anterior. Creamos el nodo y le damos datos. Luego, si la lista está vacía, pongo que primero apunte al nuevo nodo y al campo "siguiente" del nuevo nodo le pongo el valor NULL. Si no está vacía, le ponemos al puntero "siguiente" del nuevo nodo el valor NULL y para agregarlo a la lista, la recorremos hasta llegar al final y a este último le ponemos en el valor "siguiente" la dirección de memoria donde está el nuevo nodo.

void insertar_al_final (struct t_nodo *p) {
struct t_nodo *nuevo_nodo, *aux; /**aux es para recorrer la lista*/

/*Reservamos memoria*/
nuevo_nodo = (struct *) malloc (sizeof (struct t_nodo));

/*Escribimos los datos*/
printf ("Ponga un número: ");
scanf ("%d", &nuevo_nodo->numero);

/*Le ponemos NULL a su "siguiete", ya que será el último*/
nuevo_nodo->siguiente = NULL;

/*E insertamos al final: */
if (p != NULL) {
   aux = p; /**aux apunta al primero*/
   while (aux->siguiente != NULL)
      aux = aux->siguiente; /*E irá apuntando a los siguientes hasta llegar al final*/
   aux->siguiente = nuevo_nodo; /*El puntero "siguiente" del último nodo pasa a apuntar al nuevo nodo*/
}
else
   p = nuevo_nodo;
}


12.3.3- Insertar ordenado

Además de lo anterior, en función a un criterio de ordenación en base a los datos de los nodos, podemos insertar a los nuevos de forma ordenada. Para hacer esto, creamos el nodo, le ponemos los datos, recorremos la lista hasta llegar a donde debería estar y lo ubicamos. Así, podría acabar al principio, al final o en medio de dos. Si acaba en medio de dos, debemos poner al puntero "siguiente" del nuevo nodo la dirección de memoria del nodo de la derecha y al "siguiente" de la izquierda la dirección de memoria del nuevo.

Por ejemplo, podemos insertar el nodo en una lista ordenada de menor a mayor:

void insertar_ordenado (struct t_nodo *p) {
struct t_nodo *nuevo_nodo, *anterior, *actual;

/*Creamos y rellenamos el nuevo*/
nuevo_nodo = (struct *) malloc (sizeof (struct t_nodo));
printf ("Inserte un número: ");
scanf ("%d", &nuevo_nodo->numero);

/**actual apunta al principio: */
actual = p;

/*Mientras no se llegue al final y el número del nodo en el que nos encontramos sea menor que el número del nuevo nodo*/
while ((actual != NULL) && (actual->numero < nuevo_nodo->numero)) {
   anterior = actual;
   actual = actual->siguiente; }

if (p == actual) {
/*Si actual es igual al primero, es que hay que ponerlo al principio*/
   nuevo_nodo->siguiente = p;
   p = nuevo_nodo; }
else {
/*Y si no, se inserta entre anterior y actual*/
anterior->siguiente = nuevo_nodo;
nuevo_nodo->siguiente = actual; }
}


12.3.4- Borrar

Para borrar uno, recorremos la lista hasta encontrar el correspondiente. Asignamos al campo "siguiente" del nodo a borrar al campo "siguiente" del nodo situado a la izquierda (o a "primero" o "p" si estamos en el primer nodo). Por último, asignamos al campo "siguiente" del nodo a borrar el valor NULL y se elimina.

void borrar (struct t_nodo *p) {
struct t_nodo anterior, actual;
int numero;

printf ("¿Qué número de la lista desea borrar?");
scanf ("%d", &numero);

actual = p;

/*Mientras no lleguemos al final y el valor "numero" del nodo "actual" sea distinto a "numero"*/
while ((actual != NULL) && (actual->numero != numero)) {
   anterior = actual;
   actual = actual->siguiente; }

/*Comprobamos que el número esté en la lista*/
if (actual != NULL) {
   if (actuall == p) {
      p = actual->siguiente;
      actual->siguiente = NULL;
      free (actual); }
   else {
      anterior->siguiente = actual->siguiente;
      actual->siguiente = NULL;
      free (actual); } }
}


12.3.5- Buscar

Ahora vamos a buscar un número en la lista en base a lo que nos dice uno que nos dice el usuario.

void buscar (struct t_nodo *p) {
struct t_nodo actual;
int encontrado = 0;
int numero;

printf ("Escribe el número que quieres buscar: ");
scanf ("%d", &numero);

actual = p;

while ((actual != NULL) && (encontrado == 0)) {
   if (actual->numero == numero)
      encontrado = 1;
   actual = actual->siguiente; }

if (encontrado == 1)
   printf ("Se ha encontrado el número.");
else
   printf ("No se ha encontrado el número.");
}


12.3.6- Mostrar

También podemos hacer una función que muestre todos los números.

void mostrar_todo (struct *p) {
struct t_nodo *actual;

actual = p;

if (p == NULL)
   printf ("La lista está vacía.");
else {
   while (actual != NULL ) {
      printf ("%d ", actual->numero);
      actual = actual->siguiente; } }
}


12.3.7- Borrar todo.

Como no podía ser de otra forma, también podemos borrar todos los datos de la lista:

void borrar_todo (struct t_nodo *p) {
struct t_nodo *nodo;

while (p != NULL) {
   nodo = p;
   p = p->siguiente;
   nodo->siguiete = NULL;
   free (nodo); }
}


12.4- Pilas

Como tanto las colas como las pilas son variables de las listas, pero en escencia lo mismo, las iremos viendo por encima y con menos profundidad que las anteriores.

12.4.1- Insertar

Recordemos que la pila inserta siempre al principio ("Último en entrar, primero en salir"). Para entender esto mejor, piensen en una pila de libros, vas poniendo libros en la cima y para quitarlos empiezas por el último, nosotros asumiremos que la variable "p" o "primero" apunta a la cima de la pila.

void insertar_en_pila (struct t_nodo *p) {
struct t_nodo *nuevo_nodo;

nuevo_nodo = (struct *) malloc (sizeof (struct t_nodo));

printf ("Escriba un número: ");
scanf ("%d", nuevo_nodo->numero);

nuevo_nodo->siguiente = p;
p = nuevo_nodo;
}


12.4.2- Borrar

Como es una pila, tendremos que borrar el que esté encima de ella, es decir, al que apunte "primero" o "p".

void borrar (struct t_nodo *p) {
atruct t_nodo *actual;

actual = p;

if (p != NULL) {
   p = actual->siguiente;
   actual->siguiente = NULL;
   free (actual); }
else
   printf ("La pila está vacía.");
}


12.4.3- Mostrar

Y para ver el número que está en la cima de la pila:

void mostrar (struct t_nodo *p) {
struct t_nodo *actual;

actual = p;

if (p == NULL)
   printf ("La pila está vacía.");
else
   printf ("%d", actual->numero);
}


12.4.4- Borrar todo

Para borrar todo en una pila, la función de la lista funciona a la perfección.

12.5- Colas

12.5.1- Insertar

Como en las colas los nodos que se insertan van siempre al final, la función insertar_al_final vendría que ni pintada. Eso sí, es normal que para facilitar el trabajo con las colas se use también un puntero que apunte al final.

12.5.2- Borrar

Igual que la función borrar de las pilas.

12.5.3- Mostrar

Igual que la función mostrar_todo de las pilas-

12.5.4- Borrar todo

Igual que la función borrar_todo de las pilas.

12.6- Ejercicios

Pues ahora empezamos con los ejercicios interesantes:

1.- Haz un programa que imite el comportamiento de una cola para entrar al cine. Es decir, que agregue una persona a la cola, que la quite... en fin, todo lo que se hace en esos divertidos momentos.

2.- Haz un programa que tengaun registro de alumnos, el nodo deberá tener como mínimo: el nombre del alumno, su nota en matemáticas, su nota en lengua, su nota en inglés y la media. Deberán estar ordenados en orden alfabético en función del nombre. Haz que se pueda ingresar nuevos alumnos, que se pueda buscar el que tenga la mejor nota en tal materia o el mejor promedio y al que tenga peor nota en tal materia o el peor promedio. También da la posibilidad de buscar en base a un nombre y mostrar todos los datos de ese alumno. Por supuesto, debes permitir que se muestren todos los datos de todos los alumnos, sólo sus notas, sólo sus promedios y sólo sus nombre. Además, deberás dejar que el programa deje borrar al usuario los que no se van a usar. Y como fruta del postre, que se puedan guardar los datos en un fichero binario.


El Reto

Harás un mini-juego. En él habrá dos listas, una con todos los objetos que se pueden conseguir y que estará en un archivo que se leerá al comienzo del juego y otra con los objetos que tiene su personaje. El funcionamiento será el siguiente: habrá un 50% de que se encuentre un nuevo objeto, si se hace se encontrará el que esté más cerca del principio que no se tenga ya; luego un 30 % de perder un sólo objeto (se perderá uno aleatorio) y un 20% de perderlos todos. Ganas cuando los encuentras a todos. Además, el juego se puede guardar en otro archivo binario a parte del ya mencionado.

Truco: para generar números aleatorios y manejar posibilidades tenemos la función rand (), de stdlib.h. Ésta genera un número entre 0 y RAND_MAX (una constante con un número muy muy grande). Para ajustar la función a un conjuto de números entre 0 y N, tendríamos que hacer:

numero = rand () % (N + 1);

Si, por ejemplo, no queremos que empiece por N, tendríamos que sumar una cantidad a lo anterior. Por ejemplo, genremos números entre 1 y 10:

numero = rand () % 10 + 1;




P.D.: Me salió un capítulo muy lioso, recomiendo leerlo más de una vez porque me expliqué de pena.[/code]

Gracias freyi *.*


Cita de: Gambit en 26 de Enero de 2010, 10:25
Follar cansa. Comprad una xbox 360, nunca le duele la cabeza, no discute, no hay que entenderla, la puedes compartir con tus amigos...

Thylzos

Soluciones del 12º capítulo

Citar1.- Haz un programa que imite el comportamiento de una cola para entrar al cine. Es decir, que agregue una persona a la cola, que la quite... en fin, todo lo que se hace en esos divertidos momentos.

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

struct t_persona {
   char nombre [30];
   struct t_persona *siguiente; }

void nueva_persona (struct t_persona *p);

void persona_menos (struct t_persona *p);

void mostrar (struct t_persona *p);

void cerrar (struct t_persona *p);

int main (void) {
struct t_persona *principio = NULL;
int opcion;

printf ("¿Qué es lo que pasa?\n1- Llega alguien a la cola\n2- Alguien entra al cine (y sale de la cola)\n3- Miras a ver quién hay\n4- Cierra el cine\n5- Salir");
scanf ("%d", &opcion);

do {
   if (opcion == 5)
      return 0;
   switch (opcion) {
      case 1: nueve_persona (principio);
              break;
      case 2: persona_menos (principio);
              break;
      case 3: mostrar (principio);
              break;
      case 4: cerrar (principio);
              break;
      case 5: printf ("Nos vamos...");
              break;
      default: printf ("Opción inválida");
               break;

   printf ("\n¿Qué es lo que pasa?\n1- Llega alguien a la cola\n2- Alguien entra al cine (y sale de la cola)\n3- Miras a ver quién hay\n4- Cierra el cine\n5- Salir");
   scanf ("%d", &opcion);
} while (opcion != 5)
return 0;
}

void nueva_persona (struct t_persona *p) {
struct t_persona *nuevo_nodo, *aux;

nuevo_nodo = (struct *) malloc (sizeof (struct t_nodo));

printf ("\n¿Cómo se llama?");
gets (nuevo_nodo->nombre);

nuevo_nodo->siguiente = NULL;

if (p != NULL) {
   aux = p;
   while (aux->siguiente != NULL)
      aux = aux->siguiente;
   aux->siguiente = nuevo_nodo;
}
else
   p = nuevo_nodo;
}

void persona_menos (struct t_persona *p) {
struct t_persona *actual;

actual = p;

if (p != NULL) {
   p = actual->siguiente;
   actual->siguiente = NULL;
   free (actual); }
else
   printf ("\nLa cola está vacía.");
}

void mostrar (struct t_persona *p) {
struct t_persona *actual;

actual = p;

if (p == NULL)
   printf ("La lista está vacía.");
else {
   while (actual != NULL ) {
      printf ("\n%s ", actual->nombre);
      actual = actual->siguiente; } }
}

void cerrar (struct t_persona *p) {
struct t_persona *nodo;

while (p != NULL) {
   nodo = p;
   p = p->siguiente;
   nodo->siguiete = NULL;
   free (nodo); }
}


Citar2.- Haz un programa que tengaun registro de alumnos, el nodo deberá tener como mínimo: el nombre del alumno, su nota en matemáticas, su nota en lengua, su nota en inglés y la media. Deberán estar ordenados en orden alfabético en función del nombre. Haz que se pueda ingresar nuevos alumnos, que se pueda buscar el que tenga la mejor nota en tal materia o el mejor promedio y al que tenga peor nota en tal materia o el peor promedio. También da la posibilidad de buscar en base a un nombre y mostrar todos los datos de ese alumno. Por supuesto, debes permitir que se muestren todos los datos de todos los alumnos, sólo sus notas, sólo sus promedios y sólo sus nombre. Además, deberás dejar que el programa deje borrar al usuario los que no se van a usar. Y como fruta del postre, que se puedan guardar los datos en un fichero binario.

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

struct t_alumno {
   char nombre [30];
   int mates;
   int lengua;
   int ingles;
   float media;
   struct t_alumno *siguiente }

void insertar_alumno (struct t_alumno *p);

void buscar (struct t_alumno *p);

void mostrar (struct t_alumno *p);

void quitar_alumno (struct t_alumno *p);

void guardar (struct t_alumno *p);

void recuperar (struct t_alumno *p);

int main void {
struct t_alumno *principio = NULL;
int opcion;

printf ("¿Qué desea hacer?\n1- Agregar un alumno\n2- Buscar un alumno\n3- Mostrar alumno\n4- Quitar alumno\n5- Guardar\n6- Recuperar\n7- Salir");
scanf ("%d", &opcion);

while (opcion !=6 ) {
   switch (opcion) {
      case 1: insertar_alumno (principio);
              break;
      case 2: buscar (principio);
              break;
      case 3: mostrar (principio);
              break;
      case 4: quitar_alumno (principio);
              break;
      case 5: guardar (principio);
              break;
      case 6: recuperar (principio);
              break;
      case 7: printf ("Adiós...");
              break;
      default: printf ("Opción inválida");
               break; }
   
   printf ("\n¿Qué desea hacer?\n1- Agregar un alumno\n2- Buscar un alumno\n3- Mostrar alumno\n4- Quitar alumno\n5- Guardar\n6- Recuperar\n7- Salir");
   scanf ("%d", &opcion);
}
return 0;
}

void insertar_alumno (struct t_alumno *p) {
struct t_alumno *nuevo_nodo, *anterior, *actual;

nuevo_nodo = (struct *) malloc (sizeof (struct t_nodo));

printf ("\nInserte el nombre: ");
gets (nuevo_nodo->nombre);
printf ("\nNota de mates: ");
scanf ("%d", nuevo_nodo->mates);
printf ("\nNota de lengua: ");
scanf ("%d", nuevo_nodo->lengua);
printf ("\nNota de ingles: ");
scanf ("%d", nuevo_nodo->ingles);
media = (nuevo_nodo->mates + nuevo_nodo->ingles + nuevo_nodo->lengua) / 3;

actual = p;

while ((actual != NULL) && (strcmp (nuevo_nodo->nombre, actual->nombre) < 0)) {
   anterior = actual;
   actual = actual->siguiente; }

if (p == actual) {
   nuevo_nodo->siguiente = p;
   p = nuevo_nodo; }
else {
   anterior->siguiente = nuevo_nodo;
   nuevo_nodo->siguiente = actual; }
}

void buscar (struct t_alumno *p) {
struct t_alumno actual, encontrar;
int opcion;
int encontrado = 0;
int nota = 0;
char nombre [30];

printf ("\n¿Cómo desea buscar?\n1- En base a sus nombres\n2- Al mejor promedio\n3- Al peor promedio\n4- Al mejor en mates\n5- Al peor en mates\n6- Al mejor en lengua\n7- Al peor en lengua\n8- Al mejor en ingles\n9- Al peor en ingles");
scanf ("%d", &opcion);

actual = p;

switch (opcion) {
   case 1: printf ("Escriba un nombre");
           gets (nombre);
           while ((actual != NULL) && (encontrado == 0)) {
               if (strcmp (actual->nombre, nombre) == 0) {
                  encontrado = 1;
                  encontrar = actual; }
               actual = actual->siguiente; }

           if (encontrado == 1)
              printf ("Se ha encontrado el nombre, estas son sus notas: lengua %d\nmates %d\nIngles %d\nmedia %d.", encontrar->lengua, encontrar->mates, encontrar->ingles, encontrar->media);
           else
              printf ("No se ha encontrado el nombre.");
           break;

   case 2: while ((actual != NULL) && (encontrado == 0)) {
               if (actual->media > nota) {
                  nota = actual->media;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->media) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El mejor promedio es %d y es de %s", nota, encontrar->nombre);
           break;

   case 3: nota = actual->media;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->media < nota) {
                  nota = actual->media;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->media) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El peor promedio es %d y es de %s", nota, encontrar->nombre);
           break;

   case 4: nota = actual->mates;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->mates > nota) {
                  nota = actual->mates;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->mates) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El mejor en mates es %d y es de %s", nota, encontrar->nombre);
           break;

   case 5: nota = actual->mates;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->mates < nota) {
                  nota = actual->mates;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->mates) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El peor en mates es %d y es de %s", nota, encontrar->nombre);
           break;

   case 6: nota = actual->lengua;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->lengua > nota) {
                  nota = actual->lengua;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->lengua) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El mejor en lengua es %d y es de %s", nota, encontrar->nombre);
           break;

   case 7: nota = actual->lengua;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->lengua < nota) {
                  nota = actual->lengua;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->lengua) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El peor en lengua es %d y es de %s", nota, encontrar->nombre);
           break;

   case 8: nota = actual->ingles;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->ingles > nota) {
                  nota = actual->ingles;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->ingles) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El mejor en ingles es %d y es de %s", nota, encontrar->nombre);
           break;

   case 9: nota = actual->ingles;
           while ((actual != NULL) && (encontrado == 0)) {
               if (actual->ingles < nota) {
                  nota = actual->ingles;
               actual = actual->siguiente; }

           while ((actual != NULL) && (encontrado == 0)) {
               if (nota == actual->ingles) {
                  encontrar = actual; }
               actual = actual->siguiente; }

           printf ("El peor en inglés es %d y es de %s", nota, encontrar->nombre);
           break;

   default: printf ("Opción no válida);
            break; } } /*Hay una forma de hacer más corto el algoritmo de búsqueda que usé, pero hubiese sido algo más lioso y por ahora me conformo con que se entienda...*/

void mostrar (struct t_alumno *p) {
int opcion;
struct t_alumno *actual;

printf ("¿Qué deseas ver?\n1- Todo\n2- Sólo los nombres\n3- Nombres y promedio\n4- Nombres y notas");
scanf ("%d", opcion);

switch (opcion) {
   case 1: if (p == NULL)
              printf ("La lista está vacía.");
           else {
              while (actual != NULL ) {
                 printf ("\n%s %d %d %d %d", actual->nombre, actual->mates, actual->lengua, actual->ingles, actual->media);
                 actual = actual->siguiente; } }
           break;

   case 2: if (p == NULL)
              printf ("La lista está vacía.");
           else {
              while (actual != NULL ) {
                 printf ("\n%s", actual->nombre);
                 actual = actual->siguiente; } }
           break;

   case 3: if (p == NULL)
              printf ("La lista está vacía.");
           else {
              while (actual != NULL ) {
                 printf ("\n%s %d", actual->nombre, actual->mates, actual->media);
                 actual = actual->siguiente; } }
           break;

   case 4: if (p == NULL)
              printf ("La lista está vacía.");
           else {
              while (actual != NULL ) {
                 printf ("\n%s %d %d %d", actual->nombre, actual->mates, actual->lengua, actual->ingles);
                 actual = actual->siguiente; } }
           break; }
}

void quitar_alumno (struct t_alumno *p) {
struct t_alumno anterior, actual;
char nombre [30];

printf ("¿Qué alumno de la lista desea borrar?");
gets (nombre);

actual = p;

while ((actual != NULL) && (strcmp (acutal->nombre, nombre) != 0)) {
   anterior = actual;
   actual = actual->siguiente; }

/*Comprobamos que el número esté en la lista*/
if (actual != NULL) {
   if (actuall == p) {
      p = actual->siguiente;
      actual->siguiente = NULL;
      free (actual); }
   else {
      anterior->siguiente = actual->siguiente;
      actual->siguiente = NULL;
      free (actual); } }
}

void guardar (struct t_alumno *p) {
FILE *fichero;
struct t_alumno *actual = p;

fichero = fopen ("binario.bin", "wb");

while (actual != NULL) {
   fwrite (actual, sizeof (p), 1, fichero);
   actual = actual->siguiente; }
}

void recuperar (struct t_alumno *p) {
FILE *fichero;
struct t_alumno *actual = (struct t_alumno *) malloc (sizeof (struct t_alumno));

if ((fichero = fopen ("binario.bin", "wb")) == NULL) {
   printf ("El fichero no existe"); }
else {
   fread (actual, sizeof (actual), 1, fichero);
   actual->siguiente = NULL;
   p = actual;
   while (feof (fichero) == 0) {
      actual->siguiente = (struct t_alumno *) malloc (sizeof (struct t_alumno));
      actual = actual->siguiente;
      fread (actual, sizeof (actual), 1, fichero);
      actual->siguiente = NULL; } }
}


CitarEl Reto

Harás un mini-juego. En él habrá dos listas, una con todos los objetos que se pueden conseguir y que estará en un archivo que se leerá al comienzo del juego y otra con los objetos que tiene su personaje. El funcionamiento será el siguiente: habrá un 50% de que se encuentre un nuevo objeto, si se hace se encontrará el que esté más cerca del principio que no se tenga ya; luego un 30 % de perder un sólo objeto (se perderá uno aleatorio) y un 20% de perderlos todos. Ganas cuando los encuentras a todos. Además, el juego se puede guardar en otro archivo binario a parte del ya mencionado.

Me di cuenta que con una lista es mejor, así que lo hice de ese modo. Una cosa, el código lo que busca es que se entienda (no creo que lo haya logrado) y utilizar, dentro de lo posible, todo lo visto, no optimizar el programa.

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

struct t_item {
   char nombre [30];
   int encontrado;
   struct t_item *siguiente; }

void generar_lista (struct t_item *p);

void perder_item (struct t_item *p);

void ganar_item (struct t_item *p);

void perder_todo (struct t_item *p);

void guardar_partida (struct t_item *p);

void recuperar_partida (struct t_item *p);

char **predeterminado = {"Espada", "Escudo", "Arco" };

int main (void) {
int opcion;
int numero;
struct t_item *principio = (struct t_item *) malloc (sizeof (struct t_item));
principio = NULL;

do {
printf ("\n\tBienvenido a este juego de calidad\n\n¿Qué desea hacer?\n1- Generar una lista de items\n2- Recuperar una partida\n3- Probar suerte\n4- Guardar\n5- Salir");
scanf ("%d", &opcion);

switch (opcion) {
   case 1: generar_lista (principio);
           break;
   case 2: recuperar_partida (principio);
           break;
   case 3: if (principio == NULL) {
              printf ("\nNo se ha inicializado la lista.");
              break; }
           numero = rand () % 10 + 1;
           if ((numero >= 1) || (numero <= 5)
              ganar_item (principio);
           else {
              if (numero > 5) || (numero < 9)
                 perder_item (principio);
              else
                 perder_todo (principio); }
           break;
   case 4: guardar_partida (principio);
           break;
   case 5: printf ("\nSaludos...");
           break;
   default: printf ("Opción no válida");
            break; }
} while (opcion != 5)
return 0;
}

void generar_lista (struct t_item *p) {
char opcion;
struct t_item *actual;
int i;
char **items;

do {
printf ("\n¿Deseas generar una lista personalizada?(S/N)");
scanf ("%c", &opcion);
} while ((opcion != 'S') || (opcion != 'N'))

actual = p;

if (opcion == 'N') {
   printf ("\nGenerando lista predeterminada...");
   
   for (i = 0; i < 3; i ++) {
      actual->encontrado = 0;
      strcpy (actual->nombre, predeterminado [i]);
      actual->siguiente = (struct t_item *) malloc (sizeof (struct t_item));
      actual = actual->siguiente; }
     
   actual = NULL; }
}
else {
   for (i = 0; opcion != 'N'; i++) {
      actual->encontrado = 0;
      printf ("\nIntroduce el nombre del nuevo item: ");
      gets (items [i]);
      strcpy (actual->nombre, items [i]);
      actual->siguiente = (struct t_item *) malloc (sizeof (struct t_item));
      actual = actual->siguiente;
      printf ("\n¿Desea seguir añadiendo items?");
      scanf ("%c", &opcion); }
   
   actual = NULL;
}
}

void perder_item (struct t_item *p) {
int item = rand ();
struct t_item *anterior, *actual;
int i;

actual = p;

for (i = 0; i < item; i++) {
   anterior = actual;
   if (actual->siguiente == NULL)
      actual = p;
   else
      actual = actual->siguiente; }

if (actual == p) {
   p = actual->siguiente;
   actual->siguiente = NULL;
   free (actual); }
else {
   anterior->siguiente = actual->siguiente;
   actual->siguiente = NULL;
   free (actual); }
}

void ganar_item (struct t_item *p) {
struct t_item *actual;

actual = p;

while ((actual->encontrado != 0) && (actual != NULL))
   actual = actual->siguiente;

if (actual == NULL)
   printf ("\nFelicidades, haz encontrado todos los items");
else {
   actual->encontrado = 1;
   printf ("\nHaz encontrado un %s", actual->nombre); }
}

void perder_todo (struct t_item *p){
struct t_item *actual;

actual = p;

while (actual != NULL) {
   actual->encontrado = 0;
   actual = actual->siguiente; }

printf ("\nHaz perdido todo");
}

void guardar_partida (struct t_alumno *p) {
FILE *fichero;
struct t_item *actual = p;

fichero = fopen ("items.bin", "wb");

while (actual != NULL) {
   fwrite (actual, sizeof (p), 1, fichero);
   actual = actual->siguiente; }
}

void recuperar_partida (struct t_alumno *p) {
FILE *fichero;
struct t_item *actual = (struct t_item *) malloc (sizeof (struct t_item));

if ((fichero = fopen ("items.bin", "wb")) == NULL) {
   printf ("No hay ninguna partida guardada"); }
else {
   fread (actual, sizeof (actual), 1, fichero);
   actual->siguiente = NULL;
   p = actual;
   while (feof (fichero) == 0) {
      actual->siguiente = (struct t_item *) malloc (sizeof (struct t_item));
      actual = actual->siguiente;
      fread (actual, sizeof (actual), 1, fichero);
      actual->siguiente = NULL; } }
}

Gracias freyi *.*


Cita de: Gambit en 26 de Enero de 2010, 10:25
Follar cansa. Comprad una xbox 360, nunca le duele la cabeza, no discute, no hay que entenderla, la puedes compartir con tus amigos...

Thylzos

#62
13- Bibliotecas estándar en C

13.1- Definiciones.

- Biblioteca: Conjunto de rutinas que se usan de manera frecuente.
- Archivos de encabezado: Archivo de una biblioteca que define variables, constantes, estructuras, funciones y demás tipos de datos en una biblioteca.
- Archivos de implementación: Archivos que implementas las funciones declaradas en las archivos de encabeza en una biblioteca
- Macro-identificador: Identificador con que se conoce a la biblioteca.

13.2- Bibliotecas más usadas

13.2.1- stdlib.h

Aquí tenemos una serie de funciones aritméticas, de números aleatorios y conversión de cadenas.

Citarint abs(int j);
long int labs(long int j);
div_t div(int numer, int denom);
ldiv_t ldiv(long int numer, long int denom);

Las dos primeras, calculan el valor absoluto del entero pasado por parámetro. Las otras dos calculan el valor numer entre denom y devuelven el cociente y el resto en una estructura llamada div_t que contiene dos miembros llamados quot y rem.

La estructura div_t:

Citarstruct div_t {
        int quot;  /* cociente */
        int rem;   /* residuo  */
}

Citarint rand(void);
void srand(unsigned int semilla);

Una de éstas ya la conocemos, es rand que devuelve un número aleatorio entre 0 y RAND_MAX (215 - 1). La otra, srand, usa semilla como una la semilla de una nueva serie de enteros pseudo-aleatorios.

Y después las cadenas:

Citardouble atof(const char *cadena) Convierte una cadena a un valor flotante.
int atoi(const char *cadena) Convierte una cadena a un valor entero.
int atol(const char *cadena) Convierte una cadena a un valor entero largo.
double strtod(const char *cadena, char **finap) Convierte una cadena a un valor de punto flotante.
double strtol(const char *cadena, char *finap, int base) Convierte una cadena a un entero largo de acuerdo a una base dada, la cual deberá estar entre 2 y 36 inclusive.
unsigned long strtoul(const char *cadena, char *finap, int base) Convierte una cadena a un entero largo sin signo.

Además tenemos un par de funciones de ordenamiento y búsqueda, pero son un poco más "retorcidas" y prefiero ahorrármelas.

13.2.2- math.h

Como su nombre indica de forma muy elocuente, esta biblioteca se caracteriza por tener funciones aplicadas a las matemáticas. Realmente no tiene ningún secreto, el único es que además de incluirla con un #include en el programa, hay que ligarla a la hora de compilar. En los sistemas *n?x sería algo así:

gcc programa.c -o programa -lm

Sus funciones:

Citardouble acos(double x) Calcula el arco coseno de x.
double asin(double x) Calcula el arco seno de x.
double atan(double x) Devuelve el arco tangente en radianes.
double atan2(double y, double x) Calcula el arco tangente de las dos variables x e y. Es similar a calcular el arco tangente de y / x, excepto en que los signos de ambos argumentos son usados para determinar el cuadrante del resultado.
double ceil(double x) Redondea x hacia arriba al entero más cercano.
double cos(double x) devuelve el coseno de x, donde x está dado en radianes.
double cosh(double x) Devuelve el coseno hiperbólico de x.
double exp(double x) Devuelve el valor de e (la base de los logaritmos naturales) elevado a la potencia x.
double fabs(double x) Devuelve el valor absoluto del número en punto flotante x.
double floor(double x) Redondea x hacia abajo al entero más cercano.
double fmod(double x, double y) Calcula el resto de la división de x entre y. El valor devuelto es x - n * y, donde n es el cociente de x / y.
double frexp(double x, int *exp) Se emplea para dividir el número x en una fracción normalizada y un exponente que se guarda en exp $x=res \times 2^{exp}$.
long int labs(long int j) Calcula el valor absoluto de un entero largo.
double ldexp(double x, int exp) Devuelve el resultado de multiplicar el número x por 2 elevado a exp (inversa de frexp).
double log(double x); Devuelve el logaritmo neperiano de x.
double log10(double x) Devuelve el logaritmo decimal de x.
double modf(double x, double *iptr) Divide el argumento x en una parte entera y una parte fraccional. La parte entera se guarda en iptr.
double pow(double x, double y) Devuelve el valor de x elevado a y.
double sin(double x) Devuelve el seno de x.
double sinh(double x) Regresa el seno hiperbólico de x.
double sqrt(double x) Devuelve la raíz cuadrada no negativa de x.
double tan(double x) Devuelve la tangente de x.
double tanh(double x) Devuelve la tangente hiperbólica de x.

Realmente no tiene mucho truco. Además cuenta con algunas constantes que nos pueden ser de utilidad:

CitarM_E La base de los logaritmos naturales e.
M_LOG2E El logaritmo de e de base 2.
M_LOG10E El logaritmo de e de base 10.
M_LN2 El logartimo natural de 2.
M_LN10 El logaritmo natural de 10.
M_PI PI
M_PI_2 PI/2
M_PI_4 PI/4
M_1_PI 1/PI
M_2_PI 2/PI
M_2_SQRTPI 2/(raiz cuadrad de PI)
M_SQRT2 La raíz cuadrada positiva de 2
M_SQRT1_2 La raíz cuadrada positiva de 1/2

13.2.3- stdio.h

Bueno, ahora una biblioteca que tiene funciones para dar y regalar. Pero como la mayoría ya las vimos, pues no tendremos problemas.

Citarvoid perror(const char *s) Produce un mensaje que va a la salida estándar de errores.
void exit(int status) Se va del programa y devuelve el estado en que terminó al Sistema Operativo o al proceso padre.
int getchar(void) Lee un carácter.
int putchar(char ch) Escribe un carácter.
int printf( const char *formato, lista arg ...) Salida formateada.
int scanf( const char *formato, lista arg ...) Entrada formateada.
int getc () Lee un carácter de distintos flujos.
int putc () Escribe un carácter a partir de diversos flujos
FILE *fopen(const char *nomb, const char *modo) Abre un archivo.
int fprintf(FILE *flujo, const char *formato, args ... ) Escritura formateada de un archivo.
int fscanf(FILE *flujo, const char *formato, args ... ) Lectura formateada de un archivo.
int fgetc(FILE *flujo) Lectura de un carácter desde un fichero
int fputc(char ch, FILE *s) Escritura de un carácter a un fichero.
int fflush(FILE *flujo) Limpia el flujo de datos.
int fclose(FILE *flujo) Desasocia un flujo de datos.
int sprintf(char *cadena, char *formato, args ... ) Escribe una cadena.
int sscanf(char *cadena, cahr *formato, args ... ) Lee una cadena.
int feof(FILE *flujo) Nos dice dónde está el final de un fichero.
int ferror(FILE *flujo) Nos dice si ocurrió un error en el flujo de datos.
void clearerr(FILE *flujo) Limpia el fichero de errores.
int fileno(FILE *flujo) Devuelve el descriptor del fichero.
int open(char* nomb, int flag) Abre archivo binario, si lo hacemos con esta función, no podremos hacer acciones formateadas.
int creat(char* nomb, int perms) Crea un fichero, como la anterior, si se usa no se pueden usar E/S formateadas.
int close(int fd) Cierra un fichero abierto con open ().
int read(int fd, char *buffer, unsigned longitud) Lee desde un fichero binario.
int write(int fd, char *buffer, unsigned longitud) Escribe desde un fichero binario.

13.2.4- string.h

Ahora veremos funciones para manejar cadenas de caracteres.

Citarchar *strcpy(const char *dest, const char *orig) Copia a orig a dest.
int strcmp(const char *s1, const char *s2) Compara las dos cadenas de caracteres.
char *strerror(int errnum) Devuelve un mensaje de error que corresponde a un número de error.
int strlen(const char *s) Calcula la longitud de la cadena.
char *strncat(char *s1, const char *s2, size_t n) Agrega n caracteres de s2 a s1.
int strncmp(const char *s1, char *s2, size_t n) Compara los primeros n caracteres de dos cadenas.
char *strncpy(const char *s1, const char *s2, size_t n) Copia los primeros n caracteres de s2 a s1.
strcasecmp(const char *s1, const char *s2) versión no sensible a mayúsculas de strcmp().
strncasecmp(const char *s1, const char *s2, size_t n) versión no sensible a mayúsculas de strncmp().
char *strchr(const char *s, int c) -- Devuelve un puntero a la primera aparición del carácter c en la cadena s.
char *strrchr(const char *s, int c) -- Encuentra la última aparición del carácter c en la cadena s.
char *strstr(const char *s1, const char *s2) -- Localiza la primera aparición de la cadena s2 en la cadena s1.
char *strpbrk(const char *s1, const char *s2) -- Regresa un apuntador a la primera aparición en la cadena s1 de cualquier carácter de la cadena s2, o un apuntador nulo si no hay un carácter de s2 que exista en s1.
size_t strspn(const char *s1, const char *s2) -- Calcula la longitud del segmento inicial de s1 que consta únicamente de caracteres en s2.
size_t strcspn(const char *s1, const char *s2) -- Regresa el número de caracteres al principio de s1 que no coinciden con s2.
char *strtok(char *s1, const char *s2) -- Divide la cadena apuntada a s1 en una secuencia de tokens, cada uno de ellos esta delimitado por uno o más caracteres de la cadena apuntada por s2.
void *memchr(void *s, int c, size_t n) -- Busca un caracter en un buffer.
int memcmp(void *s1, void *s2, size_t n) -- Compara dos buffers.
void *memcpy(void *dest, void *fuente, size_t n) -- Copia un buffer dentro de otro.
void *memmove(void *dest, void *fuente, size_t n) -- Mueve un número de bytes de un buffer a otro.
void *memset(void *s, int c, size_t n) -- Pone todos los bytes de un buffer a un caracter dado.

Por Dios, qué aburrida esta parte...

13.3- Creando nuestras bibliotecas estáticas.

Si tenemos una serie de funciones y estructuras hechas por nostros que usamos frecuentemente o que necesitaremos para una serie de programas que tenemos pensado hacer, para no tener que estar definiéndolas constantemente, se pueden unir todas en una biblioteca personalizada en archivos de encabezado y de implementación.

13.3.1- Archivos de encabezado.

Como bien se dice más arriba, sirven para definir todos los datos que vallamos a usar. Los archivos de cabecera tienen la extencion archi-conocida ".h" y la siguiente estructura:

#ifndef identificador
#define identificador

/*Las declaraciones van aquí*/

#endif /*Identificador*/

Donde identificador es el macro-identificador de nuestra biblioteca, que no sirve para otra cosa más que para que el procesador se aclare. En la línea:

[code]#ifndef identificador


Comprueba que no esté ya definido el macro-identificador. Si no lo está pasa a definirlo:

#define identificador

Y cuando se terminan de declarar los datos, se termina la definición:

#endif /*Identificador*/

En estos archivos podemos poner desde funciones hasta datos como variables, estrcuturas o constantes. Estos últimos son útiles cuando necesitamos datos comunes entre muchos programas o archivos de un programa. Además, puedes agregar bibliotecas a tu propia biblioteca. Una cosa a tener en cuenta, es que si queremos que los programas que usen nuestra biblioteca puedan acceder a sus variables o funciones, en su declaración debemos anteponer extern. Para aclarar un poco la cosa, veamos un ejemplo, el archivo "mibibli.h:

#ifndef _MIBIBLI_H
#define _MIBIBLI_H

#include <stdio.h>
#define NUMERO_MAXIMO_DE_ALGO 2

extern int variable_inservible;
extern void funcion_sin_sentido (void);

#endif /*_MIBIBLI_H*/


13.3.2- Archivos de implementación.

En estos pondremos las funciones que hemos declarado antes, llevan ".c" como extensión y también deben compilarse. Por ejemplo, el archivo mibibli.c:

#include "mibibli.h"

void funcion_sin_sentido (void) {
printf ("Está función no tiene sentido");
}


Y listo. Lo que queda es compilar, cosa que depende bastante de la plataforma que usemos, así que no se me ocurre cómo dar una explicasión universal. Igual, si alguno tiene una duda con este paso, que consulte.

13.4- Ejercicios

Como este capítulo no tuvo mucho contenido que digamos, sólo habrá un ejercicio:

1- Haz una biblioteca que tenga todo lo necesario para manejar estadísticas.





Y hasta aquí, todo lo publicado hasta ahora. Mañana o pasado pongo lo siguiente.[/code]

Gracias freyi *.*


Cita de: Gambit en 26 de Enero de 2010, 10:25
Follar cansa. Comprad una xbox 360, nunca le duele la cabeza, no discute, no hay que entenderla, la puedes compartir con tus amigos...

Genki

bueno... posteo medio obligado por mskina... porque me decía no se qué de un riñón... bueno, al grano...

siento mi ineptitud, pero en el punto 3, en lo de tipos de datos, me lo he leido varias veces(más de lo que me veía capaz) y sigo sin entenderlo muy bien...
alguien podría explicarlo para tontos? :$

Sorry but you are not allowed to view spoiler contents.

Thylzos

Cita de: Genki en 11 de Agosto de 2008, 03:00
bueno... posteo medio obligado por mskina... porque me decía no se qué de un riñón... bueno, al grano...

siento mi ineptitud, pero en el punto 3, en lo de tipos de datos, me lo he leido varias veces(más de lo que me veía capaz) y sigo sin entenderlo muy bien...
alguien podría explicarlo para tontos? :$

¿Te refieres al capítulo 3?, ¿el de las variables?

Gracias freyi *.*


Cita de: Gambit en 26 de Enero de 2010, 10:25
Follar cansa. Comprad una xbox 360, nunca le duele la cabeza, no discute, no hay que entenderla, la puedes compartir con tus amigos...

Faerindel

Cita de: Genki en 11 de Agosto de 2008, 03:00
bueno... posteo medio obligado por mskina... porque me decía no se qué de un riñón... bueno, al grano...

siento mi ineptitud, pero en el punto 3, en lo de tipos de datos, me lo he leido varias veces(más de lo que me veía capaz) y sigo sin entenderlo muy bien...
alguien podría explicarlo para tontos? :$
No es nada difícil, pero si pusieses unas preguntas más concretas sería mejor.

Una variable ha de ser de un tipo determinado para poder manejarla. En el tema 3 se explican los tipos básicos: char (para guardar un solo caracter ASCII), int (números enteros), float (números reales) y double (números reales más grandes).

Luego están los modificadores long y short, cuando se declara una variable se reserva una cantidad de memoria para ella, si un número necesita más memoria para ser almacenado que el que tiene reservada la variable, ocurre un desbordamiento de memoria (básicamente el programa peta), de ahí que se tenga en cuenta el rango de números que acepta una variable. Long y short incrementan o decrementan la cantidad de memoria reservada, aumentando o disminuyendo el rango.

Y signed y unsigned simplemente indican si la variable acepta valores negativos o no. Por defecto int, float y double aceptan negativos, poner signed sería redundante. En cambio si ponemos unsigned int sólo aceptará valores positivos (y creo que además aprovecha todo el rango para positivos pasando de -32768..32767 a 0..65355).

Genki

ah joder...
mi problema era con el tipo de datos, del capítulo 3, pero con lo que explicó faerindel, lo entiendo mejor...
muchas gracias :$

ah, y si tengo más dudas puedo preguntar? o hay un tope? xDDDD

Sorry but you are not allowed to view spoiler contents.

Thylzos

Cita de: Genki en 11 de Agosto de 2008, 18:11
ah joder...
mi problema era con el tipo de datos, del capítulo 3, pero con lo que explicó faerindel, lo entiendo mejor...
muchas gracias :$

ah, y si tengo más dudas puedo preguntar? o hay un tope? xDDDD

Suelta todas las que tengas.

Gracias freyi *.*


Cita de: Gambit en 26 de Enero de 2010, 10:25
Follar cansa. Comprad una xbox 360, nunca le duele la cabeza, no discute, no hay que entenderla, la puedes compartir con tus amigos...

Faerindel

Cita de: Genki en 11 de Agosto de 2008, 18:11
ah joder...
mi problema era con el tipo de datos, del capítulo 3, pero con lo que explicó faerindel, lo entiendo mejor...
muchas gracias :$

ah, y si tengo más dudas puedo preguntar? o hay un tope? xDDDD
20k de caracteres por post es tu tope, más de eso tendrás que doblepostear.

Memnoch

Visitante      07:22     Imprimiendo el tema "Curso de iniciación en programación C".

Mandad ésto a Meneame cuando tengamos el nuevo server troncos :lol:

Últimos mensajes

Mininoticias de jug0n
[Hoy a las 00:55]


Adivina la película de M.Rajoy
[Ayer a las 12:08]


¿Qué manga estás leyendo? de M.Rajoy
[14 de Mayo de 2024, 09:43]


El hilo con el increíble título mutante de Orestes
[13 de Mayo de 2024, 19:24]


¿Cuándo moriremos? de M.Rajoy
[13 de Mayo de 2024, 08:05]