Punteros y memoria dinamica

Iniciado por bemone, 28 Agosto 2015, 19:11 PM

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

bemone

Buenas tardes gente,

Estoy aprendiendo C y me estoy rompiendo el marote contra la pared bien fuerte.
Tengo una estructura Persona. La cual quiero manipularla dinamicamente a traves de la estructura Array (TDA) y me surgio un problema que desconozco a que se puede deber.

Si cargo el array desde el main() todo funciona perfecto. Cuando lo quiero cargar a traves de un metodo, se rompe todo.

He aqui el codigo:

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

typedef struct persona{
   char *nombre;
   int edad;
   int sexo;
}Persona;

typedef struct {
   int size;
   Persona vecPersona[];
}Array;

Array* getArrayInstance(){
   Array *vec;
   vec = (Array*) malloc (sizeof(Persona));
   vec->size = 0;
   return vec;
}

void push_back(Array ** vec, Persona tipito){
   (*vec)->vecPersona[(*vec)->size] = tipito;
   (*vec)->size++;
   printf("%d-", (*vec)->size);
   int newSize = (*vec)->size*2-(*vec)->size+1;
   Array *tmp = realloc((*vec), newSize*sizeof(Persona));
   if(tmp)
       *vec = tmp;
   else
       (*vec)->size--;
}

void mostrarPersonas(Array *vec){
   int i;
   printf("\n\n");
   printf("%d", vec->size);
   for(i=0; i<vec->size; i++){
       printf("(%d) Nombre: %s - Edad: %d - Sexo: ", i, vec->vecPersona[i].nombre, vec->vecPersona[i].edad);
       if(vec->vecPersona[i].sexo == 0)
           printf("Masculino");
       else
           printf("Femenino");
       printf("\n");
   }
}

void cargarPersonas(Array **vec){
   int i, edad, random;
   int cantPersonas = rand()%30+1;
   Persona aux;
   char **hombres = {"Ramiro","Pedro","Federico","Jose","Antonio","Pablo","Raul","Gustavo","Gonzalo","Airton"};
   char **mujeres = {"Mariana","Jennifer","Luz","Roxana","Ana","Sol","Micaela","Romina","Melina","Camila"};
   for(i=0; i<cantPersonas; i++){
       edad = rand()%80+1;
       aux.edad = edad;
       if( (random = rand()%10) %2 == 0){ // hombres
           aux.nombre = hombres[random];
           aux.sexo = 0;
       }
       else{
           aux.nombre = mujeres[random];
           aux.sexo = 1;
       }

       push_back(vec, aux);
   }
}


int main()
{
   srand(time(NULL));
   Array *vecPersonas = getArrayInstance();

   Persona aux;
   aux.nombre="Cecilia";
   aux.edad=27;
   aux.sexo=0;
   push_back(&vecPersonas, aux); // Esto anda
   push_back(&vecPersonas, aux); // Esto anda
   push_back(&vecPersonas, aux); // Esto anda
   push_back(&vecPersonas, aux); // Esto anda
   push_back(&vecPersonas, aux); // Esto anda
   push_back(&vecPersonas, aux); // Esto anda

   //cargarPersonas(&vecPersonas); // Esto no
   //printf("%d", vecPersonas->size);
   mostrarPersonas(vecPersonas);

   return 0;
}



:-\ :-\
Odio los tipos de variable de Windows.

ivancea96

Array* getArrayInstance(){
    Array *vec;
    vec = (Array*) malloc (sizeof(Persona));
    vec->size = 0;
    return vec;
}


(Array*) malloc(sizeof(Persona));

Si vas a crear un Array, entonces tendrás que poner sizeof(Array), puesto que Array tiene un tamaño de sizeof(Persona*) + sizeof(int) = 8 bytes, mientras que Persona tiene un tamaño de 12 bytes.

bemone

Cita de: ivancea96 en 29 Agosto 2015, 01:20 AM
Array* getArrayInstance(){
    Array *vec;
    vec = (Array*) malloc (sizeof(Persona));
    vec->size = 0;
    return vec;
}


(Array*) malloc(sizeof(Persona));

Si vas a crear un Array, entonces tendrás que poner sizeof(Array), puesto que Array tiene un tamaño de sizeof(Persona*) + sizeof(int) = 8 bytes, mientras que Persona tiene un tamaño de 12 bytes.

Perdon, creo que me exprese mal.
Quiero un Array dinamico dentro de una estructura.
Lo que me decis vos es para crear un array de Array.
Odio los tipos de variable de Windows.

ivancea96

No, es correcto. Pon malloc(sizeof(Array)), puesto que estás reservando memoria del tamaño de Array.

Otra cosa importante: en vez de:
Persona vecPersona[];
pon:
Persona *vecPersona;
Puesto que es un puntero.

Además, tienes otros errores como, en push_back:

int newSize = (*vec)->size*2-(*vec)->size+1;

No sé qué pretendes sacar con esa ecuación. Al principio, siendo size=1, haces un realloc((*vec)->vecPersona, 0). Y ya luego, valores altos. Eso debería quedar:

int newSize = (*vec)->size+1;

En fin, he reconstruido esa función:
void push_back(Array ** vec, Persona tipito){
int newSize = (*vec)->size+1;
Persona *tmp = realloc((*vec)->vecPersona, newSize*sizeof(Persona));
if(tmp){
(*vec)->vecPersona = tmp;
(*vec)->vecPersona[(*vec)->size] = tipito;
(*vec)->size++;
}
    printf("%d-", (*vec)->size);
}


Además, inicialicé el contenido de vecPersona en getArrayInstance:
Array* getArrayInstance(){
    Array *vec;
    vec = (Array*) malloc (sizeof(Array));
vec->vecPersona = 0;
    vec->size = 0;
    return vec;
}


Y otro tema muy importante:

char *hombres[] = {"Carlos", "Pablo"};
No puedes poner un doble puntero para ser inicializado de ese modo.


Además, en push_back te recomiendo poner:

(*vec)->vecPersona[(*vec)->size].nombre = (char*) malloc((strlen(tipito.nombre)+1)*sizeof(char));
strcpy((*vec)->vecPersona[(*vec)->size].nombre, tipito.nombre);


Copiar las cadenas, no copiar los punteros, puesto que si se libera la memoria de uno de ellos, todos los demás perderán lso datos, y podrán tirar errores.

Claro que si vas a hacer un método "pop", tendrás que recordar liberarlos.

Bueno, este es el código completo, por si quieres ver qué se cambió más claramente:

Para strlen y strcpy, la librería <string.h>

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

typedef struct persona{
    char *nombre;
    int edad;
    int sexo;
}Persona;

typedef struct {
    int size;
    Persona *vecPersona;
}Array;

Array* getArrayInstance(){
    Array *vec;
    vec = (Array*) malloc (sizeof(Array));
vec->vecPersona = 0;
    vec->size = 0;
    return vec;
}

void push_back(Array ** vec, Persona tipito){
int newSize = (*vec)->size+1;
Persona *tmp = realloc((*vec)->vecPersona, newSize*sizeof(Persona));
if(tmp){
(*vec)->vecPersona = tmp;
(*vec)->vecPersona[(*vec)->size] = tipito;
(*vec)->vecPersona[(*vec)->size].nombre = (char*) malloc((strlen(tipito.nombre)+1)*sizeof(char));
strcpy((*vec)->vecPersona[(*vec)->size].nombre, tipito.nombre);
(*vec)->size++;
}
}

void mostrarPersonas(Array *vec){
    int i;
    printf("\n\n");
    for(i=0; i<vec->size; i++){
        printf("(%d) Nombre: %s - Edad: %d - Sexo: ", i, vec->vecPersona[i].nombre, vec->vecPersona[i].edad);
        if(vec->vecPersona[i].sexo == 0)
            printf("Masculino");
        else
            printf("Femenino");
        printf("\n");
    }
}

void cargarPersonas(Array **vec){
    int i, edad, random;
    int cantPersonas = rand()%30+1;
    Persona aux;
    char *hombres[] = {"Ramiro","Pedro","Federico","Jose","Antonio","Pablo","Raul","Gustavo","Gonzalo","Airton"};
    char *mujeres[] = {"Mariana","Jennifer","Luz","Roxana","Ana","Sol","Micaela","Romina","Melina","Camila"};
    for(i=0; i<cantPersonas; i++){
        edad = rand()%80+1;
        aux.edad = edad;
        if( (random = rand()%10) %2 == 0){ // hombres
            aux.nombre = hombres[random];
            aux.sexo = 0;
        }
        else{
            aux.nombre = mujeres[random];
            aux.sexo = 1;
        }

        push_back(vec, aux);
    }
}


int main()
{
    srand(time(NULL));
    Array *vecPersonas = getArrayInstance();
    cargarPersonas(&vecPersonas); // Esto no
    printf("%d", vecPersonas->size);
    mostrarPersonas(vecPersonas);

    return 0;
}

geeke

Otra aproximación con la correspondiente liberación de memoria del array de estructuras y algunas que otras mejoras

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

typedef struct Persona
{
    char *nombre;
    int edad;
    int sexo;
} Persona;

typedef struct
{
    Persona *array;
    size_t used;
    size_t size;
} Array;

void initArray(Array *a, size_t initialSize)
{
    a->array = (Persona*)calloc(initialSize , sizeof(Persona));
    a->used = 0;
    a->size = initialSize;
}

void push_back(Array *a, Persona element)
{
    if (a->used == a->size)
    {
        a->size *= 2;
        a->array = (Persona *)realloc(a->array, a->size * sizeof(Persona));
        memset(&a->array[a->used],0,sizeof(Persona) * (a->size - a->used));
    }
    a->array[a->used].nombre = (char*)malloc(strlen(element.nombre) + 1);
    strcpy(a->array[a->used].nombre, element.nombre);
    a->array[a->used].edad = element.edad;
    a->array[a->used].sexo = element.sexo;
    a->used++;
}

void freeArray(Array *a)
{
    int i;
    for (i = 0; i < a->used; i++)
    {
        free(a->array[i].nombre);
        a->array[i].nombre = NULL;
    }
    free(a->array);
    a->array = NULL;

    a->used = 0;
    a->size = 0;
}

void cargarPersonas(Array * arr)
{
    int i, edad, random;
    int TAM = rand() % 30 + 1;
    Persona temp;

    char *hombres[] = {"Ramiro","Pedro","Federico","Jose","Antonio","Pablo","Raul","Gustavo","Gonzalo","Airton"};
    char *mujeres[] = {"Mariana","Jennifer","Luz","Roxana","Ana","Sol","Micaela","Romina","Melina","Camila"};

    for ( i = 0; i < TAM; i++)
    {
        edad = rand() % 80 + 1;
        temp.edad = edad;
        if( (random = rand() % 10) % 2 == 0)
        {
            temp.nombre = hombres[random];
            temp.sexo = 0;
        }
        else
        {
            temp.nombre = mujeres[random];
            temp.sexo = 1;
        }
        push_back(arr, temp);
    }
}

void mostrarPersonas(Array *arr)
{
    int i;
    for ( i = 0; i < arr->used; i++)
    {
        printf("(%d) Nombre: %s - Edad: %d - Sexo: ", i, arr->array[i].nombre, arr->array[i].edad);
        if ( arr->array[i].sexo == 0)
            printf("Masculino");
        else
            printf("Femenino");
        printf("\n");
    }
}

int main(void)
{
    srand(time(NULL));
    Array a;
    initArray(&a, 5);

    cargarPersonas(&a);
    mostrarPersonas(&a);

    freeArray(&a);
    return 0;
}