2010-09-28 10 views
8

E 'appena venuto in mente che non so come inizializzare un puntatore a puntatore da un valore non puntatore con una dichiarazione in C++:puntatore inizializzazione di puntatore con più operatori di indirizzo in C o C++

int a = 1; 
int** ppa = &&a; //Does not compile 
int** ppa = &(&a); //Does not compile 
int* pa = &a; //Works but is a 
int** ppa = &pa; //Two step solution 

Mi manca qualcosa, le due affermazioni sono l'unico modo per farlo?

+3

Perché pensi che sia necessario un puntatore a un puntatore, in questo caso? – SingleNegationElimination

+0

possibile duplicato di [Come funzionano i puntatori ai puntatori in C?] (Http://stackoverflow.com/questions/897366/how-do-pointer-to-pointers-work-in-c) –

+1

@Jens Gustedt, questo non è un duplicato La domanda collegata chiede informazioni sugli indicatori in generale. Questa domanda riguarda il caso specifico. –

risposta

12

se si vuole un puntatore a un puntatore, il puntatore che si desidera puntare deve trovarsi da qualche parte nella memoria, quindi penso che non ci può essere un "one step", perché hai bisogno di una variabile puntatore a cui puoi puntare.

(Nota: Questa frase non è destinata ad essere una prova linguistica di usare "punto" il più spesso possibile in una frase :-))

14

Non è possibile ottenere il puntatore su un valore temporaneo. &a restituisce un valore r. È permesso non avere un indirizzo reale.

+1

Questo è corretto al 100%, ma ho accettato la risposta di Philip invece perché entra nella logica del perché è questo, piuttosto che limitarsi allo standard. –

2

Si desidera un puntatore (chiamarlo PP) su un puntatore (chiamarlo P)?

Quindi il P deve effettivamente esistere. Il che significa che devi dichiararlo.

Ovviamente il compilatore non riuscirà a &&a - perché non è possibile prendere l'indirizzo di un indirizzo. È possibile possibile prendere l'indirizzo di un puntatore, ma è necessario dichiarare prima il puntatore.

Così:

int a = 1; 
int *P = &a; 
int **PP = &P; 
+1

Il parser fallisce a '&& a' non perché non si può prendere l'indirizzo di un indirizzo ma perché' && 'è un singolo token che non è valido a questo punto nella dichiarazione. 'int ** ppa = x &&a;' potrebbe essere un'inizializzazione valida per un 'x' opportunamente digitato e un' && 'opportunamente sovraccarico (male!) ma non sarebbe l'indirizzo di un indirizzo. –

0

Quando si esegue il seguente:

char a; 
char* b = &a; 
char** c = &b; 

Prima di tutto, ora esiste in pila. Ovviamente ha un indirizzo di memoria (cioè la sua posizione di stack) questo è ciò che si assegna a b. b ora esiste anche nello stack e puoi quindi passare il suo indirizzo di memoria a c. Tuttavia, non è possibile prendere l'indirizzo dell'indirizzo di un valore senza lo stack intermedio poiché non esiste senza averlo prima creato esplicitamente.

-1

questo potrebbe funzionare:

int ** ppa = & (int *) {a} &;

+0

Hmm se no, crea un valore temporaneo – fileoffset

7

I molti altri hanno ragione: il puntatore a un puntatore deve puntare a qualcosa. Tuttavia, in C99 si può barare usando compound literals:

int a = 1; 
int **ppa = &(int *){ &a }; 

letterali composti sono appena fondamentalmente oggetti senza nome e hanno le stesse regole di memorizzazione come oggetti normali. (Ma non è possibile fornire una durata di memorizzazione statica composta letterale dell'ambito della funzione con la parola chiave static). Si può anche nido loro in modo da poter riscrivere l'esempio precedente a una singola linea:

int **ppa = &(int *) { &(int) { 1 } }; 
+0

Questo sarà probabilmente un comportamento indefinito e probabilmente bloccherà l'applicazione al primo utilizzo del puntatore. Il composto letterale è un temporaneo e il compilatore può riutilizzare quello spazio, quindi '* ppa' punta a' & a' durante l'esecuzione della seconda riga, ma potrebbe puntare a qualsiasi altra cosa dopo. –

+1

@David Rodriguez: No, hai torto. Il valore letterale composto avrà la stessa durata di memorizzazione di 'a' e' ppa': Statico se esterno a una funzione, altrimenti automatico per la durata del blocco di chiusura. Vedi C99 6.5.2.5 (6). – schot

+1

Hai perfettamente ragione. Avrei dovuto controllare lo standard prima di saltare in un commento ... Se in qualsiasi momento modifichi la risposta, commento e trasformerò il -1 in un +1, non mi permette di cambiarlo ora. In ogni caso, a seconda di cosa si vuole fare con il puntatore, è * pericoloso * come la soluzione variabile intermedia. –

5

C++ 03 [Section 5.3.1] dice

Il risultato della & operatore unario è un puntatore al suo operando. L'operando deve essere un lvalue o un id qualificato.Nel primo caso, se il tipo dell'espressione è “T”, il tipo del risultato è “puntatore a T”

in &&a, & operatore non può essere applicato al risultato della &a perché il risultato non è un lvalue.

visualizzato anche this filo

2

Un indirizzo è un numero. Ha solo un indirizzo proprio se è contenuto in una variabile, cioè un puntatore. Così

int *i1 = &a; 

ha un senso, ma

int **i2 = &&a; 

non ha senso. Tuttavia

int **i2 = &i1; 

ha senso. Ha senso?

+1

La terminologia è errata. L'indirizzo-dell'operatore * fa * produce un puntatore, vedere [ISO03, 5.3.1 expr.unary.op §2]. È comune chiamare puntatore * valori * "indirizzi" e puntatore * variabili * "puntatori", ma in senso stretto, è sbagliato. – fredoverflow

+0

La terminologia che ho usato è di uso comune. Il valore di un puntatore nel senso dello Standard è un indirizzo in qualsiasi senso, che a sua volta è un numero in qualsiasi senso. Per mettere quello che ho detto in un altro modo, e non produce una variabile *, * così non produce nulla il cui indirizzo può essere preso. – EJP

0

Il problema quando si esegue qualcosa come &&a; è che si sta richiedendo "l'indirizzo dell'indirizzo a".

Questo non ha senso. Possiamo ottenere l'indirizzo di a bene, ma questo non ci dà una variabile, possiamo prendere l'indirizzo di. Ci dà solo un valore puntatore. Fino a quando quel valore non viene memorizzato da qualche parte, non possiamo prendere il suo indirizzo.

Se si dispone di codice come 2+2, il risultato non ha nemmeno un indirizzo. È solo il valore 4, ma non è ancora stato memorizzato da nessuna parte, quindi non possiamo prendere un indirizzo. Una volta che lo memorizziamo in una variabile int, possiamo prendere l'indirizzo di quella variabile.

Fondamentalmente, il problema è la differenza tra valori e variabili. Un valore è solo un numero (o un carattere o altri dati). Una variabile è un luogo in memoria in cui è memorizzato un valore. Una variabile ha un indirizzo, ma un valore no.

In C++ - speak, è la differenza tra rvalues ​​e lvalue. Un valore di rvalue è essenzialmente temporaneo, tipicamente è un valore che è stato restituito da un'altra operazione (come l'operatore & nel tuo caso), ma che non è stato ancora memorizzato da nessuna parte.

Una volta memorizzato in una variabile, si ottiene un lvalue e i lvalue hanno un indirizzo che è possibile prendere.

Quindi sì, sono necessarie le due dichiarazioni separate. Prima prendi l'indirizzo e poi lo memorizzi da qualche parte. E poi puoi prendere l'indirizzo di questo "da qualche parte".

+0

La terminologia è errata. L'indirizzo-dell'operatore * fa * produce un puntatore, vedere [ISO03, 5.3.1 expr.unary.op §2]. È comune chiamare puntatore * valori * "indirizzi" e puntatore * variabili * "puntatori", ma in senso stretto, è sbagliato. – fredoverflow

+0

@Fred: abbastanza giusto. Sospettavo che mi sarei messo nei guai per quello. ;) Questo mi insegnerà a provare a riformulare la semantica C++: p – jalf

+0

Risolto un po '. Spero di aver ottenuto i pezzi più fuorvianti. – jalf