Confusione della dichiarazione nei puntatori [chiuso]

1

Ero solo confuso riguardo la seguente dichiarazione in C:

char **p[5]

Capisco il char *p[] come una matrice di puntatori di caratteri, ma questo mi sta sconcertando. In base alla precedenza di [] su * , come posso interpretarlo?

    
posta user1369975 14.01.2016 - 12:37
fonte

2 risposte

4

In "C", un "array" è effettivamente l'indirizzo del suo primo elemento ...

char a[5] == char * a 

... quindi la tua variabile ...

char **p[5]

... è un puntatore a un puntatore a un puntatore a un carattere (di cui solo capita di essere cinque allocati sequenzialmente in memoria).

In caso di dubbi, torna a carta e penna e disegna riquadri per rappresentare ciascun puntatore:

  ---      ---      --- 
p| * | -> | * | -> | * | 
  ---      ---      --- 
                     |
                     v 
                    "four
char a[5] == char * a 
"
    
risposta data 14.01.2016 - 13:19
fonte
4

Le variabili in C sono dichiarate come un tipo seguito da un identificatore seguito da una dimensione facoltativa. (Tralascio i modificatori facoltativi, come static perché non sono pertinenti.) Inizierò con gli interi poiché sono facili da digerire:

Se non ci sono dimensioni presenti, la variabile è del tipo immediatamente a sinistra dell'identificatore. La dichiarazione di int x significa che x è di tipo int . Lo stesso con un puntatore: int *x è di tipo int * .

L'aggiunta di una dimensione ( int x[5] ) modifica la dichiarazione in una matrice, che ha alcuni effetti collaterali:

  • La matrice stessa (cioè il suo contenuto ) è la variabile; l'identificatore diventa semplicemente un modo per riferirsi ad esso, e in C che lo squalifica dall'essere usato come un lvalue. Si tratta di un residuo del linguaggio assembly, in cui è possibile definire un blocco di spazio nella sorgente, assegnargli un'etichetta e fare in modo che la posizione finale dell'etichetta venga riempita ovunque sia stata utilizzata durante il collegamento. Non è possibile modificare l'etichetta; se volevi una variabile, doveva essere in un registro o in una memoria.

  • Il compilatore allocerà abbastanza spazio per contenere l'array (sia esso in pila per un automatico, spazio nell'oggetto per una statica o come parte di una struttura) e prendere nota di dove si trova lo spazio.

  • L'uso dell'identificatore dell'array come valore di rvalore ne viene trattato come se fosse un puntatore al primo elemento * in tutti i contesti tranne due (quelli che sono gli operatori & e sizeof ). Ai fini della comprensione di ciò che è stato dichiarato, trattalo come un puntatore: aggiungi una stella alla fine del tipo e non preoccuparti della dimensione (ad es., int x[5] si comporta come int *x quando x è usato come valore di rvalore ).

Applicandolo al tuo esempio, lo suddividiamo nelle sue parti costitutive:

char **    p    [5]

È presente una dimensione, quindi la sminuzziamo e aggiungiamo una stella al tipo:

char ***   p

Utilizzato come valore di rvalore in tutti tranne i casi eccezionali, p equivale a un puntatore a un puntatore a un puntatore a char .

Il problema con i puntatori è che non hanno alcuna nozione di dove possono essere puntati senza superare i limiti dell'array. Questo è un altro holdover da assembly, in cui un indirizzo potrebbe trovarsi in un registro senza altri contesti e potrebbe non puntare a un array; potrebbe essere solo un'istanza casuale di quel tipo.

L'operatore sizeof ti dà un modo per determinare la dimensione di un array, perché il suo operando è uno di quei casi eccezionali in cui l'identificatore non valuta un puntatore:

int x[5];
size_t x_elements = sizeof x / sizeof *x

Un'altra nota: chiedi delle precedenze relative di * e [] . In una dichiarazione, non sono operatori perché non stai valutando un'espressione. Ergo, la precedenza non si applica.

* Ad un certo punto nei 30 anni da quando ho imparato C, qualcuno ha iniziato a chiamare questo decadimento . Come programmatore di assemblaggi di lunga data, penso che sia un termine terribile perché l'implicazione è che il sottoprodotto è in qualche modo inferiore. Ci sono, sfortunatamente, molti puristi del linguaggio che non riescono a capire che qualcuno deve scrivere tutte queste cose di basso livello per far funzionare le loro belle astrazioni. K & R lo ha reso abbastanza chiaro nella prefazione alla prima edizione di The C Programming Language che questa è l'applicazione per cui è stato sviluppato C.

    
risposta data 14.01.2016 - 15:56
fonte

Leggi altre domande sui tag