C void pointer with ternary operator - c

I have a problem with a void pointer in use with a ternary condition operator.
In case of:
int x = 5;
void * pointer = &x;
printf("x: %d \n", 1 == 1 ? (*((int*)pointer)) : (*((char*)pointer)));
It writes to console the number 5, whitch is correct activity. But when I change in last line char to double:
printf("x: %d \n", 1 == 1 ? (*((int*)pointer)) : (*((double*)pointer)));
Then it writes 0 and I don't know why. I know I can use if-else instead of it but I'm just curious why it is working that way. Could anyone help me?

The result of a ternary expression is the common type of the two branches. In the case of one branch being an int and the other a double then the result will be a double as well.
And you don't print a double value, you attempt to print an int value. Mismatching format specifier and value will lead to undefined behavior.
For more information see e.g. this conditional operator reference.

You should use %lf instead of %d
int x = 5;
void * pointer = &x;
printf("x: %lf \n", 1 == 1 ? (*((int*)pointer)) : (*((char*)pointer)));

Related

Pointers in ternary operator

When I use a pointer in ternary operator if condition is true it executes exp3
#include <stdio.h>
int main(){
int a,b;
printf("Enter first number:");
scanf("%d",&a);
printf("Enter second number:");
scanf("%d",&b);
printf("Address of a:%u \n",&a);
printf("Address of b:%u \n",&b);
int *ptr=&b;
// when i use pointer in ternary operator if condition is true it execute exp3
// problem in this line
(*ptr++) > (*ptr) ? printf("\n %d is the maximum number",b):printf("\n %d is the maximum number",a);
(a>b) ? printf("\n %d",a) : printf("\n %d",b);
return 0;
}
There are several issues in your code that cause undefined behaviour (UB). The first is that you are using pointer arithmetic inappropriately. Operations like incrementing, decrementing and comparisons are only really useful on pointers to elements of arrays. In your case, neither a nor b is an array (although, from the compiler's perspective, they can be treated as single-element arrays), so there is no obligation on the compiler to follow any specific relative memory arrangement for those variables: they could be adjacent in memory, or separated by any number of bytes; and, even if they are adjacent, they could be "either way round" (that is, either a or b could be in the lower address).
We can create a 'quick workaround' in your code for this, by declaring an actual array and then make the a and b tokens aliases for elements of that array:
// int a, b;
int data[2];
#define a (data[0])
#define b (data[1])
Another cause of UB is the use of the wrong printf format specifier when showing your pointers; pointers should be printed using the %p specifier and, even then, should really be cast to void* when passed as arguments to printf:
printf("Address of a:%p \n", (void*)&a);
printf("Address of b:%p \n", (void*)&b);
But the third – and perhaps most important – source of UB occurs in the "condition" expression of your conditional ('ternary') operator: the (*ptr++) > (*ptr) comparison.
For this expression, the C Standard does not specify which of the operands of the > is evaluated first (i.e. the > operator is not a sequence point). So, expanding how the compiler might interpret this, using intermediate variables, we could get this:
T1 = (*ptr++); // T1 will get the value of "a", then "ptr" is incremented
T2 = (*ptr); // T2 will get the value of "b"
if (T1 > T2) ... // This will now be equivalent to the "a > b" comparison
Alternatively, the compiler would be equally entitled to do this:
T1 = (*ptr); // T1 will get the value of "a"
T2 = (*ptr++); // T2 will ALSO get the value of "a" and THEN 'ptr' is incremented
if (T1 > T2) ... // This will now be equivalent to the "a > a" comparison - which is wrong
We can resolve this UB by explicitly using intermediate variables like those above:
int T1 = *ptr++;
int T2 = *ptr;
T1 > T2 ? printf("\n %d is the maximum number", b) : printf("\n %d is the maximum number", a);
But note, even then, your code will show the wrong answer, because of the way the post-increment is applied (that is, after the value of *ptr has been assigned to T1).
If you must use pointers in your code, then avoid the post-increment and just use a simple addition to get the address of b (or the second element) and thus leaving ptr unchanged when using it to refer to a (the first element):
*(ptr+1) > *ptr ? printf("\n %d is the maximum number", b) : printf("\n %d is the maximum number", a);

can somebody explain why does my first print 0, but after *p = 6.35, it can print 6.35?

#include <stdio.h>
void print_binary(int n);
void test();
int main(){
test();
return 0;
}
void print_binary (int n){
unsigned int mask = 0;
mask = ~mask^(~mask >> 1);
for (; mask != 0; mask >>= 1){
putchar ((n & mask) ? '1' : '0');
}
}
void test(){
int x;
float *p;
p = (float *) &x;
printf ("x init value :%d\n", x);
printf ("addr x and p are %p %p\n", &x, p);
printf ("print x in bit ");
print_binary(x);
printf ("\n");//00000000000000000000000000000000
*p = 6.35;
printf ("print x in bit ");
print_binary(x);
printf ("\n");//01000000110010110011001100110011
printf ("x after 6.35 value :%d\n", x);//1087058739
printf ("call1 x:%.100f\n", x);//0.0000000.....
printf ("x:%d\n", x);//1087058739
printf ("call2 x:%f\n", x);//0.000000
printf ("p:%f\n", *p);//6.350000
printf ("call3 x:%f\n", x);//6.350000
}
Results:
x init value :0
addr x and p are 0x7ffc37d5ba8c 0x7ffc37d5ba8c
print x in bit 00000000000000000000000000000000
print x in bit 01000000110010110011001100110011
x after 6.35 value :1087058739
call1 x:0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
x:1087058739
call2 x:0.000000
p:6.350000
call3 x:6.350000
I print my x after *p = 6.35;, and
in the memory, we get 01000000110010110011001100110011, this is the right number according to the IEEE754,
could someone explain why my first printf ("call1 x:%.100f\n", x) print me 0.00...,
but after I printf ("p:%f\n", *p), it can print the 6.35 ?
Dereferencing p is undefined behavior, since p is not pointing to a float, but to an int (ref. eg. What is the strict aliasing rule?).
Also, trying to print an int with the "%f" format specifier is undefined behavior, since that format specifier expects a double (ref. eg. Why does printf("%f",0); give undefined behavior?).
So, you can't rely on any behavior of this code - anything is possible.
In practice, what's probably happening, is that the compiler decided to move *p = 6.35; to right before printf ("p:%f\n", *p);.
From your tags (type-conversion and implicit conversion) you seem to expect some type conversion to happen.
This is not the case.
Accessing memory with ill-typed pointer does not trigger any conversion to happen. It simply interpretes the memory in a different way. This includes violating the strict aliasing rules causing undefined behaviour.
And when you use
printf ("call1 x:%.100f\n", x);//0.0000000.....
you are cheating your compiler.
You promise to pass a double value (%f format specifier) which typically holds 8 bytes but then you only pass 4 bytes of an integer.
Mismatch in type specifier and parameter type causes undefined bahaviour and all expectations are worhless.
Then again you use
printf ("p:%f\n", *p);//6.350000
which works fine as you provide the proper double parameter. (here is the only implicit type conversion)
Your compiler should print some warnings when you try to compile this code.
And you should always listen to the compiler and resolve the warnings.

Pointer not printing in the desired way

This is a C code
int (*a)[3];
a is a pointer to an array of 3 integers
a=(int (*)[3])malloc(sizeof(int)*3);
note the Typecast used here; the number of elements must be specified in the typecast shown. Also, the brackets around the * is necessary.
printf("brrbrrbrr %d %d %d %d\n",&a,a,a+1,a+2);
*(a+0)[0]=40;
*(a+0)[1]=41;
*(a+0)[2]=42;
printf("noobnoob %d %d %d \n",a[0][0],*(a+0)[1],(*(*(a+0)+2)));
The output is:
brrbrrbrr -7077000 29278656 29278668 29278680
noobnoob 40 41 0
I am not getting why the last number is 0 instead of 42?
Indexation has higher precedence than dereferencing a pointer. Your assignments don't do what you want. They are evaluated like:
*((a+0)[0])=40;
*((a+0)[1])=41;
*((a+0)[2])=42;
If you want to keep your syntax, you shall use parenthesis like:
(*(a+0))[0] = 40;
(*(a+0))[1] = 41;
(*(a+0))[2] = 42;
The same applies for printing the second element of the array. *(a+0)[1] shall be (*(a+0))[1].
What you are looking for is
int (*a)[3] = malloc(sizeof(int) *3);
(*a)[0] = 40;
(*a)[1] = 41;
(*a)[2] = 42;
printf("%d %d %d\n",(*a)[0],(*a)[1],(*a)[2]);
a is a pointer to an array of 3 int members. So allocate memory for the pointer and store values as shown above.
If you want the address of where the values are stored then you should do
printf("%p\n",(void*)(a)[0]);

pre-increment and post-increment in printf

int main()
{
int value = 4321;
int *ptrVal = &value;
printf("%d %d",++value,(*(int*)ptrVal)--);
return 0;
}
How does pre-increment/post increment works in above print statement ?
And why is answer 4321 4321 ?
You are modifying the object value twice between two sequence points: you are invoking undefined behavior. Undefined behavior means your program can print 4321 4321, print 42 or even just crash.
A correct version of your program would be:
int value = 4321;
int *ptrVal = &value;
++value;
(*ptrVal)--; // no need to cast to int *
printf("%d %d", value, *ptrVal); // same as printf("%d %d", value, value);
Of course you don't need any temporary pointer to achieve this.
The code above is just broken. It is unspecified how it will work or what the answer will be. You need a sequence point between modifications or modifications and accesses.

Pointers for 2D arrays

This is a question from Microsoft Test:
main()
{
int a[2][3]= { (1,2,3),(4,5,6)};
int (*ptr)[3] = &a[0];
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
ptr+=1;
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
}
Options given are:
segmentation fault
compiler error
bus error
run time error
I ran this code and I didn't get any of this. I got the following answer:
6 0
0 0
Can you please help me understand what's happening?
The main issue is this line:
int a[2][3]= { (1,2,3),(4,5,6)};
It is using parentheses instead of braces. The result of (1,2,3) is just 3, and the result of (4,5,6) is just 6. So this is equivalent to:
int a[2][3]= { 3,6 };
Which in turn is equivalent to
int a[2][3] = { {3,6,0}, {0,0,0} };
This line makes ptr point to a[0]:
int (*ptr)[3] = &a[0];
This line
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
is then equivalent to
printf("%d %d\n", (*&a[0])[1],(*&a[0])[2]);
which can be simplified to
printf("%d %d\n", (a[0])[1],(a[0])[2]);
or just
printf("%d %d\n", a[0][1],a[0][2]);
This line
ptr+=1;
makes ptr point to the next element of a, so it is equivalent to
ptr=&a[1];
so the next line simplifies to
printf("%d %d\n", a[1][1],a[1][2]);
The program effectively prints a[0][1], a[0][2], a[1][1] and a[1][2], so that's why you get 6,0,0,0.
Charles Baley points out that main() is missing the return type. This may be what they are getting at. The compiler would normally at least give a warning about that.
Are you sure you copied the text correctly?
(1,2,3) is an expression with two sequence or comma (,) operators; its value is 3. Likewise, the value of (4,5,6) is 6. This is the 6 that is being printed at a[0][1] (since ptr points to a[0] and you print (*ptr)[1]); the 0 is a[0][2], which has default initialization of 0. Then you increment ptr, pointing it to a[1], so you print a[1][1] and a[1][2], which also have default initialization of 0.

Resources