#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
Related
On basis of the convention int (*o)[5]=&s; is the right way for a pointer o to point an array having 5 elements.
We can also write this s in this statement
int (*p)[10]=s;
but why preferring
&s at int (*o)[5]=&s;
as both of them return the same output.
#include <stdio.h>
int main()
{
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
printf("%d\n",*p);
printf("%d\n",**p);
printf("%d\n",&s);
printf("\n");
int (*o)[5]=&s;
printf("%d\n",*o);
printf("%d\n",**o);
printf("%d",&s);
return 0;
}
Output of this program is:
-593812272
10
-593812272
-593812272
10
-593812272
This is not valid:
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
Because you're initializing a variable of type int (*)[10] (a pointer to an array of int of size 10) with an expression of type int *. These types are not compatible.
While this is fine:
int (*o)[5]=&s;
Because the type of the initializer matches the type of the variable.
Also, when printing pointer values, you should use the %p format specifier and cast the argument to void *. Mismatching format specifiers with their associated arguments triggers undefined behavior.
This line
int (*p)[10]=s;
is incorrect. The initializer has the type int * due to the implicit conversion of the array designator s to a pointer to its first element. And the two pointers in the left hand side and in the right hand are not compatible. So the compiler should issue a message.
This line
int (*o)[5]=&s;
is correct. The initializer has the type int ( * )[5] that is the same type of the initialized pointer o.
Pay attention to that to output a value of a pointer you have to use the conversion specifier %p. Otherwise using the conversion specifier %d to output a pointer invokes undefined behavior.
So for example instead of these calls
printf("%d\n",*o);
//...
printf("%d",&s);
you have to write
printf("%p\n", ( void *)*o);
//...
printf("%p\n", ( void * )&s);
The expression *o yields value of the array s that is in turn is implicitly converted to a pointer to its first element.
The values of the expression *o and of the expression &s are the same because it is the address of the extent of memory occupied by the array. But their types are different. The first expression used as an argument of the call of printf has the type int * while the second expression has the type int ( * )[5].
I am getting incompatible type error at line 14 when passing the pointer of the integer to another function. Can anybody explain me why and how to solve this problem.
#include<stdio.h>
int check_similar(int *pa, int *pb);
int main()
{
int a[5], b[5], i;
for (i=0; i<5; i++){
scanf("%d", &a[i]);
}
for (i=0; i<5; i++){
scanf("%d", &b[i]);
}
if (check_similar(&a, &b))
printf("Strictly identical");
else
printf("Not identical");
}
int check_similar(int *pa, int *pb)
{
int i=0;
while (*(pa+i)==*(pb+i)){
i++;
}
if (i==5)
return 1;
else
return 0;
Because a and b are defined as:
int a[5], b[5]
The symbol for each points to the the first element of the array, therefore satisfying the need for passing the address of the argument without using the address of operator & :
if (check_similar(&a, &b))
^ ^
The incompatible type error you are seeing is because by using the & operator, the variable types passed are effectively int *[5]. (And because array types decay into simple pointer types, the called function sees each argument as int **.) The prototype requires these argument types to be int *.
Changing it to the following will address the problem:
if (check_similar(a, b))
You must pass arrays in check_similar function as it is.
check_similar(a,b);
a and b are pointers to a [0] and b [0] respectively. As such, &a and &b are pointers to pointers to a [0] and b [0] respectively.
if (check_similar(&a, &b))
Since arrays, when passed as an argument to a function, decay to a pointer to the first element by default:
"Except when it is the operand of the sizeof 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. If the array object has register storage class, the behavior is undefined."
Source: C18, §6.3.2.1/3
using the & operator to that pointer gains a pointer of type int (*)[5], but check_similar expects int * as arguments.
That is the pointer mismatch, the incompatible pointer error referred to.
Simply omit the &s:
if (check_similar(a, b))
and everything is fine.
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.)
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*.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
int a[3][4] = {
1,2,3,4,
5,6,7,8,
9,10,11,12,
};
printf("%u %u %u \n", a[0]+1, *(a[0]+1), *(*(a+0)+1));
Time for a crash course on arrays in C.
First of all, let's fix the initializer for the array:
int a[3][4] = {
{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12}
};
This defines a 3-element array of 4-element arrays of int. The type of the expression a is "3-element array of 4-element arrays of int".
Now for the headache-inducing part. Except when it's the operand of the sizeof or unary & operators, or if it's a string literal being used to initialize another array in a declaration, an expression of array type will have its type implicitly converted ("decay") to a pointer type.
If the expression a appears by itself in the code (such as in a statement like printf("%p", a);, its type is converted from "3-element array of 4-element array of int" to "pointer to 4-element array of int", or int (*)[4]. Similarly, if the expression a[i] appears in the code, its type is converted from "4-element array of int" (int [4]) to "pointer to int" (int *). If a or a[i] are operands of either sizeof or &, however, the conversion doesn't happen.
In a similar vein, array subscripting is done through pointer arithmetic: the expression a[i] is interpreted as though it were written *(a+i). You offset i elements from the base of the array and dereference the result. Thus, a[0] is the same as *(a + 0), which is the same as *a. a[i][j] is the same as writing *(*(a + i) + j).
Here's a table summarizing all of the above:
Expression Type Decays To Resulting Value
---------- ---- --------- -----
a int [3][4] int (*)[4] Address of the first element of the array
&a int (*)[3][4] n/a Same as above, but type is different
*a int [4] int * Same as above, but type is different
a[0] int [4] int * Same as above
*(a+0) int [4] int * Same as above
a[i] int [4] int * Address of the first element of the i'th subarray
*(a+i) int [4] int * Same as above
&a[i] int (*)[4] n/a Same as above, but type is different
*a[i] int n/a Value of the 0'th element of the i'th subarray
a[i][j] int Value of the j'th element of the i'th subarray
*(a[i]+j) int Same as above
*(*(a+i)+j) int Same as above
Hopefully, that should give you everything you need to figure out what the output should be. However, the printf statement should be written as
printf("%p %d %d\n", (void *) a[0]+1, *(a[0]+1), *(*(a+0)+1));
$ gcc -Wall -o output output.c
output.c: In function ‘main’:
output.c:5:5: warning: missing braces around initializer [-Wmissing-braces]
output.c:5:5: warning: (near initialization for ‘a[0]’) [-Wmissing-braces]
output.c:9:5: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat]
because the 2-dimensional array is initialized as though it had only one dimension.
Complete program, for reference:
#include <stdio.h>
int main()
{
int a[3][4] = {1,2,3,4,
5,6,7,8,
9,10,11,12,
};
printf ("%u %u %u \n", a[0]+1, *(a[0]+1), *(*(a+0)+1));
return 0;
}
First of all, your initialization is wrong: your initializer it for one-dimensional array, whereas you declare a two-dimensional one.
Second, let's see what does your code do.
a is a two-dimensional array, so a[0] is of type int[4] (one-dimensional array), and represents the 0-th column of the multidimensional array, and is (mostly) the same as a pointer to the column's leading element. Now you use address arithmetics: a[0] + 1 is the pointer to element after the leading one in the 0-th column (represented as a pointer to it), that is, pointer to the 1-st element in the 0-th column. That's where the second warning appears, saying that your argument to printf is int* and not unsigned int.
Next, *(a[0]+1) dereferences the pointer to the 1-st element of the 0-st column. This is (as usually) equivalent to a[0][1].
Next, *(*(a+0)+1)) is the same, because *(a+0) is the same as a[0].
(In order to understand this all, you need to know some basics: that in C *(x + y) is the same as x[y], and that the 1-dimensional array is essentially the same as the pointer to its leading element.)
About the difference between your book and the reality: the first output value is just a pointer, so it can be an arbitrary value, depending on where your array happened to be in the memory. About the other two values, the question depends on how the array was filled by the wrong initializer.