El acceso a la memoria dinámica solo funciona dentro de la función

4 minutos de lectura

Esta pregunta está destinada a ser utilizada como un duplicado canónico para esta pregunta frecuente:

Estoy asignando datos dinámicamente dentro de una función y todo funciona bien, pero solo dentro de la función donde se realiza la asignación. Cuando intento usar los mismos datos fuera de la función, se bloquea 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);
}

En cualquier momento print_array se llama desde dentro del create_array función, obtengo el resultado esperado 0 1 2 3 4pero cuando lo llamo desde mainme falla el programa.

¿Cuál es la razón para esto?

  • Casi te voté negativo por cometer un error tan estúpido 🙂

    – Jean-François Fabre

    14 de septiembre de 2016 a las 9:25

  • @Jean-FrançoisFabre Desafortunadamente, no he encontrado una manera de hacer que la pregunta sea una wiki comunitaria, solo la respuesta. He pinchado las modificaciones, así que espero que pronto se convierta en wiki de la comunidad.

    – Lundin

    14 de septiembre de 2016 a las 9:27

  • Creo que puede estar mejor alojado en la Documentación Beta.

    – LP

    14 de septiembre de 2016 a las 9:27

  • @RestlessC0bra Falsos positivos = errores de herramienta = herramienta rota. VS2015 es un compilador de C++. En modo C, está muy roto y todo el mundo lo sabe. No cumple con el estándar C, ni con el estándar C anterior de 1999, ni con el antiguo estándar C90/ANSI. También es bien sabido quejarse del código C perfectamente correcto, ya que Microsoft cree que solo ellos deberían tener la autoridad para dictar qué características del lenguaje son buenas y malas, en lugar del comité estándar de C.

    – Lundin

    17 de marzo de 2017 a las 12:06

  • @Lundin ¡Te daría una recompensa por tu comentario si pudiera!

    – Matthieu

    17 mayo 2019 a las 23:12

La razón de este error es que el data utilizado por el create_array función es 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 ejemplo simple:

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í un dupdo 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 cambia 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 utilizar de forma fiable.


Los punteros no son una excepción a esta regla de paso por valor. En su ejemplo, la variable de puntero data se pasa por valor a la función. Él data puntero dentro de la función es una copia local y la dirección asignada de malloc nunca se devuelve a la persona que llama.

Entonces, la variable de puntero en la persona que llama permanece sin inicializar y, por lo tanto, el programa falla. además, el create_array función también ha creado un pérdida de memoriaya 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 esa parte de la 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 escribiendo directamente en 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);
}

Cualquier forma está bien.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad