¿Errores en los enunciados de un examen de C?

Iniciado por samur88, 13 Enero 2011, 14:27 PM

0 Miembros y 1 Visitante están viendo este tema.

samur88

Saludos, mire tengo el siguiente problema, el caso es que un profesor me ha puesto el siguiente ejercicio en un examen, no quiero que me lo resolváis ni nada por el estilo, lo único que necesito que me digáis si este profesor esta cometiendo algunas locuras en los ejercicios.

Veréis se como implementar una cola en C lo he echo otras veces y me funciona perfectamente, pero el caso es que en el examen de este hombre me he encontrado con lo siguiente y esta poniendo en duda mis conocimientos sobre C:

Dada la siguiente declaración:

struct Componente {
int dato;
struct Componetne  *sig
}
typedef Componente *Puntero;
struct Cola { Puntero principio, final; }


El dice que eso es la implementación de una cola , yo la verdad veo algunos errores en ese codigo para que eso sea dicha implementación pero bueno vosotros me diréis.
Luego sobre esa estructura de datos que el denomina cola, quieres que hagamos una serie de operaciones sobre la cola:
CitarInicializar la cola.
Primero: Devuelve el elemento que ocupe la primera posición.
Encolar: Introduce un nuevo elemento en la cola.
SacarCola: Elimina el elemento en la cabeza de la cola. (Aquí veo otro error si hablamos de colas solo puedo sacar de ella el ultimo elemento, otra cosa es que sean Bicolas, pero el eso no lo ha explicado)
Vacia: Averigua si la cola no tiene nada en su interior.

Un saludo, espero que podáis ayudarme.


do-while

¡Buenas!

No se que ves de extraño en la declaracion de los tipos. Una cola tiene un punto de entrada y uno de salida, que es lo que se ha agrupado en el struct Cola. Pero esto lo puedes hacer como quieras, siempre y cuando puedas saber donde esta el principio, para sacar datos, y donde el final, para introducirlos.

¡Saludos!
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

samur88

#2
No se si esto:
struct Componente {
int dato;
struct Componente  *sig
}
typedef Componente *Puntero;


es igual a esto:
struct Componente {
       int dato;
       struct Componente *next;
      };
typedef struct Componente Puntero;


Ya que en el primer caso declara un puntero a una estructura del tipo Componente y en el segundo creo un nuevo tipo de variable a una estructura de tipo componente. ¿Es lo mismo? y en el primer caso obtengo un puntero a dicha estructura y en el segundo una variable en si que puede ser accesible por un puntero.

El segundo fallo que veo es que a pesar de crear una plantilla de estructura de la siguiente forma struct Cola { Puntero principio, final; } no crea una variable de esa plantilla, de hecho el compilador no me compilaba por eso.
De todas formas al usar ese código aún declarando la variable de estructura, tengo problemas para trabajar con los punteros principio y final.
Un saludo, espero que podáis ayudarme.


N0body

#3
Yo creo que lo que quiso hacer tu profesor es lo siguiente (tengo muy poca experiencia en listas enlazadas, sé la lógica, pero muchos conceptos los ignoro):


struct Componente {
int dato;
struct Componetne  *sig;
};


Hasta ahí, lo que entiendo es que declara el elementeo básica de una lista enlazada: una estructura que tiene un dato y un puntero hacia una estructura de éste mismo tipo (hasta ahí el único error está en el ";" que pongo luego de "struct Componetne  *sig" y el que agrego al final)

Luego hace esto:

typedef Componente *Puntero;


Lo cual (o por lo menos con lo poco que sé de C) es incorrecto, porque trata de crear un nuevo tipo llamado "*Puntero" que sea igual al tipo "Componente" (el cuál no existe, existe "struct Componente")

El quiso hacer (en mi opinión)


typedef struct Componente* Puntero;


De modo que ahí creaba un nuevo tipo llamado Puntero, que consistía en un puntero a una estructura tipo Componente.
Creo que eso es lo que quisiste poner con:
Citar
Ya que en el primer caso declara un puntero a una estructura del tipo Componente

Ahora lo que haces tú es:

typedef struct Componente Puntero;

Ahí como bien dices:
Citarcreo un nuevo tipo de variable a una estructura de tipo componente

Y ahora te respondo la pregunta:
Citar¿Es lo mismo?
Bueno, creo que te la contestaste solito:
Citaren el primer caso obtengo un puntero a dicha estructura y en el segundo una variable en si que puede ser accesible por un puntero

Lo que, como bien dices, haces con tu código es crear un tipo llamado Puntero que es lo mismo que struct Componente. Osea, con lo tuyo sería lo mismo hacer:


struct Componente a;
//o hacer:
Puntero a;


En vez si quieres q "a" sea un puntero a una estructura componente debes hacer (para tu caso):


struct Componente *a;
//o hacer:
Puntero *a;


Ya que en tu caso, te vuelvo a repetir struct Componente vendría a ser lo mismo que Puntero...

Aún así, creo que ya que el tipo de variable que estás definiendo se llama "Puntero" sería mejor que sea un puntero, no?

Pués entonces habría que hacer lo que hice yo arriba (y creo que eso quiso hacer tu profesor)


typedef struct Componente* Puntero;


Bueno aquí un ejemplo del uso del mismo:

struct Componente a;
Puntero b;
a.dato=7;
b=&a;
b->dato=33


De modo que "a" es una estructura Componente y b un puntero a estructura Componente que luego le asignamos la dirección de "a" y modificamos el contenido de ésta variable a través de "b"...

Luego puedes hacer:

struct Cola { Puntero principio, final; };

Ahi declaras otro tipo de estructura (la estructura Cola) que posee dentro de sí un dos punteros a estructuras Componente.
Sé lo que haces pero no se bien para que la utilizas... necesitaría el código, como te dije tengo muy poca experiencia en ésto de las listas enlazadas y no sé que es una cola, pero tengo claro lo que hiciste ahí... Pero supongo que te viene mejor que sea una estructura con dos punteros a estructuras componentes que una estructura con dos estructuras componentes adentro. Ya que de este modo, podés cambiar el principio y el final (haciendo que dichos punteros apunten a otras estructuras)...

Y la verdad que no entiendo tus problemas sin una explicación un poco más detallada y menos confusa... además del código....


Espero aver ayudado y no haber liado más el asunto...

samur88

Hola, saludos, muchísimas gracias por la respuesta, la primera parte la tengo clara, cuando llego aquí:
Struct Cola { Puntero principio, final; };

El único problema que habría es que mi profesor declaro la plantilla de estructura pero no declaro una variable de esa plantilla de estructura.
Por eso el compilador me daba error, yo le expuse este problema en el examen pero me dijo que no, que el código estaba bien...
Yo declararía la siguiente estructura, por ejemplo:
Struct Cola Cola1
Haciendo esto, ya me compilaba, pero tenía errores en el código que he solucionado pero no tengo muy clara la idea de como lo he solucionado, a ver si me puedes echar una mano a entenderlo todo mejor, expongo el código funcionando:

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

struct Componente {
        int dato;
        struct Componente *next;
       };
typedef struct Componente *Puntero;
struct nodcola{Puntero principio,final;};
struct nodcola Cola;


int add_nod(Puntero *first,Puntero *ultimo,int dato){
Puntero nuevo;
nuevo = (Puntero) malloc (sizeof(Puntero));
nuevo->dato = dato;
nuevo->next = NULL;     
if(*first == NULL){
             *first = nuevo;
             *ultimo = nuevo;
            }else {
                   (*ultimo)->next = nuevo;
                   *ultimo = nuevo;
              }
}

int ext_nod(Puntero *first,Puntero *ultimo){
     Puntero aux;
     int v;
     
     aux = *first;
     if(aux == NULL){return -1;}
     *first = (*first)->next;
     v = aux->dato;
     free(aux);
     if(*first == NULL)
      ultimo = NULL;
     return v;
    }
   
int main(){
Cola.principio = NULL;
Cola.final = NULL;

add_nod(&Cola.principio,&Cola.final,6);
add_nod(&Cola.principio,&Cola.final,8);
add_nod(&Cola.principio,&Cola.final,3);
     printf("%d\n",ext_nod(&Cola.principio,&Cola.final));
     printf("%d\n",ext_nod(&Cola.principio,&Cola.final));
     printf("%d\n",ext_nod(&Cola.principio,&Cola.final));
     printf("%d\n",ext_nod(&Cola.principio,&Cola.final));
system("pause");

}


Yo defino una variable de estructura de la siguiente manera struct nodcola Cola; pero a las funciones add_nod y ext_nod no les paso Cola.principio, les paso la variable por referencia, esto no entiendo por que es, ya que la variable de estructura Cola es una variable global por lo tanto debería ser accesible por todas las funciones (pero si no lo hago así el programa no funciona correctamente).
Esa sería mi única duda ahora mismo.
Un saludo y gracias por todo de nuevo.

N0body

#5
Pués bien, mis hipótesis se confirman... La estructura Cola (en tu código la llamas nodcola), que contiene dos punteros hacia estructuras Componentes, es para manejar la lista, teniendo siempre una referencia al principio y al final de la cadena...

Creí eso, pero no quise preguntarte para no liarte tanto. Porque... para qué quieres declarar el tipo de estructura Cola, si sólo necesitas una variable de ese tipo? Bah, yo creo que si vas a declarar una estructura (una plantilla como tu creo que llamas) es para declarar luego más de una sola variable de ese tipo. Pero en éste caso solo necesitas una variable, para poder almacenar el principio y el final de la lista...
Espero que te quede más claro con esto:

Si haces esto:

struct nodcola {Puntero principio, final};


Estás definiendo un nuevo tipo (struct nodcola). Cualquier varible que definas de éste tipo, poseerán dos punteros hacia estructuras Componente.
Así luego podemos hacer:


struct nodcola a,b;
struct componente x,y,z;
x.next=&y;
y.next=&z;
z.next=NULL;
a.principio=&x;
a.final=&z;
/* Para qué necesito la variable b (de tipo nodcola)
   si me basta con a, para tener una referencia del
   principio y del final de la lista enlazada...
*/


En todo caso podés hacer esto:


struct {Puntero principio, final} Cola;

Y ahí estás declarando una variable Cola que contiene en sí dos punteros Cola.principio y Cola.final con los cuales podes apuntar al principio y al final de la lista haciendo algo como:


Cola.principio=&x;
Cola.final=&z


Osea, no declaras el tipo "struct nodcola" ya que sólo necesitas UNA variable de ese tipo...

Bueno, éstas fueron aclaraciones tontas, que de verdad no hacen al funcionamiento del programa... Ahora sí unas aclaraciones serias sobre lo que dices y sobre tu código...


-
CitarHaciendo esto, ya me compilaba, pero tenía errores en el código que he solucionado pero no tengo muy clara la idea de como lo he solucionado

La verdad que no sé como solucionas problemas si no tenés idea clara de como lo estás haciendo, a menos que hagas como muchos alumnos míos que ponen las cosas de diferentes maneras hasta que les compile o funcione...
Un consejo: trata de entender cada cosa que hagas... cada línea que escribas, que sepas certeramente lo que en verdad estás haciendo... Si no la tienes muy claras puedes crear un programa de prueba, en donde probar la parte en cuestión sobre la que tienes dudas y ver como funciona...


-Para poder modificar las variables dentro de las funciones las pasas por referencia. En tu caso pasas un puntero a dichas variables... Pero tu siempre trabajas con la variable apuntada por dicho puntero... Aver si me explico...
Si hago:

Puntero *first;

first es un puntero a un puntero a una estructura componente...
pero tu siempre trabajas con (*first) porque lo que te interesa es el puntero a la estructura componente, no el puntero a este puntero...
Puedes hacer más claro el código si utilizas las variables pasadas por referencia del siguiente modo:

int add_nod(Puntero &first,Puntero &ultimo,int dato)

Mirate esto: http://www.mailxmail.com/curso-programacion-c/parametros-valor-referencia


-Tratá de no usar variables globales inecesarias, es cierto que es cómodo que los punteros que tienen la referencia del principio y el final de la lista sean globales, pero para códigos más largos puede llegar a causar confusiones...
En verdad creo que sí algún aspecto positivo tiene declarar el tipo strcut nodcola es que puedes hacer que el retorno de una función sea de dicho tipo y así no tener que usar variables globales ni referencias...


-Te explico el funcionamiento de malloc, porque creo que la utilizas mal
Si yo quiero declarar N variables tipo int hago lo siguiente:

int* puntero;
puntero = (int *) malloc (N*sizeof(int));


El argumento indica el tamño del espacio reservado... lo que tu haces es como si yo hiciese acá:


int* puntero;
puntero ( (int *) malloc (N*sizeof(int*));


Espero que entiendas lo que tienes que modificar, no pretendas que te lo dé servido...


-En la función ext_nod cuando haces:

if(*first == NULL)
     ultimo = NULL;


No estás modificando el valor de Cola.final, sino que estás modificando el puntero que apunta a esta variable... tendrías que modifcar (*ultimo)...


-No sé que es lo que se te pide, pero si la función add_nod crea más nodos al final de la lista, sería más lófico que ext_nod extraiga nodos del final de la cola en vez desde el principio no?


-Utiliza las etiquetas GeSHi para que el código sea más claro...


-Dices que:
CitarEl único problema que habría es que mi profesor declaro la plantilla de estructura pero no declaro una variable de esa plantilla de estructura.
Pero en tu código si utilizas dicha estructura... (osea, declaras variables de dicho tipo)... Supongo que en el código donde no la usabas declarabas directamente:


Puntero principio, final;



-Tan preocupado estás por el código de un exámen? y te acuerdas del código perfectamente de dicho exámen? Espero que ésto no sea una tarea, pués sería contrario a las reglas del foro... En cualquier caso en mis explicaciones no doy el código resuelto, sino indicaciones de que hacer para enmendar tus errores...




Si tienes cualquier duda más no temas en hacerla y disculpa si te prejuzgo un poco, pero hay muchos vivos que quieren sus tareas hechas...
Y bueno

samur88

Muchísimas gracias por las respuestas.
Sobre esto:
CitarPorque... para qué quieres declarar el tipo de estructura Cola, si sólo necesitas una variable de ese tipo?

Realmente no lo se, en el primer post que publique esta el enunciado del examen copiado, mi profesor dio una estructuras de datos ya hecha y pretendía de que implementáramos las funciones a partir de dicha estructura, pero el no hace lo siguiente:
struct {Puntero principio, final} Cola
Ni declara una variable de la plantilla cola, por lo tanto daba error al compilar, por eso yo cree una variable de estructura, realmente es mejor usar eso que dices, o simplemente definir los punteros fuera de una estructura, si solo voy a trabajar con una lista de ese tipo.
Gracias por la corrección.

Sobre el tema de las variables globales y lo que hacía, creo que ya lo he entendido, seria algo así:
Aunque la estructura que contiene los punteros principio y final esté declarada fuera del main, siguen siendo locales a la estructura en los que fueron declarados y por eso los paso por referencia, ¿no?
Eso era lo que no entendía, realmente si sabía que se los pasaba por referencia, pero no tenía muy claro el por que lo hacía, ya que la estructura estaba declarada fuera del main y eso me ha liado.
Y gracias por el consejo a la hora de probar algo cuando no me funcione, realmente suelo hacer lo que dices, pero basándome en ideas que se me ocurren, quiero decir, que no me lió a poner símbolos a loco, si no que intento razonar que puede estar pasando.. normalmente claro, por que hay otros días que ya por perdición me lió a poner cosas sin saber que hago jeje.

CitarTe explico el funcionamiento de malloc, porque creo que la utilizas mal
El problema de malloc creo que lo veo pero no se como solucionarlo, se que lo que le estoy pasando es un puntero al operador sizeof y no en si un tipo de dato, ese sería el problema, ¿no? Si me puedes dar una ayudita mas, se lo agradecería mucho.
CitarEn la función ext_nod cuando haces:
Cierto, disculpa, se me paso ese error por delante y no me di cuenta. Muchísimas gracias por la corrección.
CitarTan preocupado estás por el código de un exámen? y te acuerdas del código perfectamente de dicho exámen? Espero que ésto no sea una tarea, pués sería contrario a las reglas del foro... En cualquier caso en mis explicaciones no doy el código resuelto, sino indicaciones de que hacer para enmendar tus errores...
Tranquilo es normal que sospeches, veras le explico, el caso es que es un examen practico, y la hoja del examen me la pude llevar, teníamos que hacerlo en la clase y enviarlo por correo, el caso de que me complique tanto por ese ejercicio que ya hice y entregue, es por que los enunciados podían tener errores algo que me resultaba bastante raro que un maestro cometa errores a la hora de plantear un examen, ya que de por si, el tema de las estructuras de datos y colas es bastante lioso para un principiante si el enunciado contiene errores sería aún peor.
Lo cierto, es que ya entregue el ejercicio, tenía fallos, a mi profesor le da igual que compilen o no, simplemente quiere el código, realmente para lo que hemos dado lo ha liado bastante el examen,  por ejemplo definiendo los punteros de primero y ultimo dentro de una estructura, nadie de la clase llego a hacerlo.
Aún así quería aprender por mi cuenta y me he puesto a investigar sobre lo que hice para de esa forma  resolver mis dudas que me surgieron a causa de ese examen, de hay todas las preguntas jeje.

Un saludo y muchísimas gracias por todo. Si me puedes explicar un poco mejor lo de malloc lo agradecería muchísimo, Creo que ahora tengo mas claro la implementación de TDA con estructuras de datos.
Muchas gracias.





N0body

-Bueno, pués supuse que era algo así. Yo voy a la secundaria y tuve una profesora que a la hora de hacer un exámen le pedía alguno de los años anteriores a otros profesores y ni se fijaba si se había correjido algo...
Era ing en sistemas y no tenía más p*** idea de como programar... Ni siquiera las cosas más simples xD...
Profesores como esos hay por todas partes, lo peor que te puede pasar es que ensima sean unos tercos y no acepten una acotación del alumno... Pero en programación no hay mucha vuelta basta apretar F9 para darse cuenta quién tenía razón...



-Con respecto a la estructura cola, la parte positiva de tener declarado el tipo de dato nodcola es la posibilidad de retornar ese tipo (aunque no declares más de una variable de ese tipo)
Un ejemplo de ésto:


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

struct punto {
       int x, y;
       };

struct punto funcion (void) {
     struct punto p;
     p.x=0;
     p.y=0;
     return p;
     }

int main(int argc, char *argv[])
{
  struct punto a;
  a.x=6;
  a.y=6;
  printf ("%i %i\n", a.x, a.y);
  a = funcion ();
  printf ("%i %i\n", a.x, a.y);
  system("PAUSE");
  return 0;
}




CitarAunque la estructura que contiene los punteros principio y final esté declarada fuera del main, siguen siendo locales a la estructura en los que fueron declarados y por eso los paso por referencia, ¿no?

Debo reconocer que lo que aquí planteas me ha hecho dudar de mis convicciones. Pero he probado y te paso un ejemplo para que compiles y te des cuenta por tigo mismo que pueden existir estructuras globales (siempres que la variable sea declarada fuera de toda función)...


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

struct punto {
       int x, y;
       };
struct punto p;

void funcion (void) {
     p.x=0;
     p.y=0;
     return;
     }

int main(int argc, char *argv[])
{
  p.x=6;
  p.y=6;
  printf ("%i %i\n", p.x, p.y);
  funcion ();
  printf ("%i %i\n", p.x, p.y);
  system("PAUSE");
  return 0;
}


Osea una cosa es la definición de la estructura
struct punto {
       int x, y;
       };

Y otra distinta la declaración de la variable del tipo de esa estructura:
struct punto p;

Si la definición de la estructura (de la plantilla como dices tu) está fuera de cualquier función (main es una), significa que en todo el código podrás declarar variables de ese tipo...
Si la declaración de la variable está fuera de toda función, esa variable será visible para todas las funciones...



-Con lo que te puse sobre las referencias, ahora me doy cuenta que sólo se puede hacer en c++, es para ahorrarse tantos (*) y evitar errores de distracción que pueden ser difiíciles de detectar. Un ejemplo

Es lo mismo hacer esto:

Código (cpp) [Seleccionar]

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

void funcion (int *x) {
     *x=0;
     return;
     }

int main(int argc, char *argv[])
{
  int a;
  a=6;
  printf ("%i\n", a);
  funcion (&a);
  printf ("%i\n", a);
  system("PAUSE");
  return 0;
}


Que esto:

Código (cpp) [Seleccionar]

#include <cstdlib>
#include <iostream>

using namespace std;

void funcion (int &x) {
     x=0;
     return;
     }

int main(int argc, char *argv[])
{
    int a;
    a=6;
    printf ("%i\n", a);
    funcion (a);
    printf ("%i\n", a);
    system("PAUSE");
    return 0;
}


Pero lo último, como ves, lo tuve que hacer en C++ porque en C no existe...



-En cuanto a la función malloc, este sí que es un problema importante, y puede traerte comportamientos no deseados del programa (por ejemplo cuando sale el cartelito que dice que el programa "no responde"), y luego tu puedes pensar que el problema deriva de no estar pasando por referencia las variables ya que así te funciona "de casualidad":

La memoria utilizada hay q reservarla (por eso declaras las variables, para que tu programar sepa cuánta memoria reservar) Pero...  ¿que sucede en casos como éste que necesito ir declarando nuevos nodos a medida que los voy necesitando?

Bueno en este caso se recuerre a funciones como éstas que reservan un pedacito de memoria de determinado tamaño. La función malloc cuando es llamada, reserva una memoria del tamaño que se le pase por argumento. Ahora... ¿como manejamos la memoria que ha reservado dicha función?. Pues porque la función devuelve la dirección de memoria del espacio que te reservo...
Así si yo quiero declarar un nuevo nodo tengo que tener en claro:
-cuanta memoria reservar, osea, cuanta memoria ocupa el nodo.
-un puntero hacia un tipo nodo, para poder guardar la dirección de la memoria reservada.
Para el primer apartado, tengo que saber el peso de un nodo. De que tipo es el nodo? (Struct Componente). Y por ende uso la función sizeof para saber cuanto pesa...
Para lo segundo apartado, declaro un puntero del tipo (struct componente*) para almacenar la dirección de memoria devuelta (lo habíamos definido como Puntero a este tipo)


Puntero a;
a = (Puntero) malloc (sizeof(struct Componente);

*el "(Puntero)" es porque malloc devuelve un puntero void (void*) y tienes que hacer la conversión...


-Bueno, espero que te quede claro que un código vale más que mil explicaciones... por ende cuando no entiendas algo, has tu propio "experimento" como los ejemplos que te puse

samur88

Ya ves jaja se encuentra uno con cada profesor... bueno si se puede llamar eso jeje
oye pues es genial todo lo que sabes de C y solo estas en la segundaria, has aprendido de forma autodidacta, ¿no?

CitarCon respecto a la estructura cola, la parte positiva de tener declarado el tipo de dato nodcola es la posibilidad de retornar ese tipo (aunque no declares más de una variable de ese tipo)

Muchísimas gracias por el ejemplo. Ahora veo mejor la utilidad que dices.

Sobre el tema de las estructuras globales, es cierto lo que dices, lo he probado en mi codigo, el caso es que ya se que me paso, tenía tal cacao mental en mi cabeza que pasaba los parámetros por valor, y luego tenía problemas para modificarlos, hay pase a pasarselos por referencia y funcionaba correctamente, pero eso no hacía falta, ya que Cola.principio y Cola.final eran variables globales.
Tu aclaración ha servido para darme cuenta de mi error. Muchas gracias.

Muchísimas gracias por la aclaración de las referencias, ya me parecia raro definir de esa forma los parámetros, pero pense que se podía hacer. Gracias lo tendre en cuenta en un futuro.

Sobre el malloc ahora me ha quedado mas claro todo, mira he puesto otro post, te lo enlazo aquí creo que hay un problema con malloc como dices, pero he probado a modificarlo de la forma que me has dicho en este post pero sigo teniendolo, si le puedes echar un vistazo al problema que planteo te lo agradecería mucho, ya que no consigo ver donde esta el error de funcionamiento.
Este es el otro post publicado: http://foro.elhacker.net/programacion_cc/fallo_de_segmentacion_al_agregar_mas_nodos_en_una_lista-t317205.0.html
Un saludo y muchísimas gracias por todo de veras.