Why Is It a Compile Error to Assign the Address of an Array to a Pointer "My_Pointer = &My_Array"

Why is it a compile error to assign the address of an array to a pointer my_pointer = &my_array?

my_array is the name of an array of 5 integers. The compiler will happily convert it to a pointer to a single integer.

&my_array is a pointer to an array of 5 integers. The compiler will not treat an array of integers as a single integer, thus it refuses to make the conversion.

Why don't I have to give the function the address of the array

Yes, you can give the function the address of the first element, and let it deal with the rest. You could do that as either:

print_array(my_array, 20);

...or:

print_array(&my_array[0], 20);

Unfortunately, while &my_array is legal code, it produces a pointer to the entire array, rather than a pointer to the first element of the array. Those have the same address, but different types, which is what's causing the error.

The type of a pointer determines (among other things) how arithmetic on that pointer will work. In your case, print_array prints the first int in the array, then adds one to the pointer. Since it's a pointer to int, that addition actually adds the size of an int to the address in the pointer.

If you used a pointer to the entire array, then adding one would instead add the size of the entire array to the address. For example, let's assume 4-byte ints and that my_array has a base address of 1000. In this case, my_array+1 will yield 1004, so it holds the address of the second int in the array (just as you undoubtedly wanted). By contrast, &my_array will take the address of the entire array, with the type "pointer to array of 20 ints". When you add one to it, that will add 1 * the size of the pointed-to type to the address, so you'll get 1080 (i.e., the entire array is 20 * 4 = 80 bytes). This is obviously not what you wanted--instead of x+1 pointing to the second item in the array, it now points past the end of the array, and attempting to dereference the pointer will give undefined behavior.

So, just switch to one of the forms above (my_array or &my_array[0]). As a more general point, realize that the name of an array evaluates as a pointer to the first element of the array under most circumstances--the notable exceptions being when you use the name of the array as a the operand of either the sizeof operator or the address-of operator (as you did here). In these two cases, the name of the array still refers to the entire array instead of a pointer to the first element.

How come an array's address is equal to its value in C?

The name of an array usually evaluates to the address of the first element of the array, so array and &array have the same value (but different types, so array+1 and &array+1 will not be equal if the array is more than 1 element long).

There are two exceptions to this: when the array name is an operand of sizeof or unary & (address-of), the name refers to the array object itself. Thus sizeof array gives you the size in bytes of the entire array, not the size of a pointer.

For an array defined as T array[size], it will have type T *. When/if you increment it, you get to the next element in the array.

&array evaluates to the same address, but given the same definition, it creates a pointer of the type T(*)[size] -- i.e., it's a pointer to an array, not to a single element. If you increment this pointer, it'll add the size of the entire array, not the size of a single element. For example, with code like this:

char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));

We can expect the second pointer to be 16 greater than the first (because it's an array of 16 char's). Since %p typically converts pointers in hexadecimal, it might look something like:

0x12341000    0x12341010

Questions about Address-of operator (&) and arrays in c and c++

An array in C++ is not a pointer. When a pointer of the appropriate type is initialized using the array's name (such as when the array is passed to a function argument of the appropriate pointer type), it will decay into a pointer, but it is not itself a pointer.

When you declare char my_array[5], you are creating an array of 5 chars; no pointer is created, but a char[5] exists and can be pointed to by other pointers.

If you do char* a = my_array;, my_array will decay into a pointer; a new char* is created pointing to the first element of my_array.

char* b = &my_array; fails because my_array isn't a char, and thus &my_array isn't a char*. char** d = &my_array; fails since my_array isn't a char*, and thus &my_array isn't a char**. &my_array is a char (*)[5] (pointer to an array of 5 chars). These "work" in C because C only requires the compiler issue a warning for implicit conversion between unrelated pointer types, but C++ does not allow these implicit conversions at all; they result in a compilation error. You need an explicit cast in C++, but even then the behavior is undefined if you dereference the resulting pointer.

Finally, pFunc pFunc1 = (pFunc)&my_array; "works" on platforms that represent function pointers and object pointers similarly (most modern systems), but it isn't required to work on all platforms. Again, using the resulting pointer will invoke undefined behavior.

pFunc pFunc2 = (pFunc)my_array; actually compiles as well using GCC, but fails to compile under MSVC. I'm not actually sure which compiler's behavior is correct, but either way the result is unlikely to be anything useful.

cannot assign to array of pointers in c++

pointers[(*id).movieId][(*id).shopId] = &(*id);

tries to store in pointers a pointer to a Movie, pointing into the setMovie.

Now consider what happens, after you do this. What if you did:

pointers[42][43]->priceId = 44;

That would possibly invalidate the set (you could have twice the same Movie). That is why the set doesn't let you do it.

One way around is:

const Movie *pointers[100][100];

Then, you could store the pointer because you wouldn't legally be allowed to modify movies, and mess up the ordering. I'm not sure that makes it a good idea, but it would solve your immediate problem.

For 2, no, it would not be a good idea to call delete on a pointer pointing to a movie stored in your set. You did not call new on this object, so you should not delete it. If you try, you'll get a crash immediately, or much later.

Is an array name a pointer?

An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.

Here is an array:

int a[7];

a contains space for seven integers, and you can put a value in one of them with an assignment, like this:

a[3] = 9;

Here is a pointer:

int *p;

p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:

p = &a[0];

What can be confusing is that you can also write this:

p = a;

This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.

Now you can use p in a similar way to an array:

p[3] = 17;

The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).

For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)

So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.

Why in C++, I don't need to dereference a pointer to an array in order to access items in the array

Code that without dereference

[ code ]

That's incorrect. You are most certainly dereferencing your pointer:

 theArray[i] = i;

That's a pointer dereference. The [] operator dereferences the pointer. This is equivalent to:

 *(theArray+i) = i;

As you know, adding or subtracting a value to a pointer advances or decrements the pointer, producing a new pointer value, and then the pointer gets dereferenced.

Also:

 *p = q;

is equivalent to

 p[0] = q;

The [] operator is just a shorthand for adding an offset to a pointer, and dereferencing the resulting pointer with the * operator. The end result is exactly the same.

C pointers : pointing to an array of fixed size

I would like to add to AndreyT's answer (in case anyone stumbles upon this page looking for more info on this topic):

As I begin to play more with these declarations, I realize that there is major handicap associated with them in C (apparently not in C++). It is fairly common to have a situation where you would like to give a caller a const pointer to a buffer you have written into. Unfortunately, this is not possible when declaring a pointer like this in C. In other words, the C standard (6.7.3 - Paragraph 8) is at odds with something like this:


int array[9];

const int (* p2)[9] = &array; /* Not legal unless array is const as well */

This constraint does not seem to be present in C++, making these type of declarations far more useful. But in the case of C, it is necessary to fall back to a regular pointer declaration whenever you want a const pointer to the fixed size buffer (unless the buffer itself was declared const to begin with). You can find more info in this mail thread: link text

This is a severe constraint in my opinion and it could be one of the main reasons why people do not usually declare pointers like this in C. The other being the fact that most people do not even know that you can declare a pointer like this as AndreyT has pointed out.

C's aversion to arrays

This part of the question...

Is there any logic behind this aversion to arrays? Why isn't there a true robust array type in C? What bad would happen if there was one?

... is not really a code question and open to speculation, but I think a short answer might be beneficial: when C was created, it was targeted at machines with very little RAM and slow CPUs (measured in Kilo-Bytes and Megahertz, resp.). It was meant to replace Assembler as systems programming language, but without introducing the overhead that the other existing high-level languages required. For the same reasons, C is still a popular language for micro controllers, due to the control it gives you over the generated program.

Introducing a 'robust' array type would have had under-the-hood performance and complexity penalties for both the compiler and the runtime, which not all systems couldn't afford. At the same time, C offers the capabilities for the programmer to create their own 'robust' array type and use them only in those situations where its use was justified.

I found this article interesting in this context: Dennis Ritchie: Development of the C Language (1993)



Related Topics



Leave a reply



Submit