¿Cómo acceder a una variable local desde una función diferente usando punteros?

7 minutos de lectura

¿Como acceder a una variable local desde una funcion diferente
Radek Simko

¿Puedo tener acceso a una variable local en una función diferente? ¿Si es así, cómo?

void replaceNumberAndPrint(int array[3]) {
    printf("%i\n", array[1]);
    printf("%i\n", array[1]);
}

int * getArray() {
    int myArray[3] = {4, 65, 23};
    return myArray;
}

int main() {
    replaceNumberAndPrint(getArray());
}

La salida del fragmento de código anterior:

65
4202656

¿Qué estoy haciendo mal? ¿Qué significa el “4202656”?

¿Tengo que copiar toda la matriz en el replaceNumberAndPrint() función para poder acceder a ella más que la primera vez?

  • Es difícil saber cuál es la mejor sugerencia para su intención, aquí. Pero es posible que desee leer sobre punteros compartidos (shared_ptr y amigos). Proporcionan algunas de las buenas propiedades de los lenguajes recolectados en la basura al hacer el conteo de referencias. Pero diferente, así que ten cuidado.

    – HostileFork dice que no confíes en SE

    31 de diciembre de 2010 a las 13:59

  • Voto para reabrir esto y usarlo como un duplicado canónico para preguntas de la naturaleza “Estoy teniendo un bloqueo cuando devuelvo un puntero a la variable local, ¿por qué?”, ​​En lugar de ese otro duplicado canónico clásico que es más bien para ” No me voy a estrellar, ¿por qué no?”.

    – Lundin

    14 de enero de 2016 a las 11:09


  • @Lundin es un poco problemático que esto tenga tanto C como C++.

    – Antti Haapala — Слава Україні

    6 de noviembre de 2018 a las 16:02

  • @AnttiHaapala No hay nada exclusivo de C ++ en la pregunta, pero desafortunadamente hay respuestas de C ++, por lo que la etiqueta debe permanecer.

    – Lundin

    6 de noviembre de 2018 a las 16:34

  • Si se usa en un sistema integrado, la asignación dinámica de memoria es peligrosa, por lo que hay 3 posibilidades, hacer que la variable sea global, hacerla estática o pasar un puntero a la variable desde la rutina de llamada.

    – usuario1582568

    16 de marzo de 2021 a las 7:45

¿Como acceder a una variable local desde una funcion diferente
CodesInChaos

myArray es una variable local y, por lo tanto, el puntero solo es válido hasta el final de su alcance (que en este caso es la función contenedora getArray) es izquierda. Si accede a él más tarde, obtiene un comportamiento indefinido.

En la práctica lo que sucede es que la llamada a printf sobrescribe la parte de la pila utilizada por myArray y luego contiene algunos otros datos.

Para corregir su código, debe declarar la matriz en un ámbito que dure lo suficiente (el main función en su ejemplo) o asignarlo en el montón. Si lo asigna en el montón, debe liberarlo manualmente o en C++ usando RAII.

Una alternativa que me perdí (probablemente incluso la mejor aquí, siempre que la matriz no sea demasiado grande) es envolver su matriz en una estructura y, por lo tanto, convertirla en un tipo de valor. Luego, devolverlo crea una copia que sobrevive al retorno de la función. Consulte la respuesta de tp1 para obtener detalles sobre esto.

  • O podrías declararlo estático.

    – Oystein

    31 de diciembre de 2010 a las 13:47

  • Hacerlo estático tiene una semántica bastante diferente, especialmente en aplicaciones de subprocesos múltiples, a menos que el contenido de la matriz sea constante.

    – CodesInChaos

    31 de diciembre de 2010 a las 13:51

  • Claro, pero es una forma de resolver el problema y debe señalarse, ¿verdad?

    – Oystein

    31 de diciembre de 2010 a las 13:57

  • Señalarlo es, por supuesto, útil, pero también debe señalar las desventajas, por lo que su primer comentario fue un poco incompleto.

    – CodesInChaos

    31 de diciembre de 2010 a las 14:29

  • yo diria recomendando static como solución a este problema es perjudicial y nunca útil. Para los novatos, se convierte en una curita formulativa en lugar de comprender realmente el problema y escribir el código correcto, y más tarde, cuando alguien más herede el código del novato, se horrorizará con todas las variables estáticas sin sentido por todas partes.

    – R.. GitHub DEJA DE AYUDAR A ICE

    31 de diciembre de 2010 a las 19:44

1647655809 70 ¿Como acceder a una variable local desde una funcion diferente
james gaunt

No puede acceder a una variable local una vez que está fuera del alcance. Esto es lo que significa ser una variable local.

Cuando está accediendo a la matriz en el replaceNumberAndPrint función el resultado es indefinido. El hecho de que parezca funcionar la primera vez es solo una afortunada coincidencia. Probablemente la ubicación de memoria a la que está apuntando no está asignada en la pila y aún está configurada correctamente para la primera llamada, pero la llamada a printf luego sobrescribe esto empujando valores en la pila durante su operación, razón por la cual la segunda llamada a printf muestra algo diferente.

Debe almacenar los datos de la matriz en el montón y pasar un puntero, o en una variable que permanece en el alcance (por ejemplo, un alcance global o algo dentro de la función principal).

Prueba algo así. La forma en que lo haces “mata” myArray causa si se define localmente.

#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
 printf("%i\n", array[0]);
 printf("%i\n", array[1]);
 printf("%i\n" , array[2]);
 free(array);
}

int * getArray() {
 int * myArray = malloc(sizeof(int) * 3);
 myArray[0] = 4;
 myArray[1] = 64;
 myArray[2] = 23;
 //{4, 65, 23};
 return myArray;
}

int main() {
 replaceNumberAndPrint(getArray());
}

Más : http://www.cplusplus.com/reference/clibrary/cstdlib/malloc/

Editar: Como los comentarios señalaron correctamente: una mejor manera de hacerlo sería que:

#include <stdio.h>
#include <stdlib.h>

void replaceNumberAndPrint(int * array) {
    if(!array)
        return;

    printf("%i\n", array[0]);
    printf("%i\n", array[1]);
    printf("%i\n" , array[2]);
}

int * createArray() {
    int * myArray = malloc(sizeof(int) * 3);

    if(!myArray)
        return 0;

    myArray[0] = 4;
    myArray[1] = 64;
    myArray[2] = 23;
    return myArray;
}

int main() {
    int * array = createArray();
    if(array)
    {
        replaceNumberAndPrint(array);
        free(array);
    }
    return 0;
}

  • Asegúrese de comentar esta “característica” MUY bien si la usa en su código. ¡Asignar memoria por una función y liberarla por otra es MUY peligroso a menos que esté debidamente documentado e incluso entonces es propenso a pérdidas de memoria! Sería mejor asignar la matriz en main y suéltelo cuando ya no sea necesario.

    – Shaihi

    31 de diciembre de 2010 a las 13:40


  • @Shaihi, esto es cierto, también este fragmento de código es muy ingenuo porque no verifica si malloc() asignado con éxito. Pero creo que OP entenderá todo el punto.

    usuario418748

    31 de diciembre de 2010 a las 13:42


  • Si bien esto funciona, es feo. Deberías cambiar los nombres de las funciones (getArray => createArray) para describir mejor su comportamiento. y teniendo replaceNumberAndPrint eliminar la matriz de origen no me parece una buena idea. Prefiero separar la eliminación y la impresión en dos funciones diferentes.

    – CodesInChaos

    31 de diciembre de 2010 a las 13:42


  • Se agregó una versión más “Correcta”.

    usuario418748

    31 de diciembre de 2010 a las 13:48

  • @Muggen: no prefieres array[i] en lugar de *(array+i)?

    – jweyrich

    31 de diciembre de 2010 a las 13:50

myArray queda fuera del alcance tan pronto como sale de getArray. En su lugar, debe asignar espacio para ello en el montón.

Su código invoca un comportamiento indefinido porque myArray sale del alcance tan pronto como getArray() devoluciones y cualquier intento de utilizar (desreferenciar) el puntero colgante es UB.

1647655810 447 ¿Como acceder a una variable local desde una funcion diferente
Comunidad

Las variables locales quedan fuera del alcance al regresar, por lo que no puede devolver un puntero a una variable local.

Debe asignarlo dinámicamente (en el montón), usando malloc o new. Ejemplo:

int *create_array(void) {
    int *array = malloc(3 * sizeof(int));
    assert(array != NULL);
    array[0] = 4;
    array[1] = 65;
    array[2] = 23;
    return array;
 }
 void destroy_array(int *array) {
     free(array);
 }
 int main(int argc, char **argv) {
     int *array = create_array();
     for (size_t i = 0; i < 3; ++i)
         printf("%d\n", array[i]);
     destroy_array(array);
     return 0;
 }

Alternativamente, puede declarar la matriz como estática, teniendo en cuenta que la semántica es diferente. Ejemplo:

int *get_array(void) {
    static int array[] = { 4, 65, 23 };
    return array;
 }
 int main(int argc, char **argv) {
     int *array = get_array();
     for (size_t i = 0; i < 3; ++i)
         printf("%d\n", array[i]);
     return 0;
 }

si no sabes que static significa, lea esta pregunta y respuesta.

1647655810 458 ¿Como acceder a una variable local desde una funcion diferente
tp1

La forma correcta de hacerlo es la siguiente:

struct Arr {
   int array[3];
};
Arr get_array() {
   Arr a;
   a.array[0] = 4;
   a.array[1] = 65;
   a.array[2] = 23;
   return a;
}
int main(int argc, char **argv) {
   Arr a = get_array();
   for(size_t i=0; i<3; i++)
       printf("%d\n", a.array[i]);
   return 0;
}

Para entender por qué necesita hacer esto, necesita saber cómo funciona sizeof(array). C (y, por lo tanto, c ++) se esfuerza por evitar copiar la matriz, y necesita que la estructura supere eso. La razón por la que se necesita copiar es por los ámbitos: el ámbito de la función get_array() desaparece y todos los valores que aún se necesitan de ese ámbito deberán copiarse en el ámbito de llamada.

  • Sé que esto fue hace bastante tiempo, pero ¿no necesitarías typedef o asignar la estructura como struct Arr a?

    – sherrellbc

    2 oct 2013 a las 16:07

  • @sherrellbc En C, sí. En C++ struct Foo { ... }; define automáticamente los tipos struct Foo y Foono typedef necesario.

    – melpomene

    13 de septiembre de 2018 a las 6:05

¿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