vijay said:
I am new to C Programming and just started reading K&R. I was about to
finish the pointers chapter but got very confused with:
1. int arr[10];
From what I have read, arr is a pointer to the first int and &arr is a
pointer to the whole array of 10 ints. Then why does sizeof(arr) gives
40 while sizeof(&arr) gives 4. Shouldn't is be the other way around.
The C FAQ is at <
http://www.eskimo.com/~scs/C-faq/faq.html>. Read
section 6, "Arrays and Pointers".
Briefly, when an array name appears in an expression, it's usually,
but not always, converted to a pointer to its first element. When it
appears as the operand of a unary "&" or sizeof operator, this
conversion doesn't happen. That's why "sizeof(arr)" (or "sizeof arr";
the parentheses aren't necessary) gives you the size of the whole
array, not the size of a pointer, and "&arr" gives you a pointer to
the whole array (which is like a pointer to its first element except
for the type).
2. int arr[2][2]={{1,2},{3,4}};
printf("%u %u",arr,*arr);
produces the same output(base address). But haven't we dereferenced arr
in the second case. I mean, arr is an address to the base of the array
and putting a star in front of should give us the value there.
Here you're invoking undefined behavior by calling printf() with a
"%u" format, but not passing a value of type unsigned int. It may
happen to work on your system (if unsigned ints and pointers happen to
be passed as arguments the same way), but it's not guaranteed. To
print a pointer value, use the "%p" format. Since "%p" expects a
void*, you need to convert the argument explicitly (there's no
implicit conversion in this case).
So try this:
int arr[2][2]={{1,2},{3,4}};
printf("%p %p\n", (void*)arr, (void*)*arr);
arr is of type array[2] of array[2] of int.
For the second argument to printf(), arr decays to a pointer to an
array[2] of int; converting to void* gives you a pointer usable with
"%p".
For the third argument, arr again decays to a pointer to an array[2]
of int. Applying the "*" operator gives you an array[2] of int, which
then decays to a pointer to int. (I think that's right; if not,
someone will jump in and correct me.) It points to the same memory
location as the second argument, but with a different type.
So the second argument points to arr[2], an array of 2 ints, and the
third argument points to arr[2][2], an int. Both are at the same
address.
Here's a program that might demonstrate more clearly what's going on,
using a function that expects arguments of the appropriate types:
#include <stdio.h>
static void print_values(int (*arg1)[2], int *arg2)
{
printf("%p %p\n", (void*)arg1, (void*)arg2);
}
int main(void)
{
int arr[2][2]={{1,2},{3,4}};
printf("%p %p\n", (void*)arr, (void*)*arr);
print_values(arr, *arr);
return 0;
}