-1

In this code:

#include<stdio.h>
  int main()
  {
    int num[2] = {20, 30};
    printf("%d", num);
    printf("%d", &num[0]);
    return 0;
  }

As far as I know, both the printf statement will print the address of the first element in num because in the first statement, num is a pointer to an int.

But if num is a pointer, then it should also have any address but on printing its address (with printf("%d", &num)), it's showing the address of the first element.

In a 2-D array the whole thing becomes confusing too:

#include<stdio.h>
int main(void)
{
    int num[ ] [2]={20,30,40,50};
    printf("%d",*num);
    return 0;
}

This program is printing the address of zeroth element that is the address of num[0][0]. But why does it do this? Why isn't it printing the value stored in it, since they all have same address(num,num[0] and num[0][0])?

Yogesh Tripathi
  • 703
  • 5
  • 16
  • 1
    Can you edit your message with editor to distinguish your code? – Mike Minaev Oct 27 '14 at 13:44
  • 2
    First of all your program is demonstrating Unedfined Behavior (UB). Whenever you want to print the address of a variable you must use the %p, instead of %d (integers). – LeatherFace Oct 27 '14 at 13:44
  • In C construction `*num` means take value from address `num` it is similar to `num[0]` – Mike Minaev Oct 27 '14 at 13:54
  • @MikeMinaev My question is that if num is a pointer in the first example then it should have its own address but has the same address as num[0] why ? and second question is that in the second example *num is showing the address not the value of the zeroth element why? they all have the same address( num,num[0],num[0][0]) – Yogesh Tripathi Oct 27 '14 at 14:07

5 Answers5

5

First things first; array variables are not pointers; they do not store an address to anything.

For a declaration such as

T a[N];

memory will be laid out as

         +---+
   a[0]: |   |
         +---+
   a[1]: |   |
         +---+
          ...
         +---+
 a[N-1]: |   |
         +---+

For a 2D MxN array, it will look like

              +---+
     a[0][0]: |   |
              +---+
     a[0][1]: |   |
              +---+
               ...
              +---+
   a[0][N-1]: |   |
              +---+
     a[1][0]: |   |
              +---+
     a[1][1]: |   |
              +---+
               ...
              +---+
 a[M-1][N-1]: |   |
              +---+

The pattern should be obvious for 3D and higher arrays.

As you can see, no storage is set aside for a separate variable a that contains the address of the first element; instead, there is a rule in the C language that an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array, except when the array expression is one of the following:

  • an operand of the sizeof operator
  • an operand of the unary & operator
  • an operand of the _Alignof operator (C99 and later)
  • a string literal used to initialize an array in a declaration

So given the declaration

T a[N];

all of the following are true:

Expression         Type        Decays to         Value
----------         ----        ---------         -----
         a         T [N]       T *               address of first element, &a[0]
        *a         T           n/a               value stored in first element
        &a         T (*)[N]    n/a               address of the array, which is 
                                                   the same as the address of the
                                                   first element of the array
      a[i]         T           n/a               value stored in the i'th element
     &a[i]         T *         n/a               address of the i'th element
  sizeof a         size_t      n/a               total number of bytes used by the
                                                   array
 sizeof *a         size_t      n/a               total number of bytes used by the
                                                   first element of the array
 sizeof &a         size_t      n/a               total number of bytes used by a 
                                                   pointer to the array 

The expression a has type "N-element array of T"; it is not the operand of the unary & or sizeof operators, so it is converted to a pointer to the first element of the array, amd its value is the address of that element.

The expression &a has type "pointer to N-element array of T"; since a is an operand of the unary & operator, the conversion rule above isn't applied (which is why the expression has type T (*)[N] instead of T **). However, since the address of the array is the same as the address of the first element of the array, it yields the same value as the expression a.

The expression &a[0] has type "pointer to T", and explicitly points to the first element of the array. Again, this value will be the same as the previous two expressions.

For a 2D array

T a[M][N];

all of the following are true:

Expression         Type        Decays to         Value
----------         ----        ---------         -----
         a         T [M][N]    T (*)[N]          address of first subarray, a[0]
        *a         T [N]       T *               address pf first subarray, a[0]
        &a         T (*)[M][N] n/a               address of the array, which is 
                                                   the same as the address of the
                                                   first subarray, which is the same
                                                   as the address of the first element
                                                   of the first subarray.
      a[i]         T [N]       T *               address of first element of i'th
                                                   subarray
     *a[i]         T           n/a               value of first element of i'th subarray
     &a[i]         T (*)[N]    n/a               address of the i'th subarray
  sizeof a         size_t      n/a               total number of bytes used by the
                                                   array
 sizeof *a         size_t      n/a               total number of bytes used by the
                                                   first subarray
 sizeof &a         size_t      n/a               total number of bytes used by a 
                                                   pointer to the array 

Final note: to print out pointer values, use the %p conversion specifier and cast the argument to (void *) (this is the pretty much the only time it's considered proper to explicitly cast a pointer to void *):

printf( "   &a yields %p\n", (void *) &a );
printf( "    a yields %p\n", (void *) a );
printf( "&a[0] yields %p\n", (void *) &a[0] );

Edit

To answer a question in the comments:

num,num[] and num[][] are all different thing. There types are different.Here num decays and became pointer to a pointer and num[] decays and became pointer to int and num[][] is a int. Right?

Not quite.

Assuming a declaration like

int arr[10][10];

then the expression arr will decay to type int (*)[10] (pointer to 10-element array of int), not int **; refer to the table above again. Otherwise you're right; arr[i] will decay to type int *, and arr[i][j] will have type int.

An expression of type "N-element array of T" decays to type "pointer to T"; if T is an array type, then the result is "pointer to array", not "pointer to pointer".

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1sec ..what is the difference between array and array name? are they both diffrent things? – Yogesh Tripathi Oct 28 '14 at 00:54
  • first of all thankyou john for giving me answer in very detailed way that really helped me.As far as i understand by you answer(if i'm wrong then please correct me) is that num,num[] and num[][] are all different thing. There types are different.Here num decays and became pointer to a pointer and num[] decays and became pointer to int and num[][] is a int.Right? – Yogesh Tripathi Oct 28 '14 at 12:37
  • @JohnBode, Thank you for your correction on my answer and this detailed post. I was honestly embarassed at my incorrect knowledge and do not know how I learned this incorrectly. – sadakatsu Oct 28 '14 at 17:35
1

In the second example, num is a 2 dimensional array, or say an array of array. It's true that *num is its first element, but this first element is an array itself.

To get num[0][0], you need **num.

printf("%d\n", **num);
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • thanks for reply Yu.But my question is all the three things that is num,num[0] and num[0][0] have the same address then why not only *num ? – Yogesh Tripathi Oct 27 '14 at 14:01
  • Simply put, it's because even though they have the same value, they have different type. There are quite a few questions about this in SO, try search here, their explanation would be much better than what I can explain in the comment. – Yu Hao Oct 27 '14 at 14:10
  • Can you please tell me what i write in the search box to search about it.It will be really great of u :) – Yogesh Tripathi Oct 27 '14 at 14:15
  • This is one: [How come an array's address is equal to its value in C?](http://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c). – Yu Hao Oct 27 '14 at 14:21
  • thankyou so much Yu .I will reply you if i understand the whole thing by this answer.And again thanks :) – Yogesh Tripathi Oct 27 '14 at 14:29
1

Look how an array looks like:

int num[ ] [2]={20,30,40,50};

is better written as

int num[][2]={{20,30},{40,50}};

It is an array with 2 elements. Those 2 elements are, again, arrays with 2 ints.

In memory, they look like

20    30    40    50

but the difference is that num refers to the whole array, num[0] to the first "part- array" and num[0][0] to the first element of the first array.

They have the same address (because they start at the same place), but they have a different type.

That is, the address is not the only important thing with a pointer, the type is important as well.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • u mean here in my example num[][] decay and become type pointer to a pointer , num[] is a type pointer to a int and num[][] is a int ? – Yogesh Tripathi Oct 28 '14 at 12:41
  • `num` decays into a pointer to its first element, to a pointer to an `int[2]`. `num[0]` as well decays into a pointer to its first element, to a pointer to an `int`. And `num[0][0]` is an `int` itself. – glglgl Oct 28 '14 at 15:33
  • so what is your review about me. i'm correct or not? :D :) – Yogesh Tripathi Oct 28 '14 at 15:36
0

Arrays are not pointers actually, though they tend to act in a bit similar way, but not always.

Say you have this array and a pointer:

int a[] = {1, 2, 3};
int i = 19;
int *ptr = &i;

Now here a is equal to &a, but the same is not true, for pointers (ptr is not equal to &ptr).

Now coming to the question:

Consider a single dimensional array:

int arr[] = {11, 19, 5, 9};

Here, this array elements are stored in contiguous memory locations. Say, with starting address 0:

 ---------------------
| 11 |  19 |  5 |  9 |
 ---------------------
0   4     8    12   16

Now when you write name of the array, arr (for this example), you will get the starting address of the 1st element. Though if you write &arr, then you get the starting address of the whole block(this includes all the elements of the array). Now when you write *arr, you actually get the value inside the 1st element of this array.

Now consider this 2-dimensional array arr[][4] = {{11, 19, 5, 9}, {5, 9, 11, 19}}:

0   4     8    12   16   -> These are memory addresses
 ---------------------
| 11 |  19 |  5 |  9 | ----> These values represent the values inside each index
 ---------------------
| 5  |   9 | 11 | 19 |
 ---------------------
16   20   24    28   32

Here, when you write the name of the array, as arr, what you get is the address of the 1st element of this array, which in this case will be address of this 0th index:

0                           16                32
 ----------------------------------------------
| 0<sup>th</sup> index | 1<sup>st</sup> index |
 ----------------------------------------------

Now when you do &arr, here what you get is the base address for whole of the block, i.e. base address of this:

0   4     8    12   16 
 ---------------------
| 11 |  19 |  5 |  9 | 
 ---------------------
| 5  |   9 | 11 | 19 |
 ---------------------
16   20   24    28   32

Now, if you do *arr, in 1-dimensional array it gives you the value inside the 1st element, though in 2-dimensional array, the value inside each index is actually one 1-dimensional array, hence you will get the address of this array:

0   4     8    12   16 
 ---------------------
| 11 |  19 |  5 |  9 | 
 ---------------------

Now if you do **arr, that is when you will actually get the value inside the 1st element, which is 11.

I hope it clears some doubts :-)

EDIT 1:

As brought to my attendtion, by fellow user, it seems there is a bit of a confusion somewhere, though I have explained in detail what is meant by what thingy. But just to justify, for this statement:

Now here __a is equal to &a__, but the same is not true, for pointers (__ptr is not equal to &ptr__).

The types of both a and &a will be different, as already stated, in the answer. If one performs pointer arithmetics, one will able to know that. Try performing a + 1 and &a + 1, how they both react to pointer arithmetics will surely give a good idea.

Considering a 1-dimensional array:

int arr[] = {11, 19, 5, 9};


 ---------------------
| 11 |  19 |  5 |  9 |
 ---------------------
0   4     8    12   16

We cannot do a++, though for a pointer:

int i = 4;
int *ptr = &i;

we can perform ptr++, this will make ptr point to the next memory location.

nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • 1
    i really appriciate you.i mean the way you explain the question is really great.Though i have aome dobts but i think it will be cleared as i will read about it more.Can you please suggest me any thing which will clear my doubts about the whole pointers in array – Yogesh Tripathi Oct 27 '14 at 15:39
  • `Understanding and Using Pointers in C` by __Richard Reese__ is a good book. Though first try to go through pointers, from any text book you just following. Once, you feel like, you are a bit comfortable, with it, then slowly go to somethingy advance. Do feel free, if you have any doubts. If within my knowledge, will surely will try to guide you. As I am also a learner. Just started learning this language (The C Programming Language by Kerninghan and Richie is a good starting point(This is what I am following, currently)). For the REST, YOU'RE MOST WELCOME and KEEP SMILING :-) – nIcE cOw Oct 27 '14 at 15:42
  • "a is equal to &a" That is not true. They have the same address, but different type. – glglgl Oct 28 '14 at 08:02
  • @glglgl: My reference is, addresses, how they both are stored in memory. Thankyou, for letting me understand, regarding some confusion, though, the latter part of my answer clarifies, in terms of how they are different. Will update soon, as I get to my system :-) – nIcE cOw Oct 28 '14 at 08:06
-2

I think it result means that the array not really a pointer, but it is converted to a pointer in some contexts that is expected a pointer, like pass to a function that expect a pointer argument.

see this code:

void test(int* num) {
     printf("test\n");
     printf("%p\n",num);
     printf("%p\n",&num);
     printf("%p\n",&num[0]);
  }

int main(){
         int num[2]={20,30};
         test(num);
         printf("main\n");
         printf("%p\n",num);
         printf("%p\n",&num);
         printf("%p\n",&num[0]);
         //other();
         return 0;
}

The output is:

test
0x7fff7a422300
0x7fff7a4222e8   //LOOK THIS! Is diferent from main!
0x7fff7a422300
main
0x7fff7a422300
0x7fff7a422300
0x7fff7a422300
Stacker-flow
  • 1,251
  • 3
  • 19
  • 39
felipeaf
  • 377
  • 2
  • 11