views:

359

answers:

5

If I have int x[10] and int *y, how can I tell the difference between the two?

I have two ideas:

  1. sizeof() is different.

  2. &x has different type --- int (*p)[10] = &x works but not int **q = &x.

Any others?

In some template library code, I need to determine whether a pointer is a "real" pointer or degenerated from an array. I can't look at source code as the library user does not exist until I write the library. ... I can work around this by rewriting the code, so now this is only a theoretical exercise.

+5  A: 

There is no general method - you either already know the type because you have just declared the object, or the type will have decayed to a pointer and been lost. Please explain what problem you are trying to solve by differentiating between them.

anon
Ditto :-)
Martin York
I suspect he's either writing some template code that differentiates between an array or pointer or trying to write an array count function/macro that fails for pointers.
MSN
+1  A: 

The sizeof idea is not very good, because if the array happens to have a single element, and the element type happens to be the same size as a pointer, then it will be the same size as the size of a pointer.

The type matching approach looks more promising, and could presumably be used to pick a template specialization (if that's what you're up to).

Daniel Earwicker
A: 

int x[10] will be allways allocated on the stack at the place were it is called. x value can never be changed.

int *y simply declare a pointer to a memory , the pointer value can be changed at any time without any restrictions.

int *y can have any arbitrary value. Meaning , it can point to stack-allocated Memoryor heap allocated memory. Technicly it can also point to invalid memory but that won't make any sense.

int x[10] guarntee you are allways pointing to a valid memory and you don't have to worry about memory deallocation.

when using int* y , you have to worry about the memory it is pointing to .

Also keep in mind that the lot your porgram has dynamically allocated memory the more it will be exposed to errors , leaks , performece issues , allocation\deallocation assimetry and many other kinds of problem.

A: 

They are different types.

How do you tell the difference between an int32 and a uint32, or a uint32 and a char[4]?

The right way to think of it is that the only way that they are similar is that in certain contexts (including array indexing!) an array promotes into a pointer.

Captain Segfault
+1  A: 

Assuming that you aren't trying to do this for a type declared at function scope:

struct yes { char pad; };
struct no { yes pad[2]; };

template <typename T, size_t N> yes is_array_test(T (&arr)[N]);
no is_array_test(...);

#define IS_ARRAY(x) (sizeof(is_array_test(x))==sizeof(yes))
MSN
I would prefer SFINAE (= specialized template) to a macro but nevertheless, this general method is the way to go.
Konrad Rudolph
Well, yes. This however is available as a compile time constant.
MSN
MSN: so is the specialized template. ;-) Only the calling syntax changes slightly, ideally it would look like a Boost type trait: `is_array<x>::value`.
Konrad Rudolph
Well, you can't exactly do is_array<variable>::value. You can do is_array<type>::value in a generic way inside a template function, which I guess is what you are referring to. But I think we both know how to solve this problem both ways, so we both win!
MSN