[C] Problema con Struct en funciones que llaman a otras funciones

Iniciado por ‭lipman, 14 Mayo 2011, 18:37 PM

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

‭lipman

Mi objetivo es crear un sistema básico que en una función, teniendo un limite, esté añadiendo contactos a una tabla.

La cosa es que no entiendo porqué no me funciona lo siguiente:

#include<stdio.h>
#define LIMITE 3



struct contactos {

  char telefono[10];

  char descripcion[51];

};

//Prototipos:
int almacenaContacto(struct contactos *f);
void leerContacto(struct contactos *f);

int main(){ //INICIO PROGRAMA

int variable;

struct contactos gente[LIMITE];



variable=almacenaContacto(&gente);




return 0;

} //FIN PROGRAMA

int almacenaContacto(struct contactos *f){


int i=0;

  while(i<LIMITE){

  leerContacto(&(*f)[i]);

  i=i+1;

  }
}

//Nota: la funcion leerContacto funciona correctamente: recibe un parámetro struct y me permite ir añadiendo contacto a contacto

La parte que empieza a dar problemas en el programa es la de "leerContacto(&(*f)[ i]);", es decir, que podria concluir diciendo que:

Tengo un programa principal y en el tengo un struct en el que quiero que vayan un determinado numero de elementos. Llamo a una funcion para que haga el bucle y vaya uno a uno, y a su vez, esta función llama a otra que se encarga individualmente de meter los datos en cada una. Mi error se encuentra justo aquí al final, que no se porqué, no consigo hacer referencia a cada parte en el bucle.

Alguna idea?

Un saludo

‭lipman

Voy a replantear el problema de otra forma, igual así alguien me puede ayudar de otra manera >.<

Tengo el siguiente código que funciona correctamente:

#include<stdio.h>


struct contacto {
  char tlfn[10];
  char dir[51];
};

//Prototipo
void probar(void);
void escribir(struct contacto *f);

int main(){
  probar();
  return 0;
}


void probar(void){
int i=0;
struct contacto gente[3];

while(i<3){
  escribir(&gente[i]);
  i=i+1;
}

}

void escribir(struct contacto *f){

printf("Introduce el telefono: ");
gets((*f).tlfn);
printf("Introduce la direccion: ");
gets((*f).dir);

}


Explicación breve:
La función principal llama a una funcion que define unas estructuras y mediante un bucle va rellenándolas. Si dentro de la primera función pusiera otra que se encargase de leer lo que he introducido, lo leeria perfectamente. El problema es que la estructura que he escrito la quiero en el int main, y no tengo ni idea de cómo llamarla.

Alguna idea?

Littlehorse

Quieres tener la estructura declarada en el main, pasarla a un función que ingrese datos a ella, y luego pasarla a otra función que lea los parámetros que le fueron ingresados.
Podes pasar el puntero directamente de la función 1 a la función 2.

Es decir, en main tenes algo como esto:

int main{
//random code
struct contacto gente[3];

AlgunaFuncion( &gente[x]);


void AlgunaFuncion ( struct contacto *ptr)
{
//random code

ptr->algo =  otracosa;

FuncionNumeroDos(ptr);
}



FuncionNumeroDos ( struct contacto *ptr) 
{
//random code
printf("%s", ptr->algo);

}


También podrías pasar el arreglo de estructuras directamente, pero no se si es eso lo que estas buscando.
No se si te entendí del todo, cualquier cosa me avisas.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

‭lipman

Muchas gracias! Ya poco a poco estoy más cerca de la solución, pero todavia le falla algo. Aquí dejo el código completo de momento:

#include<stdio.h>

struct contacto {
  char tlfn[10];
  char dir[51];
};

//Prototipo
void probar(struct contacto *f);
void escribir(struct contacto *f);

int main(){
  struct contacto gente[3];
  probar(&gente[3]);
  return 0;
}

void probar(struct contacto *f){
int i=0;

while(i<3){
  escribir(f);
  i=i+1;
}

}

void escribir(struct contacto *f){

printf("Introduce el telefono: ");
gets(f->tlfn);
printf("Introduce la direccion: ");
gets(f->dir);

}


Este código compila (te sale el warning de la funcion gets pero no es problema). El error viene cuando lo voy a ejecutar: hace los tres bucles pidiendome tres veces los datos, los introduzco, y justo despues, en lugar de terminar sin decirme nada, me salta con un: "violacion del segmento ('core' generado)"

El problema no es del gets, porque lo he cambiado por unos respectivos bucles usando el getchar con lectura adelantada para que compile sin warnings y recogiendo la información usando otra alternativa y termina exactamente igual.

¿Que puede pasar?

Un saludo y gracias!

Littlehorse

#4
Bueno por lo pronto algunas cosas:


while(i<3){
escribir(f);
i=i+1;
}


Esto no se porque lo haces siendo que f siempre contiene el mismo elemento. Es decir, ese bucle no tiene sentido, estas asignando contenido siempre al mismo elemento, el cual es el que le pasaste desde main. En todo caso en el main es donde tendrías que hacer el bucle (pasarías un elemento a la función probar en cada vuelta), o le tendrías que pasar el array completo a la función probar y ahí si seria correcto de la forma en que lo tienes.

Entrando en el main, el elemento que le pasas esta fuera de los limites del array. Recuerda que el primer elemento de un array comienza en la posición 0 y termina en arraymax-1.

struct contacto gente[3];
probar(&gente[3]);


gente[0] , gente[1], gente[2]. Esas son las 3 posiciones que tenes actualmente.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

‭lipman

Vale vale, me he liado y no me he fijado en eso, de ahí viene esa incongruencia tan rara =S

Lo que yo queria hacer (ahora entenderás el porqué del bucle while) era que, desde la primera funcion a la que llamas, haga un bucle de, en este caso, tres veces, ejecutando la funcion segunda tres veces en total. Esta funcion segunda es la que se encarga de tomar los datos. De esta manera, si tengo un array gente[3] (como tu dices, del 0 al 2), quisiera pasarle a la segunda funcion cada vez un valor distinto, para que al final de la llamada a la segunda función, tras recoger todos los datos, me quedase lo siguiente de forma esquemática:

gente[0].tlfn = "lo que sea"
gente[0].dir = "lo que sea"
gente[1].tlfn = "lo que sea"
gente[1].dir = "lo que sea"
gente[2].tlfn = "lo que sea"
gente[2].dir = "lo que sea"

Y de esta manera, desde la función principal poder usar cualquier dato. Creo que ahora si que me he explicado bien xD, pero claro, lo que no puedo hacer es lo siguiente:

while(i<3){
  escribir(f[i]);
  i=i+1;
}


O igual si que puedo hacerlo, pero tengo que cambiar la estructura de la función escribir: ahí mi duda.

Muchas gracias, un saludo!

Littlehorse

#6
void probar(struct contacto f[]) // *f
{
int i=0;

while(i<3){
escribir(&f[i]);
i=i+1;
}

}


//llamada
probar(gente);


Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

‭lipman

En efesto. Muchísimas gracias, me solucionaste el problema por completo =)

D4RIO

En vista de tu código, supongo que estás aprendiendo C y no tienes del todo afianzados los conocimientos técnicos del lenguaje. Por eso, permíteme hacerte algunos comentarios que te pueden favorecer el aprendizaje.

Primer Punto: No debería ser un WHILE sino un FOR, puesto que sabes exáctamente cuántos lugares recorrer.

Segundo: En estos casos, mientras uses C, te convendría ser más explícito en la aritmética de punteros, y quizá menos en la lógica. Yo prefiero ese estilo de codificación porque es más explícito en lo que se está haciendo a nivel memoria. Me refiero a que si tu código es más técnico, lo comprenderás mejor. Cuando conozcas lo suficiente, elegirás cuál es tu manera de codificar favorita.

No he probado porque estoy en el trabajo, pero esto es lo que haría yo:

1 - SIEMPRE pasar el puntero, así sabemos exáctamente con qué trabajamos:
int almacenaContacto(struct contactos *f)

2 - Usar la aritmética de punteros. Cada suma de una unidad para un puntero es un desplazamiento equivalente a su tamaño. Es totalmente claro hacer algo así:
int almacenaContacto(struct contactos *f){
    int i;
    struct contactos *punt = f;
    /* punt contiene la misma direccion, por
     * lo tanto es equivalente, pero como es
     * local a la funcion, podemos moverlo
     */
    for(i=0; i<LIMITE; i++) {
        /* en cada vuelta tienes una llamada simple
         */
        leerContacto(punt);
        /* se mueve una vez el tamanno de
         * la estructura
         */
        punt++;
    }
}


Respecto a la notación que LittleHorse te indicaba, lo reescribiría de esta forma:
void probar(struct contacto f[]) {
    int i;
    for(i=0; i<3; i++){
        escribir(&f[i]);
    }
}



Y por favor, no utilices:
i=i+1

Esto no es PASCAL, aquí existe el operador de incremento:
i++


Saludos
OpenBSDFreeBSD

Littlehorse

Cita de: ‭lipman en 18 Mayo 2011, 12:40 PM
En efesto. Muchísimas gracias, me solucionaste el problema por completo =)

De nada! igualmente dale una leída a todo lo que es punteros y pasaje por referencia así no queda nada en el aire.

Cita de: xD4RIOx en 18 Mayo 2011, 20:37 PM

Respecto a la notación que LittleHorse te indicaba, lo reescribiría de esta forma:
void probar(struct contacto f[]) {
int i;
for(i=0; i<3; i++){
escribir(&f[i]);
}
}


Solo tome el código tal cual estaba en el primer post y modifique los parámetros para resolver la duda inicial, por lo que el código no es realmente mio. Mas allá de esta pequeña aclaración, tus indicaciones son correctas.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.