...then why is the code below give same value (meatballs) for address and the actual content? And how to make sense of %d value of meatballs, is it random?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
meatballs);
return 0;
}
meatballs is an array, and it has type int[5]. However C doesn't allow passing arrays by value, so array decays into pointer for function call. This is equivalent of pointer to first element of array &meatballs[0], and it has type int*.
&meatballs is a pointer to an array, and it has type int(*)[5]. Since it's a pointer it can be passed to a function.
As you can see, both 1. and 2. return same address, but they have different types: pointer to integer array vs pointer to single integer.
Note: Types void* and int* don't necessarily have the same representation(1), and for %p only valid type is void*(2) or you will get undefined behaviour(3). Always convert pointer to void* when printing addresses:
printf("%p %p", (void*)meatballs, (void*)&meatballs);
Last situation is same as first, but you are using wrong type specifier %d. Resulting type is again int* as in case 1, but it is interpreted as int. This is clear undefined behaviour, and output is garbage.
To print integer array element, use any of the following methods:
printf("%d %d %d", meatballs[i], *(meatballs + i), *meatballs);
First two will print array element at index i, and last will print first element. I recommend using the meatballs[i] in most cases, as it's most clear.
References to C standard (draft):
N1570, 6.2.5 paragraph 28
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.48)... ...Pointers to other types need not have the same representation or alignment requirements.
N1570, 7.21.6 paragraph 8
p The argument shall be a pointer to void. ...
N1570, 7.21.6 paragraph 9
... If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
You have to use the unary dereference operator *, so that the actual value is shown as %d expects an integer.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
*meatballs);
return 0;
}
Look at the last parameter: *meatballs. This code actually prints 1 as value and is the first element in your array. So your guess is right and it is only a bug.
Related
This question already has answers here:
what does it mean to convert int to void* or vice versa?
(6 answers)
Closed 28 days ago.
I was practicing with void pointers when this code successfully compiled:
#include <stdio.h>
int main()
{
void *x = (void*) 576;
int *y = x;
printf("%d\n", y);
return 0;
}
I don't understand this. How can the literal 576 be type-casted to a void pointer? Additionally, notice how in the printf() function call, the dereference operator is missing from y. And yet it prints the value 576. And when I add the dereference operator to y, nothing prints to the terminal.
After a bit of research, I found out that NULL is just the literal 0 type-casted to a void pointer. Can anything be type-casted to a void pointer? Is the code I posted up dangerous?
A pointer of the type void * may be converted to a pointer of other object type.
From the C Standard (6.3.2.3 Pointers)
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
As for this call
printf("%d\n", y);
then you are trying to output a pointer using the conversion specifier %d that is designed to output integers. As a result such a call invokes undefined behavior.
If you want to output a pointer you need to use conversion specifier %p as for example
printf("%p\n", ( void * )y);
If you want to output a pointer as an integer you need to include headers <stdint.h> and <inttypes.h> (the last header already contains the first header) and to write like
#include <stdint.h>
#include <inttypes.h>
//...
printf( "%" PRIuPTR "\n", ( uintptr_t )y );
What is difference between %d and %p when printing?
For example:
int main() {
int a = 9;
printf("%d\n", &a);
printf("%p\n", &a);
return 0;
}
The printf function supports different conversions for different types of arguments: %d produces a decimal representation (d for decimal) for an argument of type int, %p produces a system dependent representation of a void pointer (p for pointer)
There are multiple problems in your code:
you pass the address of an int variable, hence a type int * where printf expects an int for the %d conversion: This has undefined behavior
you pass the address of an int variable, hence a type int * where printf expects an void * for the %p conversion: This has undefined behavior
you did not include <stdio.h> and you call the function printf without a proper prototype: the prototype inferred from the call is incompatible with the actual definition, so the behavior is undefined.
The output you observe is the result of undefined behavior: it is unpredictable and potentially irreproducible: on my system, I get different output every time I run the program, even without recompiling. Undefined behavior means anything can happen.
Here is a modified version:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main() {
int a = 9;
printf("%d\n", a);
printf("%p\n", (void *)&a);
printf("0x%"PRIxPTR"\n", (uintptr_t)&a);
printf("%p\n", (void *)NULL);
printf("0x%"PRIxPTR"\n", (uintptr_t)NULL);
return 0;
}
Output:
9
0x7fff54823844
0x7fff54823844
0x0
0x0
The last conversion takes a uintptr_t, an integer type large enough to store an integer representation of a pointer. On my system, OS/X, the %p conversion produces the same output as 0x%x for the corresponding integer type.
Will output something like:
-1807747332,
00000083943ff6fc
The format specifier converts the value of the corresponding variable to the format data type. %d converted it to a signed integer. If you use %p it simply treats the value as the memory address of a pointer and prints it in hexadecimal.
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 was expecting the code below to print 4 (since a float is 4 bytes), but it prints 1. Would someone explain why this happens?
#include <stdio.h>
int main()
{
float a[4]={0.0,0.1,0.2,0.3};
printf("%d", &a[1]-&a[0]);
return 0;
}
First of all, change
printf("%d", &a[1]-&a[0]);
to
printf("%td", &a[1]-&a[0]);
as the result type of two subtraction yields a type ptrdiff_t and %td is the conversion specifier for that type.
That said, quoting C11, chapter §6.5.6, subtraction operator (emphasis mine)
When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. [....] In
other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of
an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. [....]
In your case, P is &a[1] and Q is &a[0], so i is 1 and j is 0. Hence the result of the subtraction operation is i-j, i.e., 1-0, 1.
You are correct that the two pointers are 4 bytes apart. And if you were subtracting two integers you'd get 4. But &a[1] and &a[0] are of type float *. Pointer arithmetic in C takes into account the size of the thing being pointed to, so &a[1]-&a[0] is 1.
This is the basic means by which array indexing works. You can take advantage of this to iterate through an array without needing a separate index and instead terminating on a boundary such as NaN.
#include <stdio.h>
#include <math.h>
int main()
{
float a[] = { 0.0,0.1,0.2,0.3,NAN };
float *iter = a;
while(!isnan(*iter)) {
printf("%f\n", *iter);
iter++;
}
}
If you instead cast the values to unsigned int you will indeed get 4.
printf("%u\n", (unsigned int)&a[1]-(unsigned int)&a[0]);
#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