0

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;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • Referring to the previous comment: also be aware that `ptr[1]` is strictly the same thing as `*(ptr+1)` – Jabberwocky Jan 19 '23 at 10:08
  • 1
    @Lundin `ptr[1]` would cause undefined behaviour (out of bounds access) – M.M Jan 19 '23 at 10:29
  • 1
    @M.M Ah yeah... it is actually not clear why they want to increment the pointer at all. – Lundin Jan 19 '23 at 10:46
  • It's quite unclear what `exp3` is. What are you actually trying to achieve? What output do you expect? Show an example of input and expected vs. actual output. Please [edit] and clarify. – Jabberwocky Jan 19 '23 at 10:59
  • 3
    The condition `(*ptr++) > (*ptr)` is undefined behaviour so any result is legitimate. There is no guarantee that the local variables `a` and `b` are adjacent to each other (though they probably are), nor is there any guarantee about which order they are stored in (though again, you've probably determined that sequence). But the UB leaves your code unreliable. – Jonathan Leffler Jan 19 '23 at 13:06

1 Answers1

1

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);
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • @EricPostpischil Actually `*ptr++` is well-defined as well. `*ptr++ > *ptr` is not, nor is `*(ptr+1)` or `ptr[1]` or `*++ptr`. There's the sequencing UB and the out-of-bounds UB. But `int x; int* ptr = &x; *ptr++;` is well-defined, since we may point one item past from our "array" of one item, long as we don't de-reference that location. `*ptr++` de-references array index `0`. – Lundin Jan 19 '23 at 15:57