Так как функция example
возвращает тип void
, чтобы она работала на temp
и эти изменения были замечены в вызывающей программе, она ожидает, что адрес является указателем, поэтому может разыменовать двойной указатель и работа на *temp
в пределах example
. Когда вы объявляете int **x;
, вы передаете x
по значению, которое неинициализировано и если затем разыменовывается в example
, вероятно, приводит к SegFault.
Однако, когда вы объявляете int *x;
и затем передаете адрес x
до example
(например, example (&x)
, затем в example
разыменование *x
(например, *temp
) обеспечивает исходный адрес x
обратно в функцию вызова, позволяя вам работать на *temp
в пределах example
точно так же, как вы работали бы с x
в вызывающей функции.
Это примерно такой конкретный пример, который я могу привести на основе того, что приведено в вопросе.
Также помните, что в C все, что у вас есть, это передача по значению , здесь нет ссылок . В первом случае с int **x;
вы передаете значение, хранящееся в x
(который не инициализирован). Во втором случае с int *x;
вы передаете * адрес x
по значению - и этот адрес всегда устанавливается.
Краткий пример может помочь:
#include <stdio.h>
#include <stdlib.h>
void example (int **temp)
{
*temp = malloc (sizeof **temp);
**temp = 5;
}
int main (void) {
// int **x = NULL; /* value of temp will be NULL */
int *y = NULL; /* value of temp will be address of pointer y */
// example (x); /* segfault - dereferences NULL in example */
example (&y); /* OK */
printf ("*y: %d\n", *y);
free (y);
}
Примечание выше, если вызывается example (x)
, temp
i s копия x
с собственным и очень другим адресом. При example (&y)
, temp
содержит адрес указателя y
, поэтому разыменование temp
(например, *temp
) предоставляет исходный адрес для указателя y
обратно в main()
, позволяя блоку памяти быть присваивается исходному указателю и значению, сохраненному в этом блоке памяти, которое доступно в main()
по возвращении example
.