Dimensionar un vector dentro de un struct

Iniciado por ShadowA7X, 8 Noviembre 2014, 19:32 PM

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

ShadowA7X

Que tal chicos y chicas,disculpen la pregunta pero me puse ante los diversos casos en el manejo de structs y éste (que creo que es básico) no lo puedo hacer.

#include <stdio.h>

typedef struct humano{

int *trabajos;

}persona;

int main(){

int cantidad_personas=8;
int cantidad_trabajos=4;
persona *primera;
primera=(persona *)malloc(sizeof(persona)*cantidad_personas);

/* Hasta este punto por lo que entiendo hice un arreglo dinamico en donde
  ubicamos a la persona en un espacio del arreglo*/

//Ahora bien cada persona tendrá más de un trabajo por lo cual el puntero
//trabajo (*trabajos) debemos convertirlo en un vector.

return 0;
}


Mi pregunta es ¿cómo hago eso? el *primera que es de tipo persona lo transformamos en un vector dinámico, pero una vez hecho eso ¿Cómo transformo el puntero que ésta dentro de *primera en otro vector?

De antemano muchas gracias.

kutcher

Cita de: ShadowA7X en  8 Noviembre 2014, 19:32 PM
¿Cómo transformo el puntero que ésta dentro de *primera en otro vector?

Simple:

primera -> trabajos = malloc(...);

Saludos

ShadowA7X

#2
Cita de: kutcher en  8 Noviembre 2014, 19:59 PM
Simple:

primera -> trabajos = malloc(...);

Saludos

Por ahí como que funciona pero con errores. Por ejemplo hice esta cosa que tiene que imprimir por pantalla del 1 al 32, pero sólo imprime los últimos 4 números(29,30,31,32) ocho veces.

#include <stdio.h>

typedef struct humano{

int *trabajos;

}persona;

int main(){

int i,j,cont=1;
int cantidad_personas=8;
int cantidad_trabajos=4;
persona *primera;
primera=(persona *)malloc(sizeof(persona)*cantidad_personas);

primera->trabajos=(int *)malloc(sizeof(int)*cantidad_trabajos);


for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

primera->trabajos[j]=cont;
cont++;
}
}

for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

printf("%d ",primera->trabajos[j]);
}
printf("\n");
}

return 0;
}


Y si le pongo un contador a primera (es decir primera [i] -> no me compila :( ) qué pasa?

ivancea96

#3
No sería primera[ i ]->, porque ya no sería puntero. Sería primera[ i ].trabajos (etc)

plataplomo2948

#4
1. Estas usando un puntero doble... por que?

2. El tomano del int siempre va a ser 4 bytes. Por cada persona, hay que allocar otro struct. Si no quiere hacer eso, hay que poner mas variables dentro de su struct.

Trata eso, pra mi funciono


typedef struct Humano
{
   int Trabajos;          
} HUMANO, *PHUMANO;    
   
int main ()
{
     
      PHUMANO Primera = (PHUMANO)malloc(sizeof(HUMANO));

      Primera->Trabajos = (int)malloc(sizeof(int));
     
      // nunca debe hacer eso por que es allocacion dinamica y eso es un valor estatico pero
     // solo es pra mostrar como funciona
      Primera->Trabajos = 248;

      printf("Primera->Trabajos = %i\n", Primera->Trabajos);
     
      free((int*)Primera->Trabajos);
      free(Primera);
      return 0;
}





Acabo de ver eso, y en ese caso no es necesario usar la alocacion dinamica porque en linea 10 "cont" es un valor estatico. Es decir que ya esta en el stack y la memora ya viene allocada del imagen.

modificacion - disculpe - en linea 11 es la declaracion estatica y en linea 23 pongas un valor dinamica a un valor estatica.



Ok, veo porque usa un puntero doble. Quiere hacer un int array dentro de un struct. Debe hacer asi:


typedef struct Humano
{
    int* Trabajos;         
} HUMANO, *PHUMANO;   
   
int main ()
{
       // eso coresponde al tomano de su array
       int NumeroDeElementos = 30;
       PHUMANO Primera = (PHUMANO)malloc(sizeof(HUMANO));

       Primera->Trabajos = (int*)malloc(sizeof(int) * NumeroDeElementos);
       
       // nunca debe hacer eso por que es allocacion dinamica y eso es un valor estatico pero
      // solo es pra mostrar como funciona
       Primera->Trabajos[15] = 248;

       printf("Primera->Trabajos = %i\n", Primera->Trabajos[15]);
       
       free((int*)Primera->Trabajos);
       free(Primera);
       return 0;
}




modificaion - se me olvido poner un *

ShadowA7X

Cita de: plataplomo2948 en  8 Noviembre 2014, 20:57 PM
Ok, veo porque usa un puntero doble. Quiere hacer un int array dentro de un struct. Debe hacer asi:


typedef struct Humano
{
   int* Trabajos;          
} HUMANO, *PHUMANO;    
   
int main ()
{
      // eso coresponde al tomano de su array
      int NumeroDeElementos = 30;
      PHUMANO Primera = (PHUMANO)malloc(sizeof(HUMANO));

      Primera->Trabajos = (int*)malloc(sizeof(int) * NumeroDeElementos);
     
      // nunca debe hacer eso por que es allocacion dinamica y eso es un valor estatico pero
     // solo es pra mostrar como funciona
      Primera->Trabajos[15] = 248;

      printf("Primera->Trabajos = %i\n", Primera->Trabajos[15]);
     
      free((int*)Primera->Trabajos);
      free(Primera);
      return 0;
}




modificaion - se me olvido poner un *


Primero muchas gracias por darte el tiempo de sacarme esta duda hermano, en verdad te lo agradezco.

1-Porque el vector de tipo  persona es dinámico y contiene otro vector dinámico en su interior.

2- Pero cada persona será representada por la casilla del vector, y esa casilla/persona tiene asignadas muchas tareas (que en este caso es 4 por ej), según el programa y los for que tengo, puedo moverme por las tareas pero no por las personas (pues no puedo agregar un contador "i" a la persona para irla recorriendo (la idea es no agregar variables al struct y usar lo que está).

Este ejemplo de 32 es sumamente improvisado, es sólo para tener la idea, pero ud que cambiaría para que el programa pueda imprimir del 1 al 32 y que no imprima el 29,30,31 y 32 ocho veces?

Así como ejemplo mi programa está así:

#include <stdio.h>

typedef struct humano{

int *trabajos;

}persona;

int main(){

int i,j,cont=1;
int cantidad_personas=8;
int cantidad_trabajos=4;
persona *primera;
primera=(persona *)malloc(sizeof(persona)*cantidad_personas);

primera->trabajos=(int *)malloc(sizeof(int)*cantidad_trabajos);


for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

primera->trabajos[j]=cont;
cont++;
}
}

for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

printf("%d ",primera->trabajos[j]);
}
printf("\n");
}

return 0;
}


Y en un mundo ideal, lo que yo quiero es que avance por las personas y los trabajos así (aclaro este no compila pero si compilara haría lo que yo quiero(bajo una logica algoritmica)):

#include <stdio.h>

typedef struct humano{

int *trabajos;

}persona;

int main(){

int i,j,cont=1;
int cantidad_personas=8;
int cantidad_trabajos=4;
persona *primera;
primera=(persona *)malloc(sizeof(persona)*cantidad_personas);

primera->trabajos=(int *)malloc(sizeof(int)*cantidad_trabajos);


for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

primera[i]->trabajos[j]=cont;
cont++;
}
}

for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

printf("%d ",primera[i]->trabajos[j]);
}
printf("\n");
}

return 0;
}



Ud cómo le haría/modificaría tomando en cuenta el mismo ejemplo que le muestro?

plataplomo2948

#6
Bueno, me parece que usted sabe de lo que habla aun que no entiendo exactamente cual es su objectivo final, pero eso es como hacer el codigo para que compila bien. Eso imprima hasta 32.

La proxima vez, deberia poner su error de compilicaion y decir que quiere hacer "un array de int dentro de un array de struct" : ) suerte


typedef struct Humano
{
   int* Trabajos;          
} HUMANO, *PHUMANO;    
   
int main ()
{
      int CantidadDeTrabajos = 4; //
      int CantidadDePersonas = 8;    // personas
      int Cont = 0;
     
      // declarar espacio por un array de struct
      PHUMANO Primera = (PHUMANO)malloc(sizeof(HUMANO) * CantidadDePersonas);
     
      // por cada persona, declara un array dentro el struct
      for (int i = 0; i < CantidadDePersonas; i++)
          Primera[i].Trabajos = (int*)malloc(sizeof(int) * CantidadDeTrabajos);
     
      for (int i = 0; i < CantidadDePersonas; i++)
      {
          for (int j = 0; j < CantidadDeTrabajos; j++)
          {
              Cont += 1;
                 
              Primera[i].Trabajos[j] = Cont;
          }    
      }
     
      for (int i = 0; i < CantidadDePersonas; i++)
          for (int j = 0; j < CantidadDeTrabajos; j++)
              printf("Trabajo#%i\n", Primera[i].Trabajos[j]);
             
             
      //Primera[0].Trabajos[0] = 248;

      //printf("Primera->Trabajos = %i\n", Primera[0].Trabajos[0]);
     
     
      for (int i = 0; i < CantidadDePersonas; i++)
          free((int*)Primera[i].Trabajos);
     
      free(Primera);
      _getch ();
      return 0;
}



Modificacion - Al respecto a 1 - no estamos trabajando con los vectores, estos son arrayes (son parecidos pero hay diferencias). Todavia si estariamos trabajando con vectores, la alocacion dinamica no seria necesario por ese codigo. Tambien, los vectores son de C++, asi que si quiere usar vectores - seria mejor usar new/delete en vez de malloc/free (eso no va a cambiar el comportamiento de su programa, solo para notar la diferencia entre C y C++ y por que no es mejor practica a mezclarlos).

Generalmente, la alocacion dinamica es necesario solo cuando acepta algun tipo de input, sea de un archivo, stdin, socket, etc. Cuando hace un inicilizacion estatica (int i = 0), esa secion de memoria (los 4 bytes) SIEMPRE va a ser libre para manipular, si o si. 

ShadowA7X

Cita de: plataplomo2948 en  8 Noviembre 2014, 21:54 PM
Bueno, me parece que usted sabe de lo que habla aun que no entiendo exactamente cual es su objectivo final, pero eso es como hacer el codigo para que compila bien. Eso imprima hasta 32.

La proxima vez, deberia poner su error de compilicaion y decir que quiere hacer "un array de int dentro de un array de struct" : ) suerte


typedef struct Humano
{
   int* Trabajos;          
} HUMANO, *PHUMANO;    
   
int main ()
{
      int CantidadDeTrabajos = 4; //
      int CantidadDePersonas = 8;    // personas
      int Cont = 0;
     
      // declarar espacio por un array de struct
      PHUMANO Primera = (PHUMANO)malloc(sizeof(HUMANO) * CantidadDePersonas);
     
      // por cada persona, declara un array dentro el struct
      for (int i = 0; i < CantidadDePersonas; i++)
          Primera[i].Trabajos = (int*)malloc(sizeof(int) * CantidadDeTrabajos);
     
      for (int i = 0; i < CantidadDePersonas; i++)
      {
          for (int j = 0; j < CantidadDeTrabajos; j++)
          {
              Cont += 1;
                 
              Primera[i].Trabajos[j] = Cont;
          }    
      }
     
      for (int i = 0; i < CantidadDePersonas; i++)
          for (int j = 0; j < CantidadDeTrabajos; j++)
              printf("Trabajo#%i\n", Primera[i].Trabajos[j]);
             
             
      //Primera[0].Trabajos[0] = 248;

      //printf("Primera->Trabajos = %i\n", Primera[0].Trabajos[0]);
     
     
      for (int i = 0; i < CantidadDePersonas; i++)
          free((int*)Primera[i].Trabajos);
     
      free(Primera);
      _getch ();
      return 0;
}



Modificacion - Al respecto a 1 - no estamos trabajando con los vectores, estos son arrayes (son parecidos pero hay diferencias). Todavia si estariamos trabajando con vectores, la alocacion dinamica no seria necesario por ese codigo. Tambien, los vectores son de C++, asi que si quiere usar vectores - seria mejor usar new/delete en vez de malloc/free (eso no va a cambiar el comportamiento de su programa, solo para notar la diferencia entre C y C++ y por que no es mejor practica a mezclarlos).

Generalmente, la alocacion dinamica es necesario solo cuando acepta algun tipo de input, sea de un archivo, stdin, socket, etc. Cuando hace un inicilizacion estatica (int i = 0), esa secion de memoria (los 4 bytes) SIEMPRE va a ser libre para manipular, si o si. 

Hermano, no sabes como te lo hipermegacontramuchoAGRADESCO!!! gracias a lo que hiciste entendí perfectamente que era lo que me hacía falta. Adapte lo que tu hiciste a mi código y mi error fundamental salió a la luz!! lo dejo aquí para que quien tenga éste problema pueda solucinarlo:

Mi código modificado según las apreciaciones de plataplomo2948 es éste:

#include <stdio.h>

typedef struct humano{

int *trabajos;

}persona;

int main(){

int i,j,cont=1;
int cantidad_personas=8;
int cantidad_trabajos=4;
persona *primera;
primera=(persona *)malloc(sizeof(persona)*cantidad_personas);


for (i=0; i < cantidad_personas; i++){
primera[i].trabajos=(int *)malloc(sizeof(int)*cantidad_trabajos);
}


for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

primera[i].trabajos[j]=cont;
cont++;
}
}

for (i = 0; i < cantidad_personas; i++){
for (j = 0; j < cantidad_trabajos; j++){

printf("%d ",primera[i].trabajos[j]);
}
printf("\n");
}

for (i = 0; i < cantidad_personas; i++){

free((int *) primera[i].trabajos);
}

free(primera);

return 0;
}


Y él error fundamental que me permite ver toda la lógica de ésto era en ésta parte:

for (i=0; i < cantidad_personas; i++){
primera[i].trabajos=(int *)malloc(sizeof(int)*cantidad_trabajos);
}


Al momento de dimensionar esa parte nunca se me ocurrió hacerlo dentro de un for, y bajo lo que ahora al fin entendí (corrijame plataplomo2948 si estoy equivocado) es obligación dimensionar cada espacio de primera en consideración a la cantidad de trabajos que haya.

El código compila perfectamente y puedo dar por solucionada mi duda. Enserio  plataplomo2948 infinitas gracias, ahora puedo hacer lo que realmente quiero :).

Por último si me permites molestarte, en la parte donde liberas memoria:

for (int i = 0; i < CantidadDePersonas; i++)
           free((int*)Primera[i].Trabajos);


por qué se pone (int *) dentro del free y no sólo free(Primera[i].trabajos)?

Sólo esa pequeña duda me quedó, pero de antemano muchas gracias por todo bro, eres un crack!

ivancea96

No hay que poner (int*) dentro del free. free() recibe un parámetro void*. El haber puesto (int*) habrá sido una equivocación. (El tipo ya es int* de por sí)

plataplomo2948

Es cuestion de preferencia y estilo (pra mi es mas facil leer) - no hace diferencia en el ASM que compila. Cosas asi no van a afectar el comprtamiento del programa y en ese caso solo es estitica.

tambem se me olvido hacer el checkeo de errores en el malloc(). tiene que hacer algo asi despues de cada llamada a malloc()

if Primera.Trabajos o Primera == NULL
    goto FINAL;

tambien, despues de liberarlos, tiene que poner el valor a cada variable a NULL. es buena practica para evitar la explotacion "use after free"