Как получить доступ к локальной переменной из другой функции, используя указатели? - PullRequest
48 голосов
/ 31 декабря 2010

Могу ли я получить доступ к локальной переменной в другой функции? Если да, то как?

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());
}

Вывод приведенного выше кода:

65
4202656

Что я делаю не так? Что означает «4202656»?

Нужно ли копировать весь массив в функции replaceNumberAndPrint(), чтобы иметь к нему доступ чаще, чем в первый раз?

Ответы [ 9 ]

56 голосов
/ 31 декабря 2010

myArray - локальная переменная, и, таким образом, указатель действителен только до конца своей области видимости (которая в данном случае содержит содержащую функцию getArray).Если вы обратитесь к нему позже, вы получите неопределенное поведение.

На практике происходит то, что вызов printf перезаписывает часть стека, используемую myArray, и затем содержит некоторые другие данные.

Чтобы исправить ваш код, вам нужно либо объявить массив в области, которая живет достаточно долго (функция main в вашем примере), либо разместить его в куче.Если вы размещаете его в куче, вам нужно освободить его либо вручную, либо в C ++, используя RAII.

Одна из пропущенных мной альтернатив (возможно, даже лучшая здесь, при условии, что массив не слишком большой) заключается в переносеВаш массив в структуру и, следовательно, сделать его типом значения.Затем при возврате создается копия, которая сохраняется после возврата из функции.См. tp1 's ответ для подробностей об этом.

18 голосов
/ 31 декабря 2010

Вы не можете получить доступ к локальной переменной, когда она выходит из области видимости.Вот что значит быть локальной переменной.

Когда вы обращаетесь к массиву в функции replaceNumberAndPrint, результат не определен.Тот факт, что он работает впервые, - просто счастливое совпадение.Возможно, область памяти, на которую вы указываете, не выделена в стеке и все еще правильно установлена ​​для первого вызова, но вызов printf затем перезаписывает это, помещая значения в стек во время своей работы, поэтому второй вызов printf отображаетразные.

Вам необходимо сохранить данные массива в куче и передать указатель или переменную, которая остается в области видимости (например, глобальная или что-то в рамках основной функции).

8 голосов
/ 31 декабря 2010

Попробуйте что-нибудь подобное. То, как вы это делаете, "убивает" myArray причину, если она определена локально.

#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());
}

Подробнее: http://www.cplusplus.com/reference/clibrary/cstdlib/malloc/

Редактировать: Как правильно указали в комментариях: лучший способ сделать это:

#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;
}
2 голосов
/ 03 января 2011

Правильный способ сделать это следующим образом:

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;
}

Чтобы понять, зачем вам это нужно, вам нужно знать, как работает sizeof (массив).C (и, следовательно, c ++) старается избежать копирования массива, и вам нужна структура, чтобы пройти мимо этого.Почему копирование необходимо из-за областей видимости - область действия функции get_array () исчезает, и все значения, все еще необходимые из этой области, необходимо будет скопировать в вызывающую область.

2 голосов
/ 31 декабря 2010

Локальные переменные выходят из области видимости по возвращении, поэтому вы не можете вернуть указатель на локальную переменную.

Вам нужно выделить его динамически (в куче), используя malloc или new. Пример:

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;
 }

В качестве альтернативы, вы можете объявить массив как статический, помня семантику. Пример:

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;
 }

Если вы не знаете, что означает static, прочитайте этот вопрос и ответ .

2 голосов
/ 31 декабря 2010

Ваш код вызывает неопределенное поведение, потому что myArray выходит из области видимости, как только возвращается getArray(), и при любой попытке использовать (разыменование) висячий указатель - UB.

2 голосов
/ 31 декабря 2010

myArray выходит из области видимости, как только вы покидаете getArray. Вместо этого вам нужно выделить для него место в куче.

1 голос
/ 20 марта 2016

C ++ решение:

«Могу ли я получить доступ к локальной переменной в другой функции? Если да, то как?»

Ответ - нет, не после завершения функции. Локальные переменные уничтожаются в этот момент.

В C++ способ обработки возвращаемых массивов заключается в управлении ими в контейнере , например std :: array (фиксированный размер) или std: : вектор (динамический размер).

Например:

void replaceNumberAndPrint(const std::array<int, 3>& array) {
    printf("%i\n", array[0]);
    printf("%i\n", array[1]);
    printf("%i\n", array[2]);
}

std::array<int, 3> getArray() {
    std::array<int, 3> myArray = {4, 65, 23};
    return myArray;
}

Во второй функции возвращаемое значение оптимизируется компилятором, поэтому вы не платите цену за фактическое копирование массива.

0 голосов
/ 07 января 2014

В этом коде вы использовали указатель на локальные объекты, но когда функция возвращает все локальные переменные, выходит из области видимости.Если вы выделите память (используя функцию malloc() для выделения), то никакие данные не будут потеряны или перезаписаны.

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

int main() {
    int i;
    int *vector = getArray(3);
    for(i=0;i<3;i++)
    {
        printf("%i\n",vector[i]);
    }
    getch();
    return 0;
}

Этот код напечатает все элементы массива, и перезапись не произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...