двойной указатель против одного указателя

Может ли кто-нибудь объяснить / дать мне аргумент в пользу того, почему значение переменной i в основной функции в ниже fragmentе кода не изменяется через функцию test1, пока оно меняет через test2? Я думаю, что одного указателя должно быть достаточно, чтобы изменить значение i. Почему мы должны использовать двойной указатель?

#include  void test1(int* pp) { int myVar = 9999; pp = &myVar; } void test2(int** pp) { int myVar = 9999; *pp = &myVar; } int main() { printf("Hej\n"); int i=1234; int* p1; p1 = &i; test1(p1); printf("does not change..., p1=%d\n",*p1); test2(&p1); printf("changes..., p1=%d\n",*p1); return 0; } 

В параметрах C передается значение. Это означает, что в test1 когда вы передаете pp копия делается из указателя, и когда вы меняете ее, изменение делается на копию, а не на указатель. С test2 копия имеет двойной указатель, но когда вы разыскиваете и назначаете здесь

 *pp = &myVar; 

вы меняете то, на что указываете, а не меняете самих себя. Обратите внимание, что это поведение в test2 не определено, как test2 в некоторых других ответах здесь

Если вы хотите изменить значение переменной типа T вы должны использовать указатель на этот тип ( T* ). Поскольку вы хотите изменить указатель ( T = int* ), вы должны указать указатель на указатель ( T* = int** ), иначе вы только собираетесь изменить копию.

Обратите внимание, что

 int myVar = 9999; *pp = &myVar; 

приведет к неопределенному поведению, поскольку pp теперь будет содержать адрес локальной переменной, который недействителен после выхода из функции.

Но вы не меняете значение i , вы меняете адрес, на который указывает pp , если вы хотите изменить значение i то этого достаточно, чтобы изменить ваш тест на:

 void test3(int* pp) { int myVar = 9999; *pp = myVar; } 

Поскольку f(x) не может изменить значение x , независимо от того, является ли x int, float или указателем.

 void test1(int* pp) { int myVar = 9999; pp = &myVar; } 

Эта функция передается указателем pp . Функция изменяет этот указатель. Но поскольку параметры передаются по значению, эта модификация не отображается вызывающим.

Вам нужно написать функцию следующим образом:

 void test1(int* pp) { *pp = 9999; } 

Ожидается, что вызывающая сторона этой функции передаст адрес переменной int . Затем функция записывает значение int , 9999 в этом случае, на этот адрес. Это ключ. Вам передается адрес, и вы затем записываете значение на этот адрес. Ваша сломанная версия просто изменила адрес. Вам не хватало косвенности.

Когда функция возвращается, вызывающий может наблюдать модификацию переменной int , адрес которой был передан функции. Код вызова может выглядеть так:

 int i = 0; test1(&i); // pass address of int variable printf("%d\n", i); // prints the new value, 9999 

 void test2(int** pp) { int myVar = 9999; *pp = &myVar; } 

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

pp = &myVar; присваивает адрес myVar указателю pp . Если вы хотите изменить значение, на которое указывает pp , используйте

 *pp = myVar; 

вместо.

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

 int* p1; p1 = &i; test1(p1); //1st test2(&p1); //2nd 

Простым способом: 1-й pass by value а второй – pass by address .

Описание :

В первом случае передающий указатель фактически является копией этого p внутри test1 поэтому pp внутри test1 является локальным для этой функции и создается в test1 . Вы назначили адрес, и когда он выходит из функции, он уничтожается.

Но во втором случае вы передаете адрес указателя на функцию test2 . Таким образом, указатель pp в test2 указывает на указатель p в main, поэтому присвоение нового адреса pp используя *pp = &myVar , автоматически установит значение p (поскольку вы разыскиваете указатель). Следовательно, когда test2 заканчивается, p будет указывать на измененное местоположение.