2013-05-10 3 views
2
#include <stdio.h> 
void SetupAll(int *iPtr, int **p, int ***pp, int ****ppp){ 
    *p = iPtr; 
    **pp =iPtr; 
    ***ppp = iPtr; 
    printf("hi\n"); 
} 

int main() { 
    int i = 42, *p, **pp, ***ppp; 
    SetupAll(&i, &p, &pp, &ppp); 
    printf("%u %u %u %u\n", ***ppp, **pp, *p, i); 
} 

Почему это происходит, когда я запускаю этот код без ppp, тройной указатель, он работает префектно и печатает 42 раза три раза. Но когда я включаю тройной указатель, я получаю seg-ошибку из функции SetupAll. На мой взгляд, ppp следует в том же формате, что и два других указателя, чтобы получить i. Помогите?Указатели на указатели

+0

Когда вы отлаживаете, каковы значения необработанного указателя 'p',' pp', 'ppp', когда вводится' SetupAll'? – Dai

ответ

4

Он падает, потому что вы разыскиваете указатели перед их инициализацией. У вас такая же проблема, даже если у вас нет ppp - вам просто повезло, и она как-то не сработала.

Что вы собираетесь сделать, это следующее:

#include <stdio.h> 
void SetupAll(int *iPtr, int **p, int ***pp, int ****ppp){ 
    *p = iPtr; 
    *pp = p; 
    *ppp = pp; 
    printf("hi\n"); 
} 

int main() { 
    int i = 42, *p, **pp, ***ppp; 
    SetupAll(&i, &p, &pp, &ppp); 
    printf("%u %u %u %u\n", ***ppp, **pp, *p, i); 
} 

Обратите внимание на разницу в SetupAll - вы разыменования каждый указатель только один раз, так что вы можете установить его значение. Остальные «звёзды» в объявлении указывают вам, на что указывает указатель.

EDIT: разработать, когда вы делаете **pp, вы фактически делаете *(*pp) - другими словами (а) первое найти значение *pp, который сам по себе является указателем на междунар, затем (б) попытаться найти значение int, которое *pp указывает на. Но в вашем исходном коде вы еще не инициализировали *pp, поэтому он указал где-то случайным. Поэтому при (b), когда вы пытаетесь найти значение int, вы можете легко сработать, если случайное значение, возвращаемое *pp, не является допустимым адресом памяти.

+2

Отличный ответ. В качестве дополнительного я рекомендовал бы инициализировать указатели нулевым, когда вы их объявляете, что могло бы избежать «удачливых», но фактически «неудачных» ситуаций: всегда сбой может быть лучше, чем не знаю, когда сбой. – 2013-05-10 02:04:12

+0

А, отлично, @duskast. всегда сбой, безусловно, лучше, чем случайный сбой! Я мог бы добавить это к ответу, но, вероятно, это яснее, если единственная разница с исходным кодом находится в де-ссылке. – Corey

0

Может быть полезно отладить эту проблему с помощью valgrind, инструмента для снятия маскировки ошибок памяти.

Собирать с отладочной и запустить его под Valgrind:

$ cc test.c -o test -g 
$ valgrind ./test 
[...] 
Use of uninitialised value of size 8 
    at 0x100000E85: SetupAll (test.c:4) 
    by 0x100000ED3: main (test.c:11) 
Invalid write of size 8 
    at 0x100000E85: SetupAll (test.c:4) 
    by 0x100000ED3: main (test.c:11) 
Address 0x0 is not stack'd, malloc'd or (recently) free'd 

4 линия заключается в следующем:

**pp =iPtr; 

Таким образом, вы можете видеть, что Valgrind расторг программу, когда вы пытались разыменованием *p, неинициализированное значение.

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