Как получить доступ к локальной переменной из другой функции с помощью указателей?
могу ли я иметь доступ к локальной переменной в другой функции? Если да, то как?
void replaceNumberAndPrint(int array[3]) {
printf("%in", array[1]);
printf("%in", array[1]);
}
int * getArray() {
int myArray[3] = {4, 65, 23};
return myArray;
}
int main() {
replaceNumberAndPrint(getArray());
}
вывод части кода выше:
65
4202656
что я делаю не так? Что означает "4202656"?
мне нужно скопировать весь массив в replaceNumberAndPrint()
функция, чтобы иметь возможность получить к нему доступ больше, чем в первый раз?
9 ответов
myArray
является локальной переменной, и, таким образом, указатель действителен только до конца его области (которая в этом случае содержит функцию getArray
) осталось. Если вы получите доступ к нему позже, вы получите неопределенное поведение.
на практике происходит то, что вызов printf
перезаписывает часть стека, используемого myArray
и затем содержит некоторые другие данные.
чтобы исправить ваш код, вам нужно либо объявить массив в области, которая живет достаточно долго (main
функция в вашем примере) или выделите ее в куче. Если вы выделяете его в куче, вам нужно освободить его вручную или в C++ с помощью RAII.
одна альтернатива, которую я пропустил (возможно, даже лучшая здесь, если массив не слишком большой), - это обернуть массив в структуру и, таким образом, сделать его типом значения. Затем, возвращая его, создается копия, которая переживает функцию return. См.tp1 ' s ответ для получения дополнительной информации.
вы не можете получить доступ к локальной переменной, как только она выходит за рамки. Вот что значит быть локальной переменной.
при доступе к массиву в функции replaceNumberAndPrint результат не определен. Тот факт, что это работает в первый раз, - просто счастливое совпадение. Вероятно, место памяти, на которое вы указываете, нераспределено в стеке и все еще правильно установлено для первого вызова, но вызов printf затем перезаписывает это, нажимая значения на стек во время его работы, поэтому второй вызов printf отображает что-то другое.
вам нужно сохранить данные массива в куче и передать указатель или переменную, которая остается в области видимости (например, глобальная или что-то в области основной функции).
попробуйте что-то вроде этого. То, как вы это делаете, "убивает" 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/
Edit: Как правильно указали комментарии: лучший способ сделать это было бы так:
#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;
}
myArray выходит из поля зрения, как только вы покидаете getArray. Вместо этого вам нужно выделить место для него в куче.
ваш код вызывает неопределенное поведение, потому что myArray
выходит из области видимости, как только getArray()
возвращает и любая попытка использовать (разыменование) болтающийся указатель-UB.
локальные переменные выходят из области видимости при возврате, поэтому вы не можете вернуть указатель на локальную переменную.
вам нужно выделить его динамически (в куче), используя 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
значит, читать этот вопрос и ответ.
правильный способ сделать это следующим образом:
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 (и, следовательно, c++) изо всех сил пытается избежать копирования массива, и вам нужна структура, чтобы пройти мимо этого. Почему копирование необходимо из-за областей-область функции get_array() исчезает, и каждое значение, все еще необходимое из этой области, нужно будет скопировать в вызывающую область.
в этом коде вы использовали указатель на локальные объекты, но когда функция возвращает все локальные переменные выходит из области видимости. Если вы выделите память (используя 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;
}
этот код напечатает все элементы массива, и перезапись не произойдет.
В C++ решение:
"могу ли я иметь доступ к локальной переменной в другой функции? Если да, то как?"
ответ-Нет, не после того, как функция закончилась. В этот момент локальные переменные уничтожаются.
на 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;
}
во второй функции возвращаемое значение оптимизируется компилятором, поэтому вы не платите цену фактического копирования массива.