Supongamos que quiero definir una estructura que represente la longitud del vector y sus valores como:
struct Vector{
double* x;
int n;
};
Ahora, suponga 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 debería asignar la memoria para x por separado.
y->x = (double*)malloc(10*sizeof(double));
Pero, parece que estoy asignando memoria para y-> x dos veces, una mientras asigna memoria para y y la otra mientras asigna memoria para y-> x, y parece una pérdida de memoria. Le agradecería mucho que me hiciera saber qué hace realmente el compilador y cuál sería la forma correcta de inicializar tanto y como y-> x.
Gracias por adelantado.
c
memory-management
Pouya
fuente
fuente
malloc()
en C. Nunca entenderé por qué todos sienten la necesidad de hacerlo. :(void *
no se convierte automáticamente a otros punteros, y la conversión es necesaria (o simplemente no se usamalloc()
en C ++, por supuesto).Respuestas:
No, estás no la asignación de memoria para
y->x
dos veces.En cambio, está asignando memoria para la estructura (que incluye un puntero) más algo para que apunte ese puntero.
Piénsalo de esta manera:
1 2 +-----+ +------+ y------>| x------>| *x | | n | +------+ +-----+
Entonces, realmente necesita las dos asignaciones (
1
y2
) para almacenar todo.Además, su tipo debe ser,
struct Vector *y
ya que es un puntero, y nunca debe convertir el valor de retornomalloc
en C, ya que puede ocultar ciertos problemas que no desea ocultar: C es perfectamente capaz de convertir implícitamente elvoid*
valor de retorno a cualquier otro puntero.Y, por supuesto, probablemente desee encapsular la creación de estos vectores para facilitar su gestión, 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 esa manera, se asegura de que los vectores estén completamente 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 arreglos dispersos para intercambiar espacio por velocidad).
fuente
La primera vez, se puede asignar memoria para
Vector
, lo que significa que las variablesx
,n
.Sin embargo
x
, todavía no apunta a nada útil .Por eso también se necesita una segunda asignación .
fuente
Pocos puntos
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
Está Maldebería ser
struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
ya quey
sostiene el puntero astruct Vector
.1st
malloc()
solo asigna memoria suficiente para contener la estructura vectorial (que es puntero a double + int)En segundo lugar,
malloc()
asigna memoria para contener 10 dobles.fuente
De hecho, 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 Vector 'y', luego hace que y-> x apunte a los datos extra asignados inmediatamente después de la estructura Vector (pero en el mismo bloque de memoria).
Si se requiere cambiar el tamaño del vector, debe hacerlo con las dos asignaciones como se recomienda. La matriz interna y-> x podría cambiarse de tamaño mientras se mantiene intacta la estructura vectorial 'y'.
fuente
En principio, ya lo estás haciendo bien. Para lo que quieres 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 las conversiones explícitas, y escribir en
sizeof *y
lugar desizeof(struct Vector)
es mejor para la seguridad de tipos y, además, ahorra en escribir.Puede reorganizar su estructura y hacer una sola
malloc()
así:struct Vector{ int n; double x[]; }; struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
fuente
if(NULL == foo)
sizeof *y
. Si lo hace solo por escribir 5 letras menos (tamaño de * y versus tamaño de (Vector)) sin otro argumento, entonces debe ser porque encuentra que la tarea de escribir 5 letras en su teclado es un gran obstáculo. Y si es así, entonces quizás considere otra opción de carrera, ya que la programación implica una gran cantidad de mecanografía en el teclado ...sizeof *y
te ayuda a combatir errores como escribirsizeof(Vector)
cuando quisistesizeof(Matrix)
. ¿Con qué frecuencia comete errores como esos? ¿Qué tan rápido los encuentra y los arregla cuando lo hace? Estoy de acuerdo en que aumenta la seguridad de los tipos y escribosizeof *y
en mi propio código, pero es casi tan paranoico como escribirif(NULL == foo)
para evitar errores tipográficos en el==
.y
es un puntero astruct Vector
sosizeof *y
es decir "tamaño de lo que apunta y", entoncessizeof struct Vector
.Cuando asigna memoria
struct Vector
, simplemente asigna memoria para el punterox
, es decir, para el espacio, donde se colocará su valor, que contiene la dirección. Entonces, de esa manera, no asigna memoria para el bloque, al quey.x
hará referencia.fuente
Primero malloc asigna memoria para la estructura, incluida la memoria para x (puntero a doble). El segundo malloc asigna memoria para el valor doble al que apunta x.
fuente
Cuando
malloc(sizeof(struct_name))
asigna memoria automáticamente para el tamaño completo de la estructura, no es necesario que mallocice cada elemento dentro.Utilice la
-fsanitize=address
bandera para comprobar cómo utilizó la memoria de su programa.fuente