2015-06-01 13 views
5

Tak więc bawiłem się wskaźnikami C i arytmetyką wskaźników, ponieważ nie jestem z nimi całkowicie komfortowo. Wymyśliłem ten kod.Odnośnie do podwójnych i potrójnych wskaźników/podwójnych wymiarów tablic

char* a[5] = { "Hi", "My", "Name", "Is" , "Dennis"}; 
char** aPtr = a; // This is acceptable because 'a' is double pointer 
char*** aPtr2 = &aPtr; // This is also acceptable because they are triple pointers 
//char ***aPtr2 = &a // This is not acceptable according to gcc 4.8.3, why ? 

//This is the rest of the code, the side notes are only for checking 
printf("%s\n",a[0]); //Prints Hi 
printf("%s\n",a[1]); //Prints My 
printf("%s\n",a[2]); //Prints Name 
printf("%s\n",a[3]); //Prints Is 
printf("%s\n",a[4]); //Prints Dennis 

printf("%s\n",*(a+0)); //Prints Hi 
printf("%s\n",*(a+1)); //Prints My 
printf("%s\n",*(a+2)); //Prints Name 
printf("%s\n",*(a+3)); //Prints Is 
printf("%s\n",*(a+4)); //Prints Dennis 

printf("%s\n",*(*(aPtr2) +0)); //Prints Hi 
printf("%s\n",*(*(aPtr2) +1)); //Prints My // ap = a, *ap = *a, *(ap)+1 = *a+1 ? 
printf("%s\n",*(*(aPtr2) +2)); //Prints Name 
printf("%s\n",*(*(aPtr2) +3)); //Prints Is 
printf("%s\n",*(*(aPtr2) +4)); //Prints Dennis 

char*** aPtr2 = &a jest nie do przyjęcia zgodnie z gcc 4.8.3, dlaczego?

Niestety zapomniał dodać ostrzeżenie kompilatora:

ostrzegawczy: Inicjowanie od niezgodnych typu wskaźnik [włączoną domyślnie]

To może jasne, co próbuję powiedzieć, więc musiałem dodaj ten link:

Zwróć uwagę na skomentowane wiersze.

+0

Co oznacza "nie do przyjęcia"? Dołącz komunikat ostrzegawczy lub informujący o błędzie. –

+3

Czy na pewno się zepsuł? http://ideone.com/KM516t (Zwróć uwagę, że brakuje średnika i korzystasz z nazwy 'aPtr2') – mtijanic

+0

Opublikowany przeze mnie link" ideone "skompilował go dobrze dla gcc-4.9.2. Z jakich flag kompilatora korzystasz? – mtijanic

Odpowiedz

1

ta pochodzi od sposobu C traktuje tablice i adresy:

int a[5]; 

a jest typu int * const, prawda, dzięki czemu można go używać gdzie oczekiwany jest wskaźnik. Jednak na stosie miejsce dla wskaźnika nie jest przydzielone, tylko przestrzeń dla pięciu intów. Znaczenie a jest takie samo jak &a[0]. Wszystko to jest oczekiwane, ale tu pojawia się dziwna część:

a jest tym samym, co &a. Jest tak dlatego, że wskaźnik nie jest przechowywany w dowolnym miejscu, nie można uzyskać jego adresu. Ale zamiast zawodzić w kompilacji, standard C mówi, że są one takie same, więc niektóre arytmetyczne będą działać.

Jednakże, ponieważ robisz char ***aPtr2 = &a;, skutecznie robisz char ***aPtr2 = a;, dlatego otrzymujesz błąd segfault. To tylko podwójny wskaźnik, a nie potrójny.

Można sprawdzić wszystkie wartości w debugger, żeby go zobaczyć jaśniej, lub uruchomić program, takich jak:

#include <stdio.h> 

int main(void) 
{ 
    char *a[5] = { "Hi", "My", "Name", "Is" , "Dennis"}; 
    char **aPtr = a; 
    char ***aPtr2 = &aPtr; 
    char ***aPtr3 = &a; 

    printf("%p %c\n", a, *a); 
    printf("%p %p %c\n", aPtr, *aPtr, **aPtr); 
    printf("%p %p %p %c\n", aPtr2, *aPtr2, **aPtr2, ***aPtr2); 
    printf("%p %p %c\n", aPtr3, *aPtr3, **aPtr3); 

    return 0; 
} 

która produkuje wyjście:

0xfff65578 H 
0xfff65578 0x8048648 H 
0xfff65574 0xfff65578 0x8048648 H 
0xfff65578 0x8048648 H 

EDIT: Kolejną interesującą rzeczą jest to, że wskaźniki funkcji są traktowane w ten sam sposób.&func jest taki sam jak func.

int add(int a, int b) { return a + b; } 
typedef int (*PFUNC)(int, int); 

PFUNC p1 = add; 
PFUNC p2 = &add; 
if (p1 == p2) 
    printf("Huh. %d, %d\n", (*p1)(1,2), p2(3, 4)); // the dereference is also optional 
2

a jest adresem bufora 5 ptr i jest niezmienny (to znaczy jest ustalonym ptr). Jeśli wolno

char ***aPtr2 = &a; 

następnie

*aPtr2 = &a[3]; 

faktycznie zmodyfikować adres a (co jest verboten).

Powiązane problemy