I have a program below ...I have a turbo c compiler so int is 2 bytes..
#include<stdio.h>
main()
{
int a[3][2]={
{1,3},
{2,0},
{3,4}
};
printf("%d",(a+1)); //increments 2 bytes
printf("%d",(&a[0]+1)); // increments 4 bytes
printf("%d",(a[2]));
return 0;
}
What is the difference between a+1 and &a[0]+1 ?
They are equivalent expresssions.
a + 1 and &a[0] + 1 values are the same and they are both of type int (*)[2].
Note that you are not correctly printing the pointer values: use p conversion specifier and cast the argument to (void *) to print the value of a pointer:
printf("%p\n", (void *) (a + 1));
printf("%p\n", (void *) (&a[0] + 1));
printf("%p\n", (void *) (a[2]));
Your compiler appears to have a bug. If a names an array then in [most] expressions a and &a[0] should have the same type and value so the result of the +1 should be identical in both cases.
a+1 and &a[0]+1 should both be equivalent to &a[1].
To be strictly correct when testing this you should use %p as a format specifier for displaying pointer values.
a names the array int a[3][2], so it has the type int [3][2]. In the expression a + 1 it decays to a pointer to the first element, which is therefore of type int (*)[2].
In the expression &a[0], a again decays to a pointer of type int (*)[2], so a[0] has the type int [2]. The address-of operator is a special case in that it does not provoke pointer decay, so &a[0] has type int (*)[2] and has the same type and value as the decayed a.
At a guess, I'd speculate that your compiler is incorrectly decaying a[0] in &a[0], so that it's giving &a[0] the type int **. If data pointers on your platform are 4 bytes in size then that would explain the observed result.
Related
This question was asked in my Sem-2 examination. Question asked us to give the desired output.
int main(void)
{
int a[] = {10,20,30,40,50,60};
int (*p1)[2]=a , (*p2)[3]= a;
if(sizeof(p1)==sizeof(p2))
printf("%d",*(*p1+2));
if(sizeof(*p1)==sizeof(*p2))
printf("%d",*(*(p2+1)));
return(0);
}
Compiler warnings:
Warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
initialization from incompatible pointer type [-Wincompatible-pointer-types]
Output that I expect: 20
Output that I get when I run it: 30
Using : gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Let's ignore the undefined behavior to work out what is probably happening.
p1 and p2 are both pointing to a[0] (ignoring the incompatible pointer types).
p1 and p2 are both pointers. Pointers to object types are generally the same size (assume this is the case), so sizeof(p1)==sizeof(p2) will be true.
p1 is of type int (*)[2], so *p1 is of type int[2]. In most expressions, an array will decay to a pointer to its first element, so in the expression *(*p1+2), *p1 will decay to an int * and will be pointing to a[0]. Therefore *p1+2 will be pointing to a[2]. Therefore *(*p1+2) will be the same as a[2], which has the value 30. Therefore the program prints 30.
An array does not decay to a pointer when it is the operand of the sizeof operator. *p1 is of type int[2] and *p2 is of type int[3], so sizeof(*p1)==sizeof(*p2) is equivalent to sizeof(int[2])==sizeof(int[3]), which is false. Therefore the second printf call that prints the value of *(*p2+1) is not evaluated.
(Let's pretend the second printf is called and that *(*p2+1) is evaluated. *p2 is of type int[3] and in this expression it decays to an int * pointing to a[0]. Therefore *p2+1 points to a[1]. Therefore, *(*p2+1) will be the same as a[1], which has the value 20.)
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%u %u ",a ,&a); //a
printf("%d %d ", *a ,*&a); //b
}
In ath line the output of a and &a are same address but in bth line *&a does not give me the answer as 1.
I know that &a means pointer to array of integers but as the address is same, it should print 1 right?
a decays to the pointer to the first element of the array.
&a is the pointer to the array of 4 ints.
Even though the numerical values of the two pointers are the same, the pointers are not of the same type.
Type of a (after it decays to a pointer) is int*.
Type of &a is a pointer to an array of 4 ints - int (*)[4].
Type of *a is an int.
Type of *&a is an array of 4 ints - int [4], which decays to the pointer to the first element in your expression.
The call
printf("%d %d ", *a ,*&a);
is equivalent to:
printf("%d %d ", *a , a);
BTW, You should use %p for pointers. Otherwise, you invoke undefined behavior. Increase the warning level of your compiler to avoid making such errors.
Taking a simpler version of your code as follows:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
printf("%d %d ", *a ,*&a); //b
}
If I compile that code I get this warnings:
test1.c
D:\Temp\test1.c(7): warning C4477:
'printf' : format string '%d' requires an argument of type 'int', but variadic
argument 2 has type 'int *'
Microsoft (R) Incremental Linker Version 14.00.23506.0
Copyright (C) Microsoft Corporation. All rights reserved.
That warning message gives you the reason why this is not working as you expect.
Now I can change that code to remove those warnings and I end up with code like this:
#include <stdio.h>
void main()
{
int a[]={1,2,3,4};
int (*p)[4] = &a;
printf("\n%u %u ", *a ,*p[0]); //b
}
That code clean compiles and when it is run you get the expected output:
1 1
The latest draft of the C standard suggests that
If the operand is the result of a unary * operator,
neither that operator nor the & operator is evaluated and the result is as if both were omitted...
However, the above paragraph refers to the case when it's &*, not *&. Try to think of it this way:
&a // pointer to array[4] of integers
*(&a) // array[4] of integers
------------------------------------------
a // array[4] of integers
Note that the operator * removes single layer of pointers. Therefore, *(&a) is identical to a semantically. In this case, a is converted to an expression with the type pointer to an integer, because another paragraph suggests that
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue...
In conclusion, the fact that the address of a (not the element inside) is printed is natural.
Please do one more thing in your code:
printf("%u %u ",a+1 ,&a+1); //a1
Suppose we have
int a[2][3] ;
int (*p)[3]=a; // is ok
int (*p)[3]=&a[0]; // is also ok
but why is
int (*p)[3]=a[0];
producing errors , although a[0] gives first array's address(as 2d arrays are array of array) and seems more
okay than &a[0] which gives address of first element of first array still is ok but why?
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, 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.
Given the declaration
int a[2][3];
Then the following are true:
Expression Type Decays To Equivalent Value
---------- ---- --------- ----------------
a int [2][3] int (*)[3] &a[0]
&a int (*)[2][3] n/a n/a
*a int [3] int * a[0]
a[i] int [3] int * n/a
&a[i] int (*)[3] n/a n/a
*a[i] int n/a a[i][0]
a[i][j] int n/a n/a
Note that a, &a, *a, a[0], &a[0], and &a[0][0] all yield the same value (the address of the first element of the array is the same as the address of the array), but the types are different.
As you can see from the table above, the expression a[0] has type "3-element array of int"; since that expression is not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to int", which is not compatible with "pointer to 3-element array of int", which is why int (*p)[3] = a[0]; throws an error.
Because a[0] is not a pointer type, but an int[3] type. A block of 3 integers which can be assigned to such, but not to a pointer.
int (*p)[3]=a; // is OK
because a is of type int (*)[3] (pointer to an array of 3 ints), after decay to the first element which is also the type of p. Assignment is legal.
int (*p)[3]=&a[0]; // is also OK
because &a[0] is also of type int (*)[3] (address of the first row)
int (*p)[3]=a[0]; // is not OK
because a[0] is of type int * after decay to the first element of row 0. Assignment of different pointer types is illegal.
How a[0] can be of type int or int[3] as we have declared it a 2d array
int a[10];
printf("%p ", &a);
will display the address of array a.
So, if I perform a redirection, *(&a), why is that I don't get value stored at a[0]. What is the rule in C language that states I should be getting address of a. Yes, it does make sense, I get address of a, since * and & will cancel each other leading to simply a, which is the address of a.
int a[10];
printf("%p ", (void *) &a); // address of the array
printf("%p ", (void *) a); // adress of the first element of the array
printf("%p ", (void *) *(&a));// same as above
Here, the value of a is the same as &a[0]. And the value *&a is the same as the value of a when the a object is an array of int.
Note that the printed address will be the same as they both start at the same address.
I added the void * cast which is required as p requires a void * argument.
The C rule that governs this is C 2011 6.3.2.1 3: “Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.”
a is an array of int. When you pass a to printf, the rule converts it to a pointer to int, and the value of that pointer is printed.
When you pass &a to printf: First, a is the operand of &, so the rule does not apply; a is not converted to a pointer to int; it remains an array of int. Second, the & is evaluated. &a yields the address of the array, and this address is printed. Since the address of the array is the same as the address of its first element, the address is printed.
Note that the type of the expression &a is “pointer to array of int”. So, when you have *&a, you are applying * to a pointer to an array of int, and the result is an array of int. Since the expression is an array of int, the rule applies, and this array of int is converted to a pointer to the first element, and the value of that pointer is printed.
The fact:
a[0] == *(a)
a[9] == *(a+9)
The type of the pointer that &a evaluates to is a pointer to an array (specifically a pointer to an int[10]). That's a different type that a pointer to the first element of the array, even if it's the same address.
printf("%d ", *&a[0]); will print the value of the first element of the array because &a[0] has type int*.
Here,I have some Doubt with the output.
Why the Output is same ?
int (*r)[10];
printf("r=%p *r=%p\n",r,*r);
return 0;
Platform- GCC UBUNTU 10.04
Because Name of the array decays to an pointer to its first element.
int (*r)[10];
Is an pointer to an array of 10 integers.
r gives you the pointer itself.
This pointer to the array must be dereferenced to access the value of each element.
So contrary to what you think **r and not *r gives you access to the first element in the array.
*r gives you address of the first element in the array of integers, which is same as r
Important to note here that:
Arrays are not pointers
But expressions involving array name sometimes behave as pointer when those being used as name of the array would not make sense.
You would better understand if you look at the following program.
#include <stdio.h>
int main()
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int (*r)[10] = &a;
printf("r=%p *r=%p *(r+0)=%p *(r+1)=%p\n", r, *r, *(r+0), *(r+1));
printf("sizeof(int)=%d \n", sizeof(int));
return 0;
}
The output is as follows:
r=0xbfeaa4b4 *r=0xbfeaa4b4 *(r+0)=0xbfeaa4b4 *(r+1)=0xbfeaa4dc
sizeof(int)=4
Observations / Point(s)-to-note:
_DO_NOT_ de-reference a pointer which has not yet made to point to an address. So in your program int (*r)[10]; was de-referenced without being assigned to a memory area. This is not acceptable.
If you see the output - *r is same as *(r+0) which is same as r (only w.r.t this case)
If you see the output for *(r+0) and *(r+1) it is 40 bytes (0xbfeaa4dc - 0xbfeaa4b4 = sizeof(int) * size of the array (which is 10 in this case). So when you increment a pointer to a particular type, it gets incremented to sizeof(type) bytes!
the other worth-notable points about a pointer-to-an-array-of-integers are explained here
Hope this helps!
Remember that when an expression of type "N-element array of T" appears in most contexts, it will be converted to an expression of type "pointer to T" and its value will be the address of the first element in the array. The exceptions to this rule are when the array expression is an operand of either the sizeof or unary & (address-of) operands, or if the array expression is a string literal being used as an initializer in an array declaration.
Your situation is a mirror image of the following:
int a[10] = {0};
printf("a = %p, &a = %p\n", (void *) a, (void *) &a);
In the printf call, the expression a has its type converted from "10-element array of int" to "pointer to int" based on the rule above, and its value will be the address of the first element (&a[0]). The expression &a has type "pointer to 10-element array of int", and its value will be the same as a (the address of the first element in the array is the same as the address of the array itself).
Your code has a bit of undefined behavior in that you're dereferencing r before it has been assigned to point anywhere meaningful, so you can't trust that the output is at all accurate. We can fix that like so:
int a[10] = {0};
int (*r)[10] = &a;
printf("r = %p, *r = %p\n", (void *) r, (void *) *r);
In this case, r == &a and *r == a.
The expression r has type "pointer to 10-element array of int", and its value is the address of a. The expression *r has type "10-element array of int, which is converted to "pointer to int", and its value is set to the address of the first element, which in this case is a[0]. Again, the values of the two expressions are the same.