tags:

views:

209

answers:

9

It just occurred to me That I don't know how to initialize a pointer to pointer from a non pointer value with one statement in 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

Am I missing something, is the two statement the one and only way to do it?

+13  A: 

You can't get pointer to a temporary. &a results in a r-value. It is allowed not to have an actual address.

Kirill V. Lyadvinsky
This is 100% correct, but I accepted Philip's answer instead because it goes into the rationale of why is that, rather than just pointing out to the standard.
David Reis
+2  A: 

You want a pointer (call it PP) to a pointer (call it P)?

Then P must actually exist. Which means you must declare it.

Of course the compiler will fail at &&a - because you can't take the address of an address. You can take the address of a pointer - but you'll have to declare the pointer first.

Thus:

int a = 1;
int *P = &a;
int **PP = &P;
PP
The parser fails at `
Charles Bailey
+9  A: 

if you want a pointer to a pointer, the pointer that you want to point to must be located somewhere in memory, so I think there cannot be a "one step solution" because you need a pointer variable that you can point to.

(Note: This sentence is not meant to be a linguistic trial to use "point" as often as possible in one sentence :-))

Philipp
A: 

When you do the following:

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

First of all a now exists on the stack. It obviously has a memory address (ie its stack position) this is what you assign to b. b now also exists on the stack and you can then pass its memory address to c. You cannot however take the address of the address of a value without the intermediate stack as it does not exist without explicitly creating it first.

Goz
A: 

This might work:

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

fileoffset
Hmm nope it doesn't, it creates a temporary
fileoffset
+6  A: 

The many other are right: Your pointer to a pointer has to point to something. However, in C99 you can cheat by using compound literals:

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

Compound literals are just basically unnamed objects and have the same storage rules as normal objects. (But you can't give a function scope compound literal static storage duration with the static keyword). You can even nest them so you can rewrite the previous example to a single line:

int **ppa =  &(int *) { &(int) { 1 } };
schot
David Rodríguez - dribeas
@David Rodriguez: No, your are wrong. The compound literal will have the same storage duration as `a` and `ppa`: Static when outside a function, automatic for the duration of the closing block otherwise. See C99 6.5.2.5 (6).
schot
You are completely right. I should have checked the standard before jumping into a comment... If at any point you modify the answer, comment and I will turn the -1 into a +1, it does not allow me to change it now. At any rate, depending on what you want to do with the pointer, it is *as dangerous* as the intermediate variable solution.
David Rodríguez - dribeas
@David Rodriguez: No problem. And indeed, pointers are always dangerous. The fact that the rules around compound literals are not well known is a reason to avoid these constructions.
schot
The rules around compound literals will only become well known if people use them.
caf
This indeed seems correct and does exactly what I wanted to begin with. However I feel its too esoteric to be used on a daily basis.
David Reis
+6  A: 

C++03 [Section 5.3.1] says

The result of the unary &operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. In the first case, if the type of the expression is “T,” the type of the result is “pointer to T.”

In &&a, & operator cannot be applied to the result of &a because the result is not an lvalue.

Also read this thread

Prasoon Saurav
+1  A: 

An address is a number. It only has an address of its own if it is held in a variable, i.e. a pointer. So

int *i1 = &a;

makes sense, but

int **i2 = &&a;

makes no sense. However

int **i2 = &i1;

does make sense. Make sense?

EJP
Your terminology is wrong. The address-of operator *does* yield a pointer, see [ISO03, 5.3.1 expr.unary.op §2]. It's common to call pointer *values* "addresses", and pointer *variables* "pointers", but strictly speaking, that is wrong.
FredOverflow
EJP
A: 

The problem when you do something like &&a; is that you're asking for "the address of the address of a".

That doesn't make sense. We can get the address of a just fine, but that doesn't give us a variable we can take the address of. It just gives us a pointer value. Until that value is stored somewhere, we can't take its addres.

If you have code such as 2+2, the result doesn't have an address either. It is just the value 4, but it hasn't yet been stored anywhere, so we can't take an address. Once we store it into an int variable, we can take the address of that variable.

Basically, the problem is the difference between values and variables. A value is just a number (or a character, or some other data). A variable is a place in memory where a value is stored. A variable has an address, but a value doesn't.

In C++-speak, it is the difference between rvalues and lvalues. An rvalue is essentially a temporary, it's typically a value that was returned from another operation (such as the & operator in your case), but which hasn't yet been stored anywhere.

Once you store it into a variable, you get a lvalue, and lvalues have an address you can take.

So yes, you need the two separate statements. First you take the address, and then you store that address somewhere. And then you can take the address of this "somewhere".

jalf
Your terminology is wrong. The address-of operator *does* yield a pointer, see [ISO03, 5.3.1 expr.unary.op §2]. It's common to call pointer *values* "addresses", and pointer *variables* "pointers", but strictly speaking, that is wrong.
FredOverflow
@Fred: fair enough. I suspected I'd get in trouble over that. ;) That'll teach me to try to rephrase C++ semantics :p
jalf
Fixed it up a bit. Hope I got the most misleading bits.
jalf