Указатели C локальны в функциях

#c #pointers

#c #указатели

Вопрос:

Это фрагмент кода, который я создал в целях изучения C , в настоящее время я пытаюсь обучить себя. Мой вопрос в том:

Почему *ptr = 30 изменяются выходные значения двух последних инструкций cout в моем main? (результат равен 30, 30, 30). Следовательно, почему int y = 30; и ptr = amp;y; не изменяют выходные данные в моем main и остаются локальными для функции? (если я закомментирую *ptr = 30, а не два предыдущих оператора, результат будет 30, 5, 5)

Если я изменю ввод функции на void printPointer(int *amp;fptr) — и закомментирую только *ptr = 30 — тогда *ptr в моем main будут изменены, но не x. Я понимаю это, поскольку передача по ссылке изменяет указатель, но не так, как мой первый оператор изменяет * ptr и x в моем main.

 #include <iostream>

using namespace std;

void printPointer(int *fptr);

int main()
{
    int x = 5;

    int *ptr = amp;x;

    printPointer(ptr);

    cout << *ptr << endl;
    cout << x << endl;

    return 0;
}

void printPointer(int *fptr)
{

//  int y = 30;             // this does not change the output of the last two couts in main, output = 30, 5, 5
 // fptr = amp;y;

    *fptr = 30;          // uncommenting this and commenting out the former two statements: output = 30, 30, 30

    cout <<  *fptr << endl;
}
  

Ответ №1:

*ptr = 30 изменяет значение того, на что указывается. В вашем случае вы установили ptr значение указывать на x (когда вы это сделали ptr = amp;x , а затем передали это в качестве аргумента printPointer() ). Таким образом, значение x изменено.

Когда вы вместо этого делаете int y = 30; fptr = amp;y; , все, что вы делаете, это изменяете fptr , чтобы указывать на другую переменную. Вот и все. Вы не меняете значение того, на что указывается (т.Е. значение x ). И вы не влияете ptr , потому что fptr это отдельная локальная переменная. Таким образом, ptr все еще указывает на x , и x по-прежнему равно 5.

Когда вы изменяете свою функцию, чтобы принимать указатель по ссылке, то изменение fptr на point at y также меняется ptr , потому что это одна и та же переменная.

Комментарии:

1. Поэтому, когда я делаю *fptr = 30, я изменяю фактическое значение, хранящееся в адресе памяти fptr, который также является тем же адресом памяти, где расположены x и ptr, таким образом изменяя их в будущих выводах. Однако int y = 30; и ftpr = amp;y являются локальными для функции и исчезают после завершения вызова функции.

2. @Antonious: Если быть педантичным, когда вы это делаете *fptr = 30 , вы изменяете значение, хранящееся по адресу, на который указывает fptr , который является тем же адресом, на который указывает ptr , и который является фактическим адресом x .

Ответ №2:

*fptr = 30 разыменовал бы адрес, хранящийся в fptr , и записал бы 30 в позицию в памяти. этот адрес в памяти вы передали функции с помощью printPointer(ptr) . ptr в данном случае это был адрес x, который вы присвоили ptr с помощью ptr = amp;x .

int y= y объявляет переменную, локальную для функции. fptr = amp;y присваивает адрес y fptr (и перезаписывает значение из ptr). таким образом, последняя строка в этом случае изменила бы локальную переменную y вместо x.

Ответ №3:

Если я правильно понимаю, вы спрашиваете о двух фрагментах кода. Первый — это то, что вы опубликовали:

 #include <iostream>

using std::cout;

void f(int* fptr) {
    *fptr = 30;  // 11
    cout << "*fptr = " << *fptr << 'n'; // 12
}

int main() {
    int x = 5; // 1
    int* ptr = amp;x; // 2
    f(ptr); // 21
    cout << "*ptr = " << *ptr << 'n'; // 22
    cout << "x = " << x << 'n'; // 23
}
  

В этом случае указатель всегда указывает на x, и в функции вы все равно изменяете значение x, поскольку именно на это указывает fptr. Если это поможет, вот демонстрация значения переменных в конце каждой строки: NE означает, что переменная в данный момент не существует.

 1.  x = 5, ptr = NE, fptr = NE
2.  x = 5, ptr = amp;x, fptr = NE
11. x = 30, ptr = amp;x, fptr = amp;x
12. x = 30, ptr = amp;x, fptr = amp;x
21. x = 30, ptr = amp;x, fptr = NE
  

После этого значения не изменяются, и все три оператора будут печатать 30.

Второй из них:

 #include <iostream>

using std::cout;

void f(int*amp; fptr) {
    int y = 30; // 11
    fptr = amp;y; // 12
    cout << "*fptr = " << *fptr << 'n'; // 13
}

int main() {
    int x = 5; // 1
    int* ptr = amp;x; // 2
    f(ptr); // 21
    cout << "*ptr = " << *ptr << 'n'; // 22
    cout << "x = " << x << 'n'; // 23
}
  

В первом случае указатель передается по ссылке, и он указывает на y . Фактически, в этом случае строка 21 предполагает неопределенное поведение, поскольку y больше не существует. Опять же, построчный анализ:

 1.  x = 5, y = NE, ptr = NE, fptr == NE
2.  x = 5, y = NE, ptr = amp;x, fptr == NE
11. x = 5, y = 30, ptr = amp;x, fptr == ptr
12. x = 5, y = 30, ptr = amp;y, fptr == ptr
13. x = 5, y = 30, ptr = amp;y, fptr == ptr
21. x = 5, y = NE, ptr = amp;y, fptr == NE
  

После этого значения снова не меняются: однако в строке 22 вы пытаетесь получить адрес ptr . Как вы можете видеть, *ptr = y = NE , и, следовательно, поведение не определено. Вывод может быть любым.

(Еще одно замечание заключается в том, что вам следует избегать, using namespace std; поскольку это может привести к конфликтам имен; используйте using std::cout; и аналогичные, как в приведенном выше коде.)