The question regarding type of pointers

S

somenath

Hello All,

I am very confused about the output of the following program.

#include<stdio.h>
int daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},
};
int day_of_year(int year,int month,int day)
{
int i;
int leap;
int (*p2)[13];
int (*p3)[2][13];
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));
printf("\nsizeof p3= %d\n", (int) sizeof(*p3));
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3]));
printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

if (month <1 || month >12 || day <1|| day >31)
{
return -1;
}
leap = year %4 && year %100 !=0 || year %400;
p2 = &daytab[0];
p3 = &daytab;
printf("\nleap =%d\n",leap);
for (i =1 ;i<month;i++){
day += *(*(daytab+leap)+i);
//day += *(*(p2+leap)+i);
//day += *(*(*p3+leap)+i);

}

}

int main(void)
{
int day;
day = day_of_year(2012,3,3);
printf("\nDay = %d\n",day);
return 0;
}

Output of the program
sizeof daytab = 104

sizeof p3= 104

sizeof p3[2][3]= 52

sizeof p2= 52

leap =1

Day = 63

My question is how the below line getting evaluated and resulting
correct output?
day += *(*(daytab+leap)+i);

According to my understanding daytab is pointing to the whole daytab[2]
[13] array i.e it is equivalent to p3. So daytab +1 will point
beyond the daytab array so trying to de reference it will cause
undefined behaviour. But I am getting the right result. Where am I
going wrong?

Along with this I would like to verify my understanding about the p2
and p3 as well.
So p2 point to the first row of the daytab array i.e it points to
{0,31,28,31,30,31,30,31,31,30,31,30,31},

Now p2+leap will point to second row depending upon the leap value.
*(p2+leap) is pointer to one of the element of the array for example
it may point to 0 of the first row. So adding i to it will shift the
pointer in that row to the i th element. Then de-reference it result
in the actual value.

Similarly p3 will point to the whole array daytab. The type of *p3
will be equivalent to p2. So the pointer arithmetic on p3 behave same
as p2 . But I am not sure that i am right here as I get the out put
of
printf("\nsizeof p3= %d\n", (int) sizeof(*p3));

as same as
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));

I am very much confused here.

Also i am not able to understand why the output of
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3])); is 52
which is same as

printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

I am not able correctly visualize the type of different pointers that
may be the reason for the whole confusion. Please provide some inputs
regarding this so that I can clearly understand the the pointer type.

I have read the article from the following link.
http://www.torek.net/torek/c/pa.html
After reading it i thought I have understood the different type
associated with pointer. But I am not able to understand still. It is
very much evident as I have failed to understand the behaviour of the
above program.


Thanks
Somenath
 
K

Kaz Kylheku

Hello All,

I am very confused about the output of the following program.

#include<stdio.h>
int daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},

[ ... ]
My question is how the below line getting evaluated and resulting
correct output?
day += *(*(daytab+leap)+i);

This was written by an incompetent who had no regard for writing
clear, maintainable code.

The proper style for this expression, given how daytab operates as a
straightforward two-dimensional table, and how leap and i are straighforward
integer indices into the dimensions of that table, is this:

day += daytab[leap];

There is absolutely no need to obfuscate this perfectly good expression
by replacing E with *((E) + I) even once, let alone twice.
 
H

Heinrich Wolf

....
leap = year %4 && year %100 !=0 || year %400;

shouldn't that be
leap = year %4 && year %100 ==0 || year %400;
?

....
My question is how the below line getting evaluated and resulting
correct output?
day += *(*(daytab+leap)+i);

According to my understanding daytab is pointing to the whole daytab[2]
[13] array i.e it is equivalent to p3. So daytab +1 will point
beyond the daytab array so trying to de reference it will cause
undefined behaviour. But I am getting the right result. Where am I
going wrong?

I don't know

....
I am not able correctly visualize the type of different pointers that
may be the reason for the whole confusion. Please provide some inputs
regarding this so that I can clearly understand the the pointer type.

I don't know

Heiner
 
P

Philip Lantz

Heinrich said:
shouldn't that be
leap = year %4 && year %100 ==0 || year %400;
?

No. It should be
leap = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
 
P

Philip Lantz

somenath said:
Hello All,

I am very confused about the output of the following program.

#include<stdio.h>
int daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},
};
int day_of_year(int year,int month,int day)
{
int i;
int leap;
int (*p2)[13];
int (*p3)[2][13];
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));
printf("\nsizeof p3= %d\n", (int) sizeof(*p3));
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3]));
printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

if (month <1 || month >12 || day <1|| day >31)
{
return -1;
}
leap = year %4 && year %100 !=0 || year %400;
p2 = &daytab[0];
p3 = &daytab;
printf("\nleap =%d\n",leap);
for (i =1 ;i<month;i++){
day += *(*(daytab+leap)+i);
//day += *(*(p2+leap)+i);
//day += *(*(*p3+leap)+i);

}

}

int main(void)
{
int day;
day = day_of_year(2012,3,3);
printf("\nDay = %d\n",day);
return 0;
}

Output of the program
sizeof daytab = 104

sizeof p3= 104

sizeof p3[2][3]= 52

sizeof p2= 52

leap =1

Day = 63

My question is how the below line getting evaluated and resulting
correct output?
day += *(*(daytab+leap)+i);

According to my understanding daytab is pointing to the whole daytab[2]
[13] array i.e it is equivalent to p3. So daytab +1 will point
beyond the daytab array so trying to de reference it will cause
undefined behaviour. But I am getting the right result. Where am I
going wrong?

daytab is not the same as &daytab. p3 is the same as &daytab. daytab (in
an expression where it gets converted to a pointer) is the same as
&daytab[0], which is the same as p2.

As Kaz pointed out, that line of code is equivalent to
day += daytab[leap];
and it should have been written that way.
Along with this I would like to verify my understanding about the p2
and p3 as well.
So p2 point to the first row of the daytab array i.e it points to
{0,31,28,31,30,31,30,31,31,30,31,30,31},

Now p2+leap will point to second row depending upon the leap value.
*(p2+leap) is pointer to one of the element of the array for example
it may point to 0 of the first row. So adding i to it will shift the
pointer in that row to the i th element. Then de-reference it result
in the actual value.
Yes.

Similarly p3 will point to the whole array daytab. The type of *p3
will be equivalent to p2. So the pointer arithmetic on p3 behave same
as p2 .

*p3 (in an expression where it gets converted to a pointer) is the same
as p2. So pointer arithmetic on *p3 behaves the same as pointer
arithmetic on p2. (Note carefully how my statement differs from yours
above.)

The following expressions are equivalent:
daytab[leap]
(*p3)[leap]
p2[leap]

But I am not sure that i am right here as I get the out put
of printf("\nsizeof p3= %d\n", (int) sizeof(*p3));

as same as
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));

Also i am not able to understand why the output of
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3])); is 52
which is same as

printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

The argument to sizeof is not one of those places where an array gets
converted to a pointer, so sizeof *p3 is not the same as sizeof p2.
However, sizeof **p3 is the same as sizeof *p2.

p3[2][3] would be undefined behavior if it were evaluated in this
program, because both subscripts are out of range. However, that
expression is still legal as an operand to sizeof, since the operand to
sizeof isn't evaluated. sizeof p3[2][3] is the same as sizeof **p3, or
sizeof (*p3)[0], which is the way I would write it if I ever had
occasion to write such a thing.
 
B

Barry Schwarz

Hello All,

I am very confused about the output of the following program.

#include<stdio.h>
int daytab[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},
};
int day_of_year(int year,int month,int day)
{
int i;
int leap;
int (*p2)[13];
int (*p3)[2][13];
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));
printf("\nsizeof p3= %d\n", (int) sizeof(*p3));
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3]));
printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

if (month <1 || month >12 || day <1|| day >31)
{
return -1;
}
leap = year %4 && year %100 !=0 || year %400;
p2 = &daytab[0];
p3 = &daytab;
printf("\nleap =%d\n",leap);
for (i =1 ;i<month;i++){
day += *(*(daytab+leap)+i);
//day += *(*(p2+leap)+i);
//day += *(*(*p3+leap)+i);

}

}

int main(void)
{
int day;
day = day_of_year(2012,3,3);
printf("\nDay = %d\n",day);
return 0;
}

Output of the program
sizeof daytab = 104

sizeof p3= 104

Obviously this is a lie since the call to printf did not print out the
size of p3 but the size of *p3. p3 is a pointer and in all likelihood
its size is either 4 or 8.
sizeof p3[2][3]= 52

sizeof p2= 52

A lie for the same reason.
leap =1

Day = 63

My question is how the below line getting evaluated and resulting
correct output?
day += *(*(daytab+leap)+i);

According to my understanding daytab is pointing to the whole daytab[2]
[13] array i.e it is equivalent to p3. So daytab +1 will point
beyond the daytab array so trying to de reference it will cause
undefined behaviour. But I am getting the right result. Where am I
going wrong?

As an object, daytab is indeed the complete array you describe. But
as an expression, daytab is converted to a pointer to the first
element of the array with type pointer to element type. (There are
exceptions which don't apply here; see 6.3.2.1-3 if interested.)

So daytab in this statement is identical to &daytab[0]. Therefore,
daytab points to the first array of 13 int. Since leap is 1,
daytab+leap points to the second array of 13 int. The expression
*(daytab+leap) dereferences this pointer value and evaluates to the
object daytab[1].

This object is also an array and is converted as described above.
Therefore, in this statement *(daytab+leap) is identical to
&daytab[1][0] which is the address of the first int in the second
array. Obviously *(daytab+leap)+i will point to the i-th int in this
array. The expression *(*(daytab+leap)+i) dereferences this address
to produce the value of the i-th int.

As others have pointed out, the calculation for leap is incorrect and
if you changed the year to 2013 it would produce a value as if that
year were a leap year also.
Along with this I would like to verify my understanding about the p2
and p3 as well.
So p2 point to the first row of the daytab array i.e it points to
{0,31,28,31,30,31,30,31,31,30,31,30,31},

p2 was never assigned a value so its value is indeterminate. You
could say it doesn't point anywhere currently. Since it is a pointer
to an array of 13 int, it could be made to point to the first "row"
(technically the first element) of daytab with either initialization
or assignment. Either daytab or &daytab[0] would serve as a suitable
expression to accomplish this.
Now p2+leap will point to second row depending upon the leap value.

p2+leap will point to the first or second row depending on whether
leap is 0 or 1, respectively.
*(p2+leap) is pointer to one of the element of the array for example

*(p2+leap) is the actual array (either first or second depending on
leap).
it may point to 0 of the first row. So adding i to it will shift the

As described above, the expression *(p2+leap) will be converted to a
pointer to the first element of the appropriate array determined by
leap. It will point to either daytab[0][0] or daytab[1][0], both of
which happen to be 0.
pointer in that row to the i th element. Then de-reference it result

p2 doesn't change value. The value of the expression will point to
the i-th element.
in the actual value.
Yes.


Similarly p3 will point to the whole array daytab. The type of *p3

Again, no value was assigned or initialized. p3 could point to daytab
but the only valid expression for achieving this is &daytab. Note the
difference between this and the possible expressions for p2 above.
will be equivalent to p2. So the pointer arithmetic on p3 behave same

The type of *p3 is array of 2 array of 13 int. The type of p2 is
pointer. They are not equivalent. (For example, the size of *p3 is
104 and the size of p2 is 4.)
as p2 . But I am not sure that i am right here as I get the out put

Pointer arithmetic on the two will NOT behave the same. p3+1 points
104 bytes beyond p3 while p2+1 points only 52 bytes beyond p2.
of
printf("\nsizeof p3= %d\n", (int) sizeof(*p3));

as same as
printf("\nsizeof daytab = %d\n", (int) sizeof(daytab));

p3 is a pointer to an array of 2 array of 13 int. Even though p3 has
not been assigned a value, the TYPE of *p3 is array of 2 array of 13
int. That is all the sizeof operator cares about. It does not
evaluate its operand. The operator is applied to the type of the
operand. daytab is an actual array of the same type and therefore has
the same size.
I am very much confused here.

Also i am not able to understand why the output of
printf("\nsizeof p3[2][3]= %d\n", (int) sizeof(p3[2][3])); is 52
which is same as

p3 is pointer to an array of 2 array of 13 int. Even though it
doesn't point to one, p3[0] is the "virtual object" it points to.
p3[1] would be the next object of this type in memory and p3[2] would
be the third such object. So p3[2] is an array of 2 array of 13 int.
Again, p3[2][0] is the first such array of 13 int it points to.
p3[2][1] would be the second, p3[2][2] the third, and p3[2][3] the
fourth. Therefore, p3[3][3] is an array of 13 int. Hence a total
size of 52.
printf("\nsizeof p2= %d\n", (int) sizeof(*p2));

p2 is a pointer to an array of 13 int. *p2 is the array it points to
(even if it doesn't really exist). Hence the same size.
I am not able correctly visualize the type of different pointers that
may be the reason for the whole confusion. Please provide some inputs
regarding this so that I can clearly understand the the pointer type.

I have read the article from the following link.
http://www.torek.net/torek/c/pa.html
After reading it i thought I have understood the different type
associated with pointer. But I am not able to understand still. It is
very much evident as I have failed to understand the behaviour of the
above program.

1 - Both the dereference operator (*) and the subscript operator ([]),
when applied to pointer, evaluate to a value that has the type of the
thing pointed to.

2 - Both operators, when applied to an array, evaluate to a value that
has the type of each of the array elements.

Thus, p3[0], which is by definition exactly the same as *p3, evaluates
to an array of 2 array of 13 int by 1 above. Similarly, *p2 evaluates
to an array of 13 int. And daytab[0] also evaluates to an array of 13
int by 2 above

Technically, sizeof does not evaluate its operand. It deals only with
the type that expression would have if it were evaluated.
 
S

somenath

Many thanks for replying and providing valuable inputs.

After going through the different article I have summarized my
understanding as follows. Please provide comments. Also I would
request you to correct my understanding if it is wrong. Again many
thanks for the help.
============================================================================
So suppose we have array declaration as follows

int ar[3];

Question ==> then the question is what is ar and what is sizeof(ar)
will produce.

Before getting into the answer of this first we need to know the
following.
C does not have array value but C has array objects. Let us take an
example to elaborate this .The declaration int a[3] declares an
ordinary array containing 3 int. Logically this ‘ar’ should be having
value as 3 int but it does not have instead it has the address of the
first element of the array that is &ar[0]. So ar in value context will
have &ar[0].
So our first question is answered.

Next what is sizeof(ar) ?

We know that sizeof needs ar in object context ant ar is an object of
3 ints so sizeof( ar) is 3*sizeof(int).
So our second question is answered.

Question => What is the sizeof(*ar)?

As said before sizeof need *ar in object context. So value of *ar is
an ordinary int. so sizeof (*ar) will be sizeof(int)

Question => What will be the sizeof(ar+0)?

Ok. So what are we doing here? We are adding value of ar to 0. So what
is value of ar? It is the &ar[0].

That mean essentially we are adding 0 to a pointer to an int. The
resultant type will be also a pointer to int. So sizeof(ar+0) will be
equal to sizeof(int*) may be equal to sizeof(int) .

So now we should not be surprised by the output of the following
program.
int a[3];
printf("\nsizeof(a) =%d\n",sizeof(a)); //Prints 12
printf("\nsizeof(a+0) =%d\n",sizeof(a+0)); //Print 4

Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
int ar[3][3];

Question => what will be sizeof(ar)?

We know that in this ar is in object context and ar is an object of
array 3 of 3 int . So sizeof(ar) is sizeof(int) *3*3.

Question => what will be the sizeof (&ar)?

We know that & operator needs an object as its operand and it produces
the address of the object.
So type of &ar will be int(*)[3][3]. Hence the sizeof(&ar) is equal to
sizeof(int(*)[3][3])) may be equal to (sizeof(int))

Question=> What is sizeof( ar[3])?

So what is ar[3]? ar[3] contains the pointer to first element of row
of int where the row size is 3. The type of ar[3] is int(*)[3]. So
ar[0] contains the starting address of the first row ,ar[1] contains
the staring address of second row so on . Hence size of ar[3]. Is 3
*sizeof(Int (*)[3]) which may be 3 *sizeof(int*)

Question => now the last question

What is the output of the following program?

int ar[3][3];
int (*p)[3][3] =&ar;
printf("%d\n",sizeof(p[2][3]));
printf("%d\n",sizeof(*((*p+2)+3)));


So we know in p[2][3] is in value context. So what is the value of
p[2][3]?
P is a pointer to 3 array of 3 int. We can imagine a 3X3 matrix in RAM
and p is pointing to the beginning address of that block. So p[2]
also pointing to 3X3 block . So inside each block we have row of int
having row size as 3. So sizeof(p[2][3]) is equal to sizeof(int) *3.

So *p+2 is same as p[2] and *((*p+2)+3) is same a p[2][3 . That’s the
reason both printf produce same output.
 
S

somenath

Many thanks for replying and providing valuable inputs.

After going through the different article I have summarized my
understanding as follows. Please provide comments. Also I would
request you to correct my understanding if it is wrong. Again many
thanks for the help.
============================================================================
So suppose we have array declaration as follows

int ar[3];

Question ==> then the question is what is ar and what is sizeof(ar)
will produce.

Before getting into the answer of this first we need to know the
following.
C does not have array value but C has array objects. Let us take an
example to elaborate this .The declaration int a[3] declares an
ordinary array containing 3 int. Logically this ‘ar’ should be having
value as 3 int but it does not have instead it has the address of the
first element of the array that is &ar[0]. So ar in value context will
have &ar[0].
So our first question is answered.

Next what is sizeof(ar) ?

We know that sizeof needs ar in object context ant ar is an object of
3 ints so sizeof( ar) is 3*sizeof(int).
So our second question is answered.

Question => What is the sizeof(*ar)?

As said before sizeof need *ar in object context. So value of *ar is
an ordinary int. so sizeof (*ar) will be sizeof(int)

Question => What will be the sizeof(ar+0)?

Ok. So what are we doing here? We are adding value of ar to 0. So what
is value of ar? It is the &ar[0].

That mean essentially we are adding 0 to a pointer to an int. The
resultant type will be also a pointer to int. So sizeof(ar+0) will be
equal to sizeof(int*) may be equal to sizeof(int) .

So now we should not be surprised by the output of the following
program.
int a[3];
printf("\nsizeof(a) =%d\n",sizeof(a)); //Prints 12
printf("\nsizeof(a+0) =%d\n",sizeof(a+0)); //Print 4

Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
int ar[3][3];

Question => what will be sizeof(ar)?

We know that in this ar is in object context and ar is an object of
array 3 of 3 int . So sizeof(ar) is sizeof(int) *3*3.

Question => what will be the sizeof (&ar)?

We know that & operator needs an object as its operand and it produces
the address of the object.
So type of &ar will be int(*)[3][3]. Hence the sizeof(&ar) is equal to
sizeof(int(*)[3][3])) may be equal to (sizeof(int))

Question=> What is sizeof( ar[3])?

So what is ar[3]? ar[3] contains the pointer to first element of row
of int where the row size is 3. The type of ar[3] is int(*)[3]. So
ar[0] contains the starting address of the first row ,ar[1] contains
the staring address of second row so on . Hence size of ar[3]. Is 3
*sizeof(Int (*)[3]) which may be 3 *sizeof(int*)

Question => now the last question

What is the output of the following program?

int ar[3][3];
int (*p)[3][3] =&ar;
printf("%d\n",sizeof(p[2][3]));
printf("%d\n",sizeof(*((*p+2)+3)));


So we know in p[2][3] is in value context. So what is the value of
p[2][3]?
P is a pointer to 3 array of 3 int. We can imagine a 3X3 matrix in RAM
and p is pointing to the beginning address of that block. So p[2]
also pointing to 3X3 block . So inside each block we have row of int
having row size as 3. So sizeof(p[2][3]) is equal to sizeof(int) *3.

So *p+2 is same as p[2] and *((*p+2)+3) is same a p[2][3 . That’s the
reason both printf produce same output.
 
B

Barry Schwarz

Many thanks for replying and providing valuable inputs.

After going through the different article I have summarized my
understanding as follows. Please provide comments. Also I would
request you to correct my understanding if it is wrong. Again many
thanks for the help.
============================================================================
So suppose we have array declaration as follows

int ar[3];

Question ==> then the question is what is ar and what is sizeof(ar)
will produce.

Before getting into the answer of this first we need to know the
following.
C does not have array value but C has array objects. Let us take an
example to elaborate this .The declaration int a[3] declares an
ordinary array containing 3 int. Logically this ‘ar’ should be having
value as 3 int but it does not have instead it has the address of the
first element of the array that is &ar[0]. So ar in value context will
have &ar[0].
So our first question is answered.

Next what is sizeof(ar) ?

We know that sizeof needs ar in object context ant ar is an object of
3 ints so sizeof( ar) is 3*sizeof(int).
So our second question is answered.

Question => What is the sizeof(*ar)?

As said before sizeof need *ar in object context. So value of *ar is
an ordinary int. so sizeof (*ar) will be sizeof(int)

Question => What will be the sizeof(ar+0)?

Ok. So what are we doing here? We are adding value of ar to 0. So what
is value of ar? It is the &ar[0].

That mean essentially we are adding 0 to a pointer to an int. The
resultant type will be also a pointer to int. So sizeof(ar+0) will be
equal to sizeof(int*) may be equal to sizeof(int) .

It may also be equal to sizeof(float) or sizeof(long) or even
sizeof(char). Don't introduce extraneous irrelevant possibilities
which will only serve to reinforce someone's misconceptions.
So now we should not be surprised by the output of the following
program.
int a[3];
printf("\nsizeof(a) =%d\n",sizeof(a)); //Prints 12
printf("\nsizeof(a+0) =%d\n",sizeof(a+0)); //Print 4

Unless size_t is a typedef for int, the output from the above is
undefined (and therefore free of surprises). If you system does not
support %z then cast the sizeof expression to match the format
conversion (in this case %d requires an int).
Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
int ar[3][3];

Question => what will be sizeof(ar)?

We know that in this ar is in object context and ar is an object of
array 3 of 3 int . So sizeof(ar) is sizeof(int) *3*3.

Question => what will be the sizeof (&ar)?

We know that & operator needs an object as its operand and it produces
the address of the object.
So type of &ar will be int(*)[3][3]. Hence the sizeof(&ar) is equal to
sizeof(int(*)[3][3])) may be equal to (sizeof(int))

And when you update your compiler to the next release it may not be
equal to sizeof(int) so again why and who cares?
Question=> What is sizeof( ar[3])?

So what is ar[3]? ar[3] contains the pointer to first element of row
of int where the row size is 3. The type of ar[3] is int(*)[3]. So

ar[3] does not exist. The only elements of ar are ar[0], ar[1], and
ar[2]. No ar contains any pointer value at all. Each ar is an
array of 3 int. Period. No pointers whatsoever.

The type of any ar is int[3], NOT int(*)[3]. With a few
exceptions, the expression ar is converted to &ar[0]. BUT one
of those exceptions is when it is the operand of the sizeof operator.
ar[0] contains the starting address of the first row ,ar[1] contains
the staring address of second row so on . Hence size of ar[3]. Is 3

ar does not contain any addresses at all.
*sizeof(Int (*)[3]) which may be 3 *sizeof(int*)

If it existed, ar[3] would be an array of 3 int. Since sizeof does
not evaluate its operand but deals only with the type the operand
would have if it existed, the fact that ar[3] does not exist is not an
issue. sizeof(ar[3]) is exactly 3*sizeof(int).
Question => now the last question

What is the output of the following program?

int ar[3][3];
int (*p)[3][3] =&ar;
printf("%d\n",sizeof(p[2][3]));

Of course p[2][3] does not exist either but sizeof doesn't care. p is
a pointer to an int[3][3]. p is therefore one such int[3][3].
p[j] is therefore one of the int[3] in that int[3][3]. Therefore
sizeof(p[2][3]) is always 3*sizeof(int).
printf("%d\n",sizeof(*((*p+2)+3)));

p is a pointer to an int[3][3]. *p is the int[3][3] it points to.
Since the expression *p+2 is not one of the exceptions, *p is
converted to the address of the first int[3] in that int[3][3]. *p+2
is computed as the address of the third int[3] in that int[3][3].
((*p+2)+3) is the same as (*p+2+3) or (*p+5) and is simply the address
of a non-existent sixth int[3] in that int[3][3]. *((*p+2)+3)) is
this sixth int[3] itself and it's size is always 3*sizeof(int).

I expect you meant sizeof(*(*(p+2)+3)). Since *(*(p+2)+3) is by
definition the same as p[2][3], this has been discussed in the comment
to the preceding printf.
So we know in p[2][3] is in value context. So what is the value of
p[2][3]?

p[2][3] doesn't exist so it has no value.
P is a pointer to 3 array of 3 int. We can imagine a 3X3 matrix in RAM
and p is pointing to the beginning address of that block. So p[2]
also pointing to 3X3 block . So inside each block we have row of int
having row size as 3. So sizeof(p[2][3]) is equal to sizeof(int) *3.

So *p+2 is same as p[2] and *((*p+2)+3) is same a p[2][3 . That’s the

No for reasons described above.
reason both printf produce same output.

p[2][3] dereferences p twice. *((*p+2)+3) dereferences p twice.
*(*(p+2)+3) dereferences p twice. All three expression have the same
type. That is why the sizeof all three expressions is the same. Since
the object described by the expressions does not exist, it is obvious
that sizeof deals only with types and not values.
 
S

somenath

somenath said:
Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
 int  ar[3][3];
Question=> What is sizeof( ar[3])?
So what is ar[3]? ar[3] contains the pointer

No, ar[3] doesn't contain any pointer.

ar[3] is an expression of type array of three int.

I did not understand this. According to my understanding C does not
have array value instead Instead, the "value" of the array is a
pointer to the first element of that array.

So for if we have int ar[3];
ar will have address of ar[0]. Essentially it is pointer to the first
element of a row of 3 int.
So now if we have int ar[3][3];

ar[0] will have the address of the first element of the the first row
of 3 int.
similarly ar[3] will have the address of the first element of the
third row of 3 int.
So the type of ar[3] will be int(*)[3] in value context. Where I am
going wrong? Please correct my understanding.
/* BEGIN new.c */

#include <stdio.h>

int
main(void)
{
    char ar[3][7];

    printf("sizeof ar[3] is %u\n.", (unsigned)sizeof ar[3]);
    return 0;

}

So sizeof operator needs ar[3] in object context. So ar[3] in the
above is in object context not in value context. Now ar[3] is an array
object of 7 char. So the printf will print the result as sizeof
(char ) *7 not sizeof(char (*)[7])

Now if we think about the value of ar[3] then it will be the address
of the first element of the the third row of size 7. Please correct
me if I am wrong.
 
S

somenath

Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
int  ar[3][3];
Question=> What is sizeof( ar[3])?
So what is ar[3]? ar[3] contains the pointer  to first element of row
of int where the row size is 3. The type of ar[3] is  int(*)[3]. So

ar[3] does not exist.  The only elements of ar are ar[0], ar[1], and
ar[2].  No ar contains any pointer value at all.  Each ar is an
array of 3 int.  Period.  No pointers whatsoever.

I am not able to correlate between the statements which say "C does
not have array values.Instead, the ‘value’ of the array is a pointer
to the first element of that array." with the fact " No ar contains
any pointer value at all. Each ar is an array of 3 int. Period.
No pointers whatsoever."

Where I am going wrong? As I have mentioned earlier my understanding
is ar will have the address of the first element of the ith row.
Is this not correct? I am very confused. Please help me to understand
it correctly.
 
J

James Kuyper

Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
int �ar[3][3];
Question=> What is sizeof( ar[3])?
So what is ar[3]? ar[3] contains the pointer �to first element of row
of int where the row size is 3. The type of ar[3] is �int(*)[3]. So

ar[3] does not exist. �The only elements of ar are ar[0], ar[1], and
ar[2]. �No ar contains any pointer value at all. �Each ar is an
array of 3 int. �Period. �No pointers whatsoever.

I am not able to correlate between the statements which say "C does
not have array values.Instead, the �value� of the array is a pointer
to the first element of that array." ...


That last sentence is incorrect. The "value of an array" is a
meaningless concept in C, so all statements about such a thing are
meaningless. What that sentence is trying and failing to correctly
describe is the fact that an lvalue expression with an array type is
automatically converted, in MOST contexts, into a pointer to the first
element of that array. Note that this is a conversion set up by the
compiler, and performed by your program when needed; it is NOT the
retrieval of a saved pointer value.

The exceptions are when applying the unary & operator, the sizeof
operator, and when a string literal is used to initialize an array. In
each of those exceptions, something is done using the entire array - but
the thing that is being done does not involve the non-existent value of
the array: &array gives a pointer to the array, The expression "sizeof
array" gives the size, in bytes, of the array. In the definition

char array[] = "string literal";

the elements of the array created by the string literal are copied into
the array created by that definition. In many contexts, that copying can
be optimized away, and there will actually be only one array, not two.
However, that's just an optimization - the standard describes the
behavior in terms of having two separate arrays.
...with the fact " No ar contains
any pointer value at all. Each ar is an array of 3 int. Period.
No pointers whatsoever."


That's right, there are no pointers contained in ar. When used in
various contexts, the expression ar gets converted into a pointer to
the first element of ar; but that pointer is (modulo optimizations)
calculated from the address of 'ar' and the value of 'i'.
Where I am going wrong? As I have mentioned earlier my understanding
is ar will have the address of the first element of the ith row.
Is this not correct? I am very confused. Please help me to understand
it correctly.


It is NOT correct. ar does NOT contain a pointer to the members of
ar, it only contains those members themselves. Your program knows
precisely where these members are, so it can create a pointer value
pointing at the first one. It knows this, because it knows where ar
is. In turn, it knows where ar is because it knows where ar is.

The details of how that is done are implementation-specific, but on many
systems, your program knows where 'ar' is because there's a register
which has been reserved to store the address of a block of memory which
may contain many variables, including 'ar', each at a fixed offset from
the start of the block. On such a system, when you write ar in a
context where it gets converted into a pointer to the first element of
ar, your program performs a calculation equivalent to the following:

(int*)(base_address + offset_of_ar) + i*3

The value of offset_of_ar is a constant, built into your program. As a
result, the only pointer your program actually needs to keep track of in
order to create a pointer value from the expression ar, is the
base_address which is stored in a register.
 
J

James Kuyper

On 04/28/2012 11:27 PM, somenath wrote:
....
I did not understand this. According to my understanding C does not
have array value instead Instead, the "value" of the array is a
pointer to the first element of that array.

C has expressions that refer to arrays. These expressions do not have a
value; the expression (NOT it's non-existent value) gets automatically
converted into a pointer to the first element of that array in many
contexts. However, an array expression does not itself have any value,
and in several important contexts no such conversion occurs.
 
S

somenath

somenath said:
somenath wrote:
Now let us focus on the two dimensional array.
==========================================================
Suppose we have the following declaration
 int  ar[3][3];
Question=> What is sizeof( ar[3])?
So what is ar[3]? ar[3] contains the pointer
No, ar[3] doesn't contain any pointer.
ar[3] is an expression of type array of three int.
I did not understand this. According to my understanding C does not
have array value instead Instead, the "value" of the array is a
pointer to the first element of that array.
So for if we have int ar[3];
ar will have address of ar[0]. Essentially it is pointer to the first
element of a row  of 3 int.
So now if we have int ar[3][3];
ar[0] will have the address of the first element of the the first row
of 3 int.
similarly ar[3] will have the address of the first  element of the
third row of 3 int.
So the type of ar[3] will be int(*)[3] in value context. Where I am
going wrong? Please correct my understanding.
/* BEGIN new.c */
#include <stdio.h>
int
main(void)
{
    char ar[3][7];
    printf("sizeof ar[3] is %u\n.", (unsigned)sizeof ar[3]);
    return 0;
}
So sizeof operator needs ar[3] in object context. So ar[3] in the
above is in object context not in value context. Now ar[3] is an array
object of 7 char. So the printf will print the result as sizeof
(char ) *7 not sizeof(char (*)[7])
Now if we think about the value of ar[3] then it will be the address
of the first element of the the third row of size 7.  Please correct
me if I am wrong.

There is no ar[3], so ar[3] has no value.

This declaration
    {char ar[3][7];}
declares an array of 3 arrays of 7 char.
The 3 arrarys are ar[0], ar[1], and ar[2].
The size of each of those 3 arrays is 7 bytes.

It doesn't matter that there is no ar[3]
for the expression (sizeof ar[3])
because the operand of sizeof is not evaluated.
The type of the expression of the operand
is all that matters to the sizeof operator.

    printf("sizeof ar[3000] is %u\n.", (unsigned)sizeof ar[3000]);
would have outputed
    "sizeof ar[3000] is 7"

Expressions of array type are converted to pointers
in all but 3 contexts:
1    operand of sizeof operator
2    operand of address operator
3    string literal initializer

When you have a declaration like
    char ar[3][7];
without any more context,
then I will describe the type of the expression (ar),
as an array type.
The type of the expression (ar + 0), is a pointer type.

You can consider the entire contents of an array
as the value of the array.
But, there is no operator in C which can assign
the value of an array to another array,
and there is no operator in C which can compare
the value of one array with another.
Many thanks for the above clarification. I was getting confused by
the fact that if C does not have array value (refer
http://www.torek.net/torek/c/expr.html#therule) then how in "int ar[3]
[3]" ar[3] is having entire row (which is nothing but array of int)
as value. Now I understand I should think differently. C does have
array value but with the following rules
"there is no operator in C which can assign the value of an array to
another array, and there is no operator in C which can compare the
value of one array with another." I think this may be the reason for
Chris Torek's statement "C does not have array values".
 
J

James Kuyper

James Kuyper wrote: ....

From this:
n1570
6.7.9 Initialization
Semantics
8 An initializer specifies the initial value stored in an object.
I would construe that the entire contents of an array,
is the value of an array.

6.7.9p10 says: "-- if it is an aggregate, every member is initialized
(recursively) according to these rules,"
6.7.9p14 says: "Successive bytes of the string literal (including the
terminating null character if there is room or if the array is of
unknown size) initialize the elements of the array.". 6.7.9p15 say the
same for arrays of wchar_t, char16_t, and char32_t.

Therefore, I think it's more appropriate to consider 6.7.9p8 to be
referring what happens recursively to the elements of an array, rather
than implying that the array as a whole has a value.

However, your formulation: that a array has a value, but that C provides
no mechanism for reading or writing that value, only mechanisms for
reading or writing individual elements of the array, is a workable
alternative interpretation.
 
J

James Kuyper

This declaration
� � {char ar[3][7];}
declares an array of 3 arrays of 7 char.
The 3 arrarys are ar[0], ar[1], and ar[2].
The size of each of those 3 arrays is 7 bytes.
....
... "int ar[3]
[3]" ar[3] is having entire row (which is nothing but array of int)
as value.

You've missed one point pete was trying to make. ar[0] is an array of 7
char (not int); ar[1] contains another 7 char; ar[2] contains another 7
char. However, ar[3] doesn't contain anything - there is no such object.
The expression ar[3] is legal, but only in contexts such as &ar[3],
which is equivalent to &*(ar+3), which is equivalent to ar+3, a pointer
one element past the end of the array.
 
S

somenath

This declaration
{char ar[3][7];}
declares an array of 3 arrays of 7 char.
The 3 arrarys are ar[0], ar[1], and ar[2].
The size of each of those 3 arrays is 7 bytes.
...
... "int ar[3]
[3]" ar[3] is having entire row  (which is nothing but array of int)
as value.

You've missed one point pete was trying to make. ar[0] is an array of 7
char (not int); ar[1] contains another 7 char; ar[2] contains another 7
char. However, ar[3] doesn't contain anything - there is no such object.
The expression ar[3] is legal, but only in contexts such as &ar[3],
which is equivalent to &*(ar+3), which is equivalent to ar+3, a pointer
one element past the end of the array.
Thanks for correction. Actually I was trying to say if we had
declaration as int ar[3][3] then what would have happen. But then also
I should have not written "value of ar[3]" instead should have
written "value of ar[2]".
Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top