S I
S I

Reputation: 1241

array of integers vs. pointer to integer in c++

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.

Upvotes: 2

Views: 1023

Answers (6)

Josh S
Josh S

Reputation: 147

I just tried the equivalent in g++ 4.5 C++0x mode for char arrays and it won't let me both define

template <typename T>void moresilly(const T v[],const char *description)

AND

template <typename T>void moresilly(const T *v,const char *description)

it claims both are the same type.

I had a function:

template <typename T>void silly(const T & v,const char *description)
{
    cout<<"size of "<<description<<" is "<< sizeof(T)<<endl;
    moresilly(v,description);
}

It correctly gets the size of an array if passed and of a pointer if passed, but I can't use moresilly to distinguish between pointer and array, so I can't tell a 4 character array from pointer to n characters.

It might work, sort of, to have templates on T[1],T[2], T[3] etc. but there's already a post saying that different compilers handle that (or some similar case) differently and that gnu prefers a pointer match in C++11.

... added later: After some experiment I found something that works in g++ 4.5

template <typename T,size_t L>void moresilly(const T (&v)[L],const char *description)
{
    cout<<description<<" is an array"<<endl;
}
template <typename T>void moresilly(const T *v,const char *description)
{
    cout<<description<<" is a pointer"<<endl;
}
template <typename T>void moresilly(const T v,const char *description)
{
    cout<<description<<" is a raw value"<<endl;
}
template <typename T>void silly(const T & v,const char *description)
{
    cout<<"size of "<<description<<" is "<< sizeof(T)<<endl;
    moresilly(v,description);
}

with the following works properly

    silly("12345","immediate string of 5 characters plus zero");
    silly((const char *)"12345","immediate constant char pointer of 5 characters plus zero");
    char testarray[]="abcdef";
    silly(testarray,"char array of 6 characters plus zero");
const char testarray2[]="abcdefg";
silly(testarray2,"const char array of 7 characters plus zero");

Note that if the first function is defined with "const T v[L]" instead of "const T (&v)[L]" it doesn't work, never matching anything.

So I solved your problem but don't expect this to work in other versions of the compiler including future ones. This is why I hate c++. Somehow the definition of the language is so unclear that compilers are full of unstable edge cases.

This is a useful trick though, I may use it.

Upvotes: 0

MSN
MSN

Reputation: 54594

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))

Upvotes: 2

Captain Segfault
Captain Segfault

Reputation: 1726

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.

Upvotes: 0

user88637
user88637

Reputation: 12140

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.

Upvotes: 0

Daniel Earwicker
Daniel Earwicker

Reputation: 116674

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).

Upvotes: 2

anon
anon

Reputation:

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.

Upvotes: 5

Related Questions