El acceso dinámico a la memoria solo funciona dentro de la función
malloc parameter-passing (1)
La razón de este error es que los
data
utilizados por la función
create_array
son una variable local que solo existe dentro de esa función.
La dirección de memoria asignada obtenida de
malloc
solo se almacena en esta variable local y nunca se devuelve a la persona que llama.
Considere este simple ejemplo:
void func (int x)
{
x = 1;
printf("%d", x);
}
...
int a;
func(a);
printf("%d", a); // bad, undefined behavior - the program might crash or print garbage
Aquí, una
copia
de la variable
a
se almacena localmente dentro de la función, como el parámetro
x
.
Esto se conoce como
paso por valor
.
Cuando
x
se modifica, solo se modifica esa variable local.
La variable
a
en la persona que llama permanece sin cambios, y dado que
a
no se inicializa, contendrá "basura" y no se puede usar de manera confiable.
Los punteros no son una excepción a esta regla de paso por valor.
En su ejemplo, los
data
variables del puntero se pasan por valor a la función.
El puntero de
data
dentro de la función es una copia local y la dirección asignada de
malloc
nunca se devuelve a la persona que llama.
Por lo tanto, la variable de puntero en la persona que llama permanece sin inicializar y, por lo tanto, el programa se bloquea.
Además, la función
create_array
también ha creado una
pérdida de memoria
, ya que después de la ejecución de esa función, ya no hay ningún puntero en el programa que realice un seguimiento de ese fragmento de memoria asignada.
Hay dos formas de modificar la función para que funcione como se espera. Ya sea devolviendo una copia de la variable local a la persona que llama:
int* create_array (int size)
{
int* data = malloc(sizeof(*data) * size);
for(int i=0; i<size; i++)
{
data[i] = i;
}
print_array(data, size);
return data;
}
int main (void)
{
int* data;
const int size = 5;
data = create_array(size);
print_array(data, size);
}
o pasando la dirección a la variable de puntero de la persona que llama y escribe directamente a la variable de la persona que llama:
void create_array (int** data, int size)
{
int* tmp = malloc(sizeof(*tmp) * size);
for(int i=0; i<size; i++)
{
tmp[i] = i;
}
*data = tmp;
print_array(*data, size);
}
int main (void)
{
int* data;
const int size = 5;
create_array(&data, size);
print_array(data, size);
}
Cualquiera de las formas está bien.
Esta pregunta está destinada a ser utilizada como un duplicado canónico para estas preguntas frecuentes:
Estoy asignando datos dinámicamente dentro de una función y todo funciona bien, pero solo dentro de la función donde tiene lugar la asignación. Cuando intento usar los mismos datos fuera de la función, me cuelgo u otro comportamiento inesperado del programa.
Aquí hay un MCVE:
#include <stdlib.h>
#include <stdio.h>
void create_array (int* data, int size)
{
data = malloc(sizeof(*data) * size);
for(int i=0; i<size; i++)
{
data[i] = i;
}
print_array(data, size);
}
void print_array (int* data, int size)
{
for(int i=0; i<size; i++)
{
printf("%d ", data[i]);
}
printf("/n");
}
int main (void)
{
int* data;
const int size = 5;
create_array(data, size);
print_array(data, size); // crash here
free(data);
}
Cada
print_array
se llama a
print_array
desde dentro de la función
create_array
, obtengo el resultado esperado
0 1 2 3 4
, pero cuando lo llamo desde
main
, obtengo un bloqueo del programa.
¿Cuál es la razón para esto?