# Thread: C arrays and pointers etc. Help!

1. ## C arrays and pointers etc. Help!

I have the code

Code:
```int k = 2;
int a[10];
int b = 0;

for(b=0;b<10;b++)
{
a[b] = 2;
}

printf("Normally with a[k] we get %d\n", a[k]);

int c;

c = *(int *) ((int)&a[0] + k*sizeof(int));

printf("So c = %d\n", c);```
Where I'm just printing out a value from the array "a". However, I don't get why

Code:
`c = *(int *) ((int)&a[0] + k*sizeof(int));`
works exactly the same as a[k].

I've been told

*(int *) = indirect
k*sizeof(int) = offset

I know that the end bit selects which value in the array I want (how many objects away from the start of the array the thing I want is), but I don't get what the other two parts do.

Thanks

2. Does this help?

(int *) = cast to pointer to int
(int) = cast to int
* = dereference (get the value at address)

I think I have that right.

3. When you add an integer (say, 4) to a pointer, C will not just add 4 bytes to your pointer. Rather, it scales the integer to the size of the pointed-to object, so if you added 4 to a pointer to int, you get the fourth int, not the fourth byte.

This is why the code is casting &a[0] (a pointer) to an int: now when an integer is added, scaling is not done. But casting a pointer to an int is really not a good idea. To achieve what this code is trying to do, you want to cast to a pointer to char. A char is a byte, so no scaling is needed, and the conversion to a char pointer is much less dicey than the conversion to an int. So, with that modification, here's what's going on:
Code:
```int a[10] = { 0, 1, 2 };
int k = 2;

/* Now I'll break it down into some rather useless
* C statements for illustrative purposes.
*/

/* This is a pointer to the first element of your array.
* The pointer has type int *.
*/
&a[0];
/* This expression is also a pointer to the first element,
* but more properly, to the first byte of the first element.
* It has type char *.
*/
(char *)&a[0];
/* Now k * sizeof(int) bytes are being added to the char
* pointer.  The resulting value is a pointer to the "k"th
* element of the array (since k is 2, this is the 2nd element).
*/
(char *)&a[0] + k * sizeof(int);
/* Great, we have a pointer to the 2nd element.  But our
* pointer has type char *, which means if we try to
* dereference it, we'll only get a single byte.  So, convert
* the pointer to an int *, so a dereference will get the
* whole int.
*/
(int *)((char *)&a[0] + k * sizeof(int));
/* And finally, the dereference. */
*(int *)((char *)&a[0] + k * sizeof(int));
printf("%d\n", *(int *)((char *)&a[0] + k * sizeof(int)));```
Pointing a char * at any object (like I've done above) is legal, at least in C99. Converting it back to an int * I'm not so sure about, but an implementation would probably have to go to some extra effort to prevent you from doing it. It's not too useful, of course, since we have the [] operator for array access.

4. That awesome car!

5. Cool

So when you have

Code:
`*(int *)`
at the beginning of the code what is the (int*) bit doing? Does the * bit at the very biginning just mean "print out the value at the memory location [whatever]"?

Also, what is the difference between

Code:
`(char *)&a[0];`
and

Code:
`(char )&a[0];`
without the * ?

I'm still learning C, so sorry if my questions seem basic/idiotic.

Thanks!

6. First question: pretty much. The asterisk (*) is the pointer dereference operator in C. For example:
Code:
```int i = 5;
int *p;
p = &i;
*p = 4;```
Here the * operator tells the compiler to look at the value of the variable p and treat that value as an address, and then store the value 4 into that location in memory.

Basically, *p and i refer to the same thing.

The reverse of * is &, which takes the address of a variable. &i is the address in memory where i is located.

Also, what is the difference between
Code:
`(char *)&a[0];`
and
Code:
`(char )&a[0];`
without the * ?
A world of a difference. The first tries to convert &a[0] (which is an int *) into a char *, that is, a pointer-to-char. The second tries to convert it to an ordinary char; since most memory addresses are outside the range of a char (128 for a max, generally), it will almost certainly cause an overflow.

Perhaps you should read a few tutorials about pointers. Just stick something like "c pointer tutorial" into Google and you'll find something. There are even some on this site. cprogramming.com/tutorial.html

7. lets say I have an array of int's
Code:
```int foo[5];
char a;```
and I want to access the LSB bytes in that array for sme reason, I can get those by

Code:
`a = *(char*)&foo[1];`
this takes the address of f[1] and recasts it to a char* then takes the data at that address, which being a char pointer is a char and on a little endian machine will be the LSB of the original int foo[1].

I can then convert that value back in to an int by
Code:
`foo[1] = (int)a;`
so now foo[1] is equal to the LSB of the original value it held.

8. Ok, this is quite stupid.

int foo[5];

foo IS A POINTER!! Test it out, try inserting printf("%d.\n", foo). You'll see that this prints an address, not a value.

There is no need to cast foo since it is a pointer. That is, foo is the same as &foo[0]. Lets look at whats going on in a bit more depth. When the compiler sees this declaration it creates an array of 5 ints on the stack. Foo is assigned the address of the first int. The compiler knows that the ints are side by side in memory so, knowing the first and the size allows it to get the rest of them. So when it gets an index such as foo[1] you can think of it as the compiler changing the pointer to point to the correct thing and then finding that value. So how does it do this? It takes the base (which is foo) and adding the offset (which is index * the size of the array element, in our case an int) and then finding the value at that memory location. So what does that look like in code? It is * (foo + 1 * sizeof(int)). Look familiar? Thats the uncluttered version of what you have above. foo is the base. 1*sizeof(int) is the offset (note that the *sizeof(int) part is only what happens under the hood, in code what would work is *(foo + 1) (see below for more details) the compiler automatically adds the *sizeof(int) and the star at the beginning is a dereference. So lets look at foo[0]. This evaluates to *(foo + 0 * sizeof(int)) which is the same as *foo. Then you did an & which gets the address of the variable so &foo[0] is the same as &*foo which is the same as foo (since the address of a dereference is the variable).

Now, the rest is an error which happens to not have an effect on your system. You took this pointer and casted it to an int. On some systems, the size of an int is 4 bytes and the size of a pointer is 8 bytes. This would cause the compiler to truncate the result. You then took that int and recast it to a pointer and tried to dereference it. This works given that the size of an int is greater than or equal to the size of an pointer (in our case a pointer to an int).

So now, the only reason that cas casted (hehe) the pointer to a char * is because the sizeof a char is 1 byte. The reason this matters is that when you are adding an int to a pointer the int gets scaled by the size of the type of the pointer. So, adding 2 to an int* is really adding 2*sizeof(int) to the pointer. So this means that *(foo + 1) is the same as foo[1] (because the compiler adds the *sizeof(int) bit. The better way to think about it is as actually adding *sizeof(*foo). The compiler would evaluate and find that foo points to an int and then replace *foo with int.

Hope this clears some things up.
chacham15

9. > Converting it back to an int * I'm not so sure about

char * and void * have the same representation and alignment, so you could just cast to void * and then cast to int *.

I think.

10. char * and void * have the same representation and alignment, so you could just cast to void * and then cast to int *.
Well, the problem as far as I see it is that the standard doesn't guarantee that a conversion back to the original type will be meaningful if it's been modified. It's not so much a matter of types as it is values.

Realistically, it should be fine. Technically it's probably not legal.

11. > foo IS A POINTER!!
Bzzt - wrong, no it isn't.
http://c-faq.com/aryptr/index.html
It's true that in many places where you use foo, it decays into "pointer to int", but that doesn't make foo itself "pointer to int". foo (as you've written it) is an "array of 5 int"

Not convinced?
Code:
```void func ( int *a ) {
printf( "%ld\n", sizeof(a) );
}
int main ( ) {
int foo[5];
int *bar = foo; // now this IS a pointer
printf( "%ld\n", sizeof(foo) );
func( foo );
printf( "%ld\n", sizeof(bar) );
func( bar );
return 0;
}```
Your suggestion that foo is just a pointer would have these producing the same answer.

> c = *(int *) ((int)&a[0] + k*sizeof(int));
If some book is teaching you this, then get another book.
Casting a pointer to an int doesn't work on some machines.
IMO, you're learning a bunch of bad habits, and you've only just started.

As cas says, the only pointer cast which is guaranteed is the round trip T* to void* and back to T*

12. Originally Posted by Salem
> foo IS A POINTER!!
Bzzt - wrong, no it isn't.
http://c-faq.com/aryptr/index.html
It's true that in many places where you use foo, it decays into "pointer to int", but that doesn't make foo itself "pointer to int". foo (as you've written it) is an "array of 5 int"

Not convinced?
Code:
```void func ( int *a ) {
printf( "%ld\n", sizeof(a) );
}
int main ( ) {
int foo[5];
int *bar = foo; // now this IS a pointer
printf( "%ld\n", sizeof(foo) );
func( foo );
printf( "%ld\n", sizeof(bar) );
func( bar );
return 0;
}```
Your suggestion that foo is just a pointer would have these producing the same answer.

> c = *(int *) ((int)&a[0] + k*sizeof(int));
If some book is teaching you this, then get another book.
Casting a pointer to an int doesn't work on some machines.
IMO, you're learning a bunch of bad habits, and you've only just started.

As cas says, the only pointer cast which is guaranteed is the round trip T* to void* and back to T*
Bzzt - wrong, no it isn't.

Wow. Just wow. What you are missing is that sizeof is a preprocessor directive. That means that in the function all the preprocessor knows is that the argument is a int* so it will place the size of the pointer there. The same with sizeof(bar). The problem is sizeof(foo). While internally the compiler treats foo as an int* the preprocessor realizes that its an array and returns the size of the array*sizeof(int). A lot of things go on before the compiler has its way or even that that compiler does. For example, creating a 2D array. There is actually no such thing (unless you manually create it with pointers). So, what does the compiler actually do with that? It creates a 1D array and places the next element of the 2d array right after the first. Then when you do a double index, the first index uses sizeof(array)*sizeof(element in array) while the second index uses sizeof(element in array) so you then get a single index into a larger array.

Casting a pointer to an int doesn't work on some machines.
Bzzt - wrong.

Casting a pointer to an int works on all machines. On some machines this will drop some data, but its not a compile error. Plus, I've said this in my previous post.

If you dont believe me about the foo being a pointer i suggest you try and do what I said (or at least explain what is going on, as I have in your situation). In case you forgot, that is do a printf("%x", foo); and see what that gets you.

13. Salem is right, you are wrong.

1. sizeof() is not a preprocessor directive. It is compiler proper - that's why you can't do something like
Code:
```#if sizeof(a) == sizeof(b)
// do something here
#else
// do something else
#endif```
That won't compile, because sizeof is not resolved at pre-processor time.

2. You can CERTAINLY create a 2D, 3D or 4D array:
Code:
```int oned[10];
int twod[10][10];
int threed[10][10][10];
int fourd[10][10][10][10];```
3.
Casting a pointer to an int doesn't work on some machines.
Bzzt - wrong.
Yes, of course, you can cast it to an integer - but the result is not particularly meaningful for the purpose of converting it BACK to a pointer. For example if you drop the upper 32 bits of a 64-bit pointer and then convert that back to a 64-bit pointer, it is quite likely no longer a valid pointer, and it will certainly no longer point to the original data [unless the upper bits were all 0 or all 1 - meaning that the pointer was within the first or last 2GB of memory - and many OS's purposely make sure that addresses of 64-bit applications are OUTSIDE of the 2GB at either end to catch applications making that mistake].

--
Mats

14. > Casting a pointer to an int works on all machines. On some machines this will drop some data
How can that ever be acceptable?

Even on ancient DOS, when you had 16 bit integers and 32 bit far pointers, all that you got was a world of pain.

As for the rest of your wibble on sizeof, go read a book!

> If you dont believe me about the foo being a pointer i suggest you try and do what I said (or at least explain what is going on, as I have in your situation).
Because that's one of the situations in which an array name decays to a pointer.
But just because it does, DOES NOT IMMEDIATELY MAKE the whole thing a pointer.
Did you bother to read the c.l.c FAQ, I bet you didn't.

15. C performs special additional mathematical changes when a pointer of any type is being added to, in order to make up for the size of each element. C actually distinguishes between arrays and pointers in this regard and will adjust accordingly. This is usually discovered when dealing with multidimensional arrays.