devolviendo una variable local de la función en C [duplicate]

4 minutos de lectura

avatar de usuario
Marca

#include <stdio.h>

int foo1(void)
{
    int p;
    p = 99;
    return p;
}

char *foo2(void)
{
    char buffer[] = "test_123";
    return buffer;
}

int *foo3(void)
{
    int t[3] = {1,2,3};
    return t;
}

int main(void)
{
    int *p;
    char *s;

    printf("foo1: %d\n", foo1());
    printf("foo2: %s\n", foo2());
    printf("foo3: %d, %d, %d\n", p[0], p[1], p[2]);
    return 0;
}

Cuando compilo esto con gcc -ansi -pedantic -W -Wall el compilador emite mensajes de advertencia para foo2() y foo3():

warning: function returns address of local variable

Pensé que no está permitido devolver una variable local, pero foo1() funciona bien y parece que hay una gran diferencia entre devolver el puntero a un objeto local y el objeto en sí.

¿Alguien podría arrojar algo de luz sobre este tema? ¡Gracias por adelantado!

avatar de usuario
kelloti

El problema aquí es que cuando crea la variable local, se asigna en la pila y, por lo tanto, no está disponible una vez que la función finaliza la ejecución (la implementación varía aquí). La forma preferible sería utilizar malloc() para reservar memoria no local. el peligro aquí es que tienes que desasignar (free()) todo lo que asignó usando malloc()y si lo olvida, crea una fuga de memoria.

  • Otro peligro es si no reinicia (p. ej. memset) la memoria asignada, puede perder información de la pila.

    – jweyrich

    21/08/2017 a las 17:00

  • @jweyrich Ahí es cuando calloc viene bien, con la asignación contigua, por supuesto.

    – talekeDskobeDa

    7 sep 2019 a las 18:50

  • @kelloti si declaro la variable local como estática y la devuelvo, ¿seguirá sin estar disponible?

    – Abdel Alem

    17 de noviembre de 2020 a las 12:52

  • @AbdelAleem En ese momento, está en el ámbito de vida estática, por lo que debería estar disponible.

    – kelloti

    17 de noviembre de 2020 a las 19:17

avatar de usuario
Leva

Para foo1()devuelves un dupdo de la variable local, no la variable local en sí.

Para las otras funciones, devuelve una copia de un puntero a una variable local. Sin embargo, esa variable local se desasigna cuando finaliza la función, por lo que termina con problemas desagradables si intenta hacer referencia a ella más tarde.

Cualquier variable tiene algo de espacio en la memoria. Un puntero hace referencia a ese espacio. El espacio que ocupan las variables locales se desasigna cuando regresa la llamada a la función, lo que significa que puede reutilizarse y se reutilizará para otras cosas. Como consecuencia, las referencias a ese espacio terminarán apuntando a algo completamente ajeno. Las matrices en C se implementan como punteros, por lo que esto termina aplicándose a ellos. Y las matrices constantes declaradas en una función también cuentan como locales.

Si desea usar una matriz u otro puntero más allá del alcance de la función en la que se crea, debe usar malloc para reservar el espacio para ello. El espacio reservado mediante malloc no se reasignará ni reutilizará hasta que se libere explícitamente llamando gratis.

  • +1. En la práctica, esto significa que debe asignar un valor de retorno en el montón en lugar de en la pila. Debe usar malloc o similar en las “matrices” que desea devolver. O mejor, tome un puntero a un búfer + longitud de búfer como parámetros.

    – stefan

    28 de enero de 2011 a las 2:48

  • @stefan: Sí, ese es un buen punto. He agregado más sugerencias sobre cómo resolver esto a la respuesta.

    –Keith Irwin

    28 de enero de 2011 a las 2:50

  • ‘Las matrices en C se implementan como punteros’ es una simplificación excesiva; es aceptable en el límite para el contexto, pero existen grandes diferencias entre matrices y punteros (así como muchas similitudes).

    –Jonathan Leffler

    28 de enero de 2011 a las 3:14

  • @Jonathan Leffler: No conozco ninguna diferencia. El sistema de tipos los trata de la misma manera y las referencias y desreferencias se compilan en el mismo ensamblado, ya sea una referencia de matriz o un puntero. Si tiene int *ip, entonces *ip e ip[0] son intercambiables. También lo son *(ip+1) e ip[1]. Puede ser algo que desconozco, pero ¿en qué se diferencian las matrices y los punteros en C?

    –Keith Irwin

    28 de enero de 2011 a las 19:32

  • Considerar: char *a = "a"; char b[] = "b"; char *c; char d[] = "d";. Puedes escribir: c = a; y c = b;pero no puedes escribir b = a; o b = d;que es una diferencia importante entre matrices y punteros.

    –Jonathan Leffler

    28 de enero de 2011 a las 20:45

Sí, está devolviendo una matriz, que en realidad es un puntero detrás de escena, a la dirección de la ubicación de memoria donde se almacena el contenido de la variable que ha inicializado. Por lo tanto, le advierte que podría no ser tan útil devolver tal resultado, cuando en realidad podría referirse a uno de los valores de la matriz.

¿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