Как получить доступ к локальной переменной из другой функции с помощью указателей?
Можно ли получить доступ к локальной переменной в другой функции? Если да, то как?
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()
, чтобы иметь доступ к нему больше, чем в первый раз?
Ответы
Ответ 1
myArray
- локальная переменная, и, таким образом, указатель действителен только до тех пор, пока не будет оставлен конец его области действия (которая в этом случае содержит функцию getArray
). Если вы позже получите доступ к нему, вы получите поведение undefined.
На практике происходит то, что вызов printf
перезаписывает часть стека, используемую myArray
, и затем содержит некоторые другие данные.
Чтобы исправить ваш код, вам нужно либо объявить массив в области действия, которая достаточно долго (функция main
в вашем примере), либо выделить ее в куче. Если вы выделите его в куче, вам нужно освободить его либо вручную, либо на С++ с помощью RAII.
Одна альтернатива, которую я пропустил (возможно, даже самая лучшая здесь, если массив не слишком большой) заключается в том, чтобы обернуть ваш массив в структуру и, таким образом, сделать его типом значения. Затем, возвращаясь, создается копия, которая выживает при возврате функции. Подробнее см. tp1 .
Ответ 2
Вы не можете получить доступ к локальной переменной, если она выходит из области видимости. Это то, что значит быть локальной переменной.
При обращении к массиву в функции replaceNumberAndPrint результат undefined. Тот факт, что он работает впервые, - это просто счастливое совпадение. Вероятно, место расположения памяти, на которое вы указываете, нераспределено в стеке и по-прежнему правильно настроено для первого вызова, но вызов printf затем перезаписывает его, вставляя значения в стек во время его работы, поэтому второй вызов printf отображает что-то отличается.
Вам нужно сохранить данные массива в куче и передать указатель или в переменную, которая остается в области видимости (например, глобальная или что-то в пределах основной функции).
Ответ 3
Попробуй что-нибудь подобное. То, как вы это делаете, "убивает" 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;
}
Ответ 4
myArray выходит из области действия, как только вы покидаете getArray. Вместо этого вам нужно выделить место для кучи.
Ответ 5
Ваш код вызывает Undefined Behavior, потому что myArray
выходит за пределы области действия, как только возвращается getArray()
, и любая попытка использования (разыменования) оборванного указателя - UB.
Ответ 6
Локальные переменные выходят из области действия по возврату, поэтому вы не можете вернуть указатель на локальную переменную.
Вам нужно выделить его динамически (в куче), используя 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
, прочитайте этот вопрос и ответ.
Ответ 7
Правильный способ сделать это выглядит следующим образом:
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 (array). C (и, следовательно, С++) пытается избежать копирования массива, и вам нужно, чтобы структура прошла мимо этого. Почему копирование необходимо из-за областей - область функций get_array() исчезает, и все значения, все еще необходимые из этой области, должны быть скопированы для вызова области.
Ответ 8
В этом коде вы использовали указатель на локальные объекты, но когда функция возвращает все локальные переменные, выходит за рамки. Если вы выделите память (используя функцию 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;
}
Этот код напечатает все элементы массива и не будет перезаписан.
Ответ 9
Решение С++:
"Могу ли я получить доступ к локальной переменной в другой функции? Если да, то как?"
Ответ - нет, не после того, как функция закончилась. Локальные переменные уничтожаются в этой точке.
В C++
способ обращения с возвращаемыми массивами - управлять ими в контейнере, как std:: array (фиксированный размер ) или std::vector (динамический размер).
Например:
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;
}
Во второй функции возвращаемое значение оптимизируется компилятором, поэтому вы не платите цену фактического копирования массива.