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.)
Related
#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
While initializing the pointer p in the given statement
int a[10], *p;
p = &a[0];
I am in doubt that whether the type of &a[0] is pointer to int or is it int?
I came to this confusion after reading this:
Using a as a pointer to the first element in the array, we can modify a[0]: *a = 7;.
NOTE: I am interested to know the type of &a[0].
&a[0] is a pointer to int. Here are the interpretation steps for that:
&a[0] is parsed as &(a[0]) because the subscript operator [] binds more tightly than the address operator &.
a is an array, but it is automatically converted to a pointer to its first element in this case. (It would not be converted if it were the operand of sizeof, _Alignof, or & or were a string literal used to initialize an array.)
a[0] takes the pointer and becomes an lvalue for the first element (element 0).
&(a[0]) is a pointer to a[0]. Since we know a[0] is an int, a pointer to a[0] is a pointer to an int.
Then p is assigned the value of &a[0]. Thus, p is a pointer to the first element of a.
Since p is a pointer to the first element of a, *p is an lvalue for that element. An lvalue can be used on the left side of an assignment to assign to the object it refers to.
for historical reasons
p = a;
and
p = &a[0]
are equivalent. Beware that
auto q = &a;
is also legal but the type of q will NOT be int* but rather int[10] *. This is probably not what you wanted.
& is the address operator so, &a[0] is taking the address of the first element of the array a, so it is an int *. Since [] has higher precedence than * you can read it as follows:
&(a[0])
which may be more clear. The case where you have:
p = a ;
works do to the array decaying to a pointer.
The address of a[0] is of type pointer to an integer.
You can modify the first element of the array because *a is equivalent to *(a + 0) which is nothing but a[0].
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.
#include<stdio.h>
int main(int argc , char *argv[])
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
printf("%d\n",*pointer);
printf("%d\n",*ppointer);
printf("%d\n",*pppointer);
printf("%d\n",*ppppointer);
return 0;
}
Four pointers are point to the first element of array.
which definition shown above is better?
And I don't known why the same value to array and &array?
The only reason all for of your definitions compile is that your C compiler is too permitting when it comes to pointer type conversions. If you use some switches that make it more pedantic in this regard, it should immediately tell you that only the third initialization is valid, while the rest are erroneous.
In most contexts (with a few exceptions) when array of type T[N] is used in an expression, it "decays" (gets implicitly converted) to pointer type T * - a pointer that points to its first element. In other words, in such contexts for any array A, the A expression is equivalent to &A[0]. The only contexts where array type decay does not occur are unary & operator, sizeof operator and string literal used as an initializer for a char array.
In your example array is a value of int [2][2] type. When used on the right-hand side of initialization it decays to pointer type int (*)[2]. For this reason this is invalid
int *pointer = array;
The right-hand side is int (*)[2], while the left-hand side is int *. These are different pointer types. You can't initialize one with the other.
The
int *ppppointer = &array[0];
is exactly equivalent to the previous one: the right-hand side produces a value of int (*)[2] type. It is invalid for the very same reason.
The &array expression produces a pointer of int (*)[2][2] type. Again, for this reason
int *ppointer = &array;
is invalid.
The only valid initialization yo have in your example is
int *pppointer = array[0];
array[0] is an expression of int [2] type, which decays to int * type - the same type that you have on the left-hand side.
In other words there's no question of which one "better" here. Only one of your initialization is valid, others are illegal. The valid initialization can also be written as
int *pppointer = &array[0][0];
for the reasons I described above. Now, which right-hand side is "better" (array[0] or &array[0][0]) is a matter of your personal preference.
In order to make your other initializations valid, the pointers should be declared as follows
int (*pointer)[2] = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2] = &array[0];
but such pointers will have different semantics from an int * pointer. And you apparently need int * specifically.
Only the third actually does the right thing. All other three are invalid C++ and cause warnings in my C compiler. It is often preferable to write C that is also valid C++, because on some platforms the C++ compiler is the also recommended compiler for C also (MSVC). This also makes it easier to include C code in a C++ project without significant build-system fiddling.
Why does your compiler complain about about 1, 2 and 4? Neither of the expressions on the right hand side have the right type to be converted to int*.
array has type int[2][2] it can be converted to int(*)[2], not int*
&array is a pointer to an int[2][2]
array[x] has actually type int*
&array[x] has type int**
int *pointer = array; //Incorrect
int *ppointer = &array; //Incorrect
int *pppointer = array[0]; //Correct
int *ppppointer = &array[0]; //Incorrect
That's the short version.
Now for the reasons.
The first pointer is incorrect, because you're assigning 'array' (which is a pointer without any further specification)...but not one of int, but one of int *[]
The second pointer is incorrect, since you'd be assigning the address of the pointer...essentially the address of the variable, which holds the pointer to the data.
The third one is correct, because you get a pointer to an int array, regardless of size.
The fourth one is incorrect, since you're copying the address of the first array.
That makes it an int **, and not a int *.
Sorry for the many edits...I must be tired.
Short answer:
$ cat decls.c
int main(void)
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
}
$ clang decls.c -Wall -o decls
decls.c:4:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int [2][2]' [-Wincompatible-pointer-types]
int *pointer = array;
^ ~~~~~
decls.c:5:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
int *ppointer = &array;
^ ~~~~~~
decls.c:7:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2]' [-Wincompatible-pointer-types]
int *ppppointer = &array[0];
^ ~~~~~~~~~
So only the third declaration is correct.
Slightly long answer: when you declare something in C, you declare it using an expression which, when evaluated, gives you the type at the left.
So, if you have a char name[][], then it means that when you have name[2][3], you get a char. This works the other way around: let A = name[3]; how can you can get a char out of A? By doing A[2], so A is a char *.
This is why only the third declaration is correct: because the declaring expression at the left and the expression at the right both have the same type.
None of them are correct (third one will not give error but I don't think it will be the value the poster want).
It should be:
int ** pointer1 = array;
int ** pointer2 = &array; //This one is wrong
int ** pointer3 = array[0]; //This one is not correct in this case
int * ppointer3 = array[0];
int ** pointer4 = &array[0];
int * pointer5 = &array[0][0];
I prefer the first one and last one.
If it is a 1-dimensional array, I would prefer the first one, because it shows the fact that array is basically pointer. If it is a multi-dimensional array, I would use the last one (because it only needs dereference once to get the value, but be careful about the index: for example if you want to get 1000, you will need to use pointer5[2] instead of pointer5[1][1]
They are all equivalent.
&array is the address of the array, which start at the same position as its first element and therefor &array = &array[0]
array is an array but in some case, it can decay into a pointer to its first element, that is why array = &array = &array[0]
As for
int *pppointer = array[0];
my first impression is that this should be wrong. may be someone else can explain.
Update: My guess is that array is considered as a pointer by the compiler here giving:
int *pppointer = (&array)[0] = array[0]
So, you have an array within an array. So the variable "array" is actually a pointer to another pointer.
So if you say:
int *pointer = array;
You've got a type mismatch. *pointer is a pointer to an int, but array is a pointer to another pointer.
When you say:
int *ppointer = &array;
You've still got a type mismatch. &array gives us the address of the pointer to a pointer, which we could only assign to a pointer to a pointer to a pointer.
When you say:
int *pppointer = array[0];
This is correct. Square brackets dereference the array variable. So array[0] actually refers to a pointer to an int, which matches up with *pppointer's type.
When you say:
int *ppppointer = &array[0];
So, we're kind of back to where we started here. array[0] is a pointer to an int, so &array[0] is the address of a pointer to an int, which we could only assign to a pointer to a pointer to an int.
So in the end, the third one is the only one that is actually valid. However, I personally think a better way to accomplish this would be:
int *pointer = *array;
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.