Stati c двойной указатель против ссылки на один stati c указатель - PullRequest
0 голосов
/ 12 января 2020

Допустим, я хочу использовать библиотечную функцию с такой подписью:

void example(int **temp); 

Я получаю ошибку сегментации, когда передаю состояние c двойной указатель :

int main(){
    int **x; 
    example(x);
} 

Однако я не получаю никакой ошибки, когда передаю ссылку на один указатель :

int main(){
    int *x; 
    example(&x);
} 

В чем разница между этими двумя типы указателей и когда я знаю, какой использовать?

Ответы [ 3 ]

0 голосов
/ 12 января 2020

Разница между этими двумя значениями:

int **x0;
int *y;
int **x1 = &y; 

заключается в том, что X0 является унифицированным указателем, а X1 ссылается на указатель theisting y

0 голосов
/ 12 января 2020

Очень много проблем в этом примере.

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

Теперь в первом случае у вас есть:

int **x; 

, то есть

x = адрес указатель, который указывает на адрес, который указывает на int . Чтобы лучше объяснить x-> y-> int . Но в вашем случае вы создаете только первый указатель x и никогда не инициализируете. Так что у и int нет выделенной памяти и не существует. Хороший способ сделать это может быть следующим:

int **x = (int **)malloc(sizeof (int*)); // allocate and initialize memory for x
*x = (int*)malloc(sizeof(int)); // allocate the memory for the int and initialize the so called "y"

Во втором случае у вас есть:

int *x; 

Но вы также в этом случае не инициализируете указатель. Таким образом, у вас есть х, который имеет адрес мусора. Таким образом, лучший способ может быть следующим:

int *x = (int *)malloc(sizeof (int));

Затем при вызове примера функции вы делаете правильную вещь, давая ссылку указателя x на функцию.

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

0 голосов
/ 12 января 2020

Так как функция 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...