IMO none of them is really "proper", since all of them are hard to read/understand without being able to lookup the actual type of i
. So just use int *c = &i;
. If you're unsure about the type changing later on, use a typedef
with a custom type rather than int
.
Personally, I'm trying to avoid auto
wherever I can, unless it's really something isolated or easy to understand like an iterator in a for()
loop.
Edit: If you really have to use auto
for whatever reason (let's assume some more complex scenario), then I'd definitely use auto a = ...
rather than auto *a = ...
. Without specifically defining a pointer you're able to replace the actual datatype with something providing a similar interface, e.g. switching from a raw pointer to a smart pointer - you're not restricted to pass/store a raw pointer.
Edit 2: Considering your addition:
auto i = 42, p = &i; // fails at compilation
This won't compile? Pretty obvious. If you declare multiple variables in one line, all of them will get the same datatype. Utilizing auto
here won't mean that the actual meaning of auto
is reevaluated for each entry. Instead, it's "one fits all", and if that fails (which is the case here), it won't compile.
If you add casts to the assignments representing the actual types being assigned, it becomes more obvious:
auto i = (int)42, p = (auto*)&i;
Now auto
is resolved to int
:
int i = (int)42, p = (int*)&i;
Splitting this into two lines to make it even more obvious:
int i = (int)42;
int p = (int*)&i; // Whoopsie!