2016-01-17 2 views
-1

У меня есть этот код:Двойной Указатели в C и сфера их применения

void alloc2(int** p) { 
    *p = (int*)malloc(sizeof(int)); 
    **p = 10; 
} 

void alloc1(int* p) { 
    p = (int*)malloc(sizeof(int)); 
    *p = 10; 
} 

int main(){ 
    int *p; 
    alloc1(p); 
    //printf("%d ",*p);//value is undefined 
    alloc2(&p); 
    printf("%d ",*p);//will print 10 
    free(p); 
    return 0; 
} 

Итак, я понимаю, что alloc1 просто делает локальную копию, так что это не осуществление вне функции указателя, который дается в качестве параметра.

Но что происходит с alloc2?

tl; dr;

И почему этот alloc1(&p); не будет работать?

Update

Я думаю, что я ответил на мой вопрос. Самое главное, что & делает вам указатель, а затем a был создан для двукратного разыменования bei разыменования. Затем двойной указатель указывает на указанный адрес: malloc. Наконец, адрес был заполнен 10.

И alloc1(&p); будет работать, но вы не сможете устранить двойной указатель, так как он принимает один указатель.

Благодаря всем вам

+0

"Двойные указатели" * являются нормальными указателями. Они всего лишь указатели, указывающие на другие указатели. Точно так же, как «единственный указатель» является указателем на то, что не является указателем. – immibis

ответ

1

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

void alloc2(int** pa2) 
{ 
    *pa2 = (int*)malloc(sizeof(int)); 
    **pa2 = 10; 
} 

void alloc1(int* pa1) 
{ 
    pa1 = (int*)malloc(sizeof(int)); 
    *pa1 = 10; 
} 

int main() 
{ 
    int *p = 0; 
    alloc1(p); 
    //printf("%d ",*p);//value is undefined 
    alloc2(&p); 
    printf("%d ",*p);//will print 10 
    free(p); 
    return 0; 
} 

Помимо переименования аргументов функций, я также инициализируется p в main() нулю (указатель NULL). У вас было это неинициализировано, что означает, что даже доступ к его значению (передать его alloc1()) дает неопределенное поведение.

С p, являющимся NULL, alloc1() также получает указатель NULL как значение pa1. Это локальная копия значения p от main(). Затем вызов malloc() изменяет значение pa1 (и не влияет на p в main(), так как это переменная). В заявлении *pa1 = 10 устанавливается malloced int как 10. Поскольку pa1 является локальным для alloc1(), он прекращает свое существование, когда возвращается alloc1(). Память, возвращаемая malloc(), не является free() d, хотя (pa1 перестает существовать, но на что указывает это не так), поэтому результатом является утечка памяти. Когда управление переходит обратно к main(), значение p по-прежнему равно нулю (NULL).

Звонок alloc2() отличается, так как main() передает адрес p. Это значение pa2 в alloc2(). Оператор *pa2 = (int *)malloc(sizeof(int)) изменяет значение p в main() - для получения значения, возвращаемого malloc(). Затем оператор **pa2 = 10 изменяет динамически распределенный int на 10.

Отметим также, что (int *) на результат malloc() ненужно в C. Если вам это нужно, то это означает один из

  1. Вы не сделали #include <stdlib.h>. Преобразование типа заставляет компилировать код, но любое использование int - строго говоря - дает неопределенное поведение. Если это так, удалите int * и добавьте #include <stdlib.h>.
  2. Вы компилируете свой C-код с помощью компилятора C++.
+0

спасибо peter, поэтому я понимаю предмет сферы, передаю по значению, передаю по ссылке. Я не понимаю '* pa2 = (int *) malloc (sizeof (int))' почему это не так: 'pa2 = (int *) malloc (sizeof (int))' (без '*'). Потому что с '*' вы на самом деле разыскиваете адрес, на который он указывает. И поскольку вы можете видеть, что 'p' указывает на NULL ... – int80

+0

@ int80' p' имеет значение '0', но то, что передается' alloc2() 'is' & p', является указателем на 'p' , Таким образом, параметр 'pa2' является указателем на' p', а не указателем NULL. Поэтому, когда 'pa2' разыменовывается' * ', вы присваиваете значение' p'. –

+0

Итак, с первым деревом вы фактически храните адрес, указанный malloc, в 'pa2', вместо этого сохраняете значение commen? Следовательно, вы можете сохранить значение путем разыменования double? Теперь я могу понять :) – int80

2

Он не стал двойным указателем, в alloc2() вы передаете указатель, содержащий адрес main() «s p. Когда вы разыгрываете это, вы фактически изменяете адрес, хранящийся в main(), p. И поэтому он работает.

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

void 
modify(int *pointer) 
{ 
    *pointer += 1; 
} 

int 
main(void) 
{ 
    int value; 
    value = 0; 

    modify(&value); 
    printf("%d\n", value); 

    modify(&value); 
    printf("%d\n", value); 
} 

выведет

1 
2 

двойной указатель является указателем на указатель, так Y ou делают указатель от p в main(), который хранит адрес p в main(), сам указатель хранится где-то, поэтому вы передаете адрес, в котором хранится указатель, и, следовательно, вы можете изменить его содержимое с alloc2().

Примечание: Плохой стиль, чтобы отличить обратный валун malloc(), read more about it here.

+0

, так что я не понимаю эти строки: '* p = (int *) malloc (sizeof (int));' и '** p = 10;' ... это должно быть разыменование? – int80

Смежные вопросы