Malloc para estructura y puntero en C

Supongamos que quiero definir una estructura que represente la longitud del vector y sus valores como:

struct Vector{ double* x; int n; }; 

Ahora, supongamos que quiero definir un vector y y asignarle memoria.

 struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); 

Mi búsqueda en Internet muestra que debo asignar la memoria para x por separado.

 y->x = (double*)malloc(10*sizeof(double)); 

Pero, parece que estoy asignando la memoria para y-> x dos veces, una mientras asigno memoria para y y la otra asignando memoria para y-> x, y parece una pérdida de memoria. Es muy apreciado si me permite saber qué es lo que realmente hace el comstackdor y cuál sería la manera correcta de inicializar y, y y-> x.

Gracias por adelantado.

No, no estás asignando memoria para y->x dos veces.

En su lugar, está asignando memoria para la estructura (que incluye un puntero) más algo para que el puntero apunte.

Piénsalo de esta manera:

  1 2 +-----+ +------+ y------>| x------>| *x | | n | +------+ +-----+ 

Entonces realmente necesitas las dos asignaciones ( 1 y 2 ) para almacenar todo.

Además, su tipo debería ser struct Vector *y ya que es un puntero, y nunca debe convertir el valor de retorno de malloc en C, ya que puede ocultar ciertos problemas que no desea ocultar: C es perfectamente capaz de convertir implícitamente el void* Devolver valor a cualquier otro puntero.

Y, por supuesto, es probable que desee encapsular la creación de estos vectores para facilitar su manejo, como con:

 struct Vector { double *data; // no place for x and n in readable code :-) size_t size; }; struct Vector *newVector (size_t sz) { // Try to allocate vector structure. struct Vector *retVal = malloc (sizeof (struct Vector)); if (retVal == NULL) return NULL; // Try to allocate vector data, free structure if fail. retVal->data = malloc (sz * sizeof (double)); if (retVal->data == NULL) { free (retVal); return NULL; } // Set size and return. retVal->size = sz; return retVal; } void delVector (struct Vector *vector) { // Can safely assume vector is NULL or fully built. if (vector != NULL) { free (vector->data); free (vector); } } 

Al encapsular la creación de esta manera, se asegura de que los vectores estén totalmente construidos o no estén construidos en absoluto, no hay posibilidad de que estén a medio construir. También le permite cambiar totalmente las estructuras de datos subyacentes en el futuro sin afectar a los clientes (por ejemplo, si desea hacer que los arreglos dispersos cambien de espacio por velocidad).

La primera vez, asigna memoria para Vector , lo que significa que las variables x , n .

Sin embargo, x todavía no apunta a nada útil .

Por eso es que también se necesita una segunda asignación .

Pocos puntos

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); Está Mal

debe ser struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); ya que y mantiene puntero a struct Vector .

1st malloc() solo asigna memoria suficiente para mantener la estructura Vector (que es puntero a double + int)

2nd malloc() realidad asigna memoria para mantener 10 dobles.

En principio ya lo estás haciendo correctamente. Para lo que quieras necesitas dos malloc() s.

Solo algunos comentarios:

 struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); y->x = (double*)malloc(10*sizeof(double)); 

debiera ser

 struct Vector *y = malloc(sizeof *y); /* Note the pointer */ y->x = calloc(10, sizeof *y->x); 

En la primera línea, asigna memoria para un objeto Vector. malloc() devuelve un puntero a la memoria asignada, por lo que y debe ser un puntero vectorial. En la segunda línea, asigna memoria para una matriz de 10 dobles.

En C no necesita los conversos explícitos, y escribir sizeof *y lugar de sizeof(struct Vector) es mejor para la seguridad de tipos, y además, ahorra en escribir.

Puedes reorganizar tu estructura y hacer un solo malloc() así:

 struct Vector{ int n; double x[]; }; struct Vector *y = malloc(sizeof *y + 10 * sizeof(double)); 

Cuando asigna memoria para struct Vector , simplemente asigna memoria para el puntero x , es decir, para el espacio, donde se colocará su valor, que contiene la dirección. De este modo, no asigna memoria para el bloque, en el que yx hará referencia.

El primer malloc asigna memoria para la estructura, incluida la memoria para x (puntero a doble). El segundo malloc asigna memoria para el valor doble con puntos x.

En realidad, podría hacer esto en un solo malloc asignando el Vector y la matriz al mismo tiempo. P.ej:

 struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double)); y->x = (double*)((char*)y + sizeof(struct Vector)); y->n = 10; 

Esto asigna el Vector ‘y’, luego hace que y-> x apunte a los datos adicionales asignados inmediatamente después de la estructura del Vector (pero en el mismo bloque de memoria).

Si es necesario cambiar el tamaño del vector, debe hacerlo con las dos asignaciones como se recomienda. La matriz interna y-> x podría entonces redimensionarse manteniendo el vector struct ‘y’ intacto.