-1

I was playing around with pointer arithmetic and came across two rules in C Standard regarding pointer subtraction and comparison.

Rule 1: When two pointers are subtracted, both must point to elements of the same array object or just one past the last element of the array object (C Standard, 6.5.6); the result is the difference of the subscripts of the two array elements. Otherwise, the operation is undefined behavior (48).

Rule 2: Similarly, comparing pointers using the relational operators <, <=, >=, and > gives the positions of the pointers relative to each other. Pointers that do not point to the same aggregate or union (nor just beyond the same array object) are compared using relational operators (6.5.8). Otherwise, the operation is undefined behavior (53).

Subtracting or comparing pointers that do not refer to the same array is undefined behavior.

Question 1: As per rule 1 mentioned above, the behavior is undefined, but the program does print an address as output. The program crashes when I try to dereference the the variable containing the address. How come there is an address which exists but the value the address points to does not exist?

Question 2: As per rule 2 mentioned above, using relational operator to compare two pointers which refer two different arrays is undefined behavior, the program should crash, but I end up with an output? How is that possible?

Can someone please help me regarding this rule confusion? I have posted the code below:

#include <stdio.h>

int main()
{
 char *pointer_1;
 char *pointer_2;
 char *difference;
 int counter=0;

 char string[20]={"Pointer Arithmetic"};
 char str[30]={"Substraction and Comparison"};

 pointer_1=string;
 pointer_2=str; 

 difference=(char *)(pointer_2-pointer_1);
 printf("%p\n",difference); Address exists

/*printf("%c\n",difference);*/ Dereferencing leads to program crash    

 while(pointer_1>pointer_2) Is one is allowed to use relational operators on 
                               pointers which point to two different arrays?
  {                             
    {
      counter++;
      pointer_2++;
     }
  }   

  printf("%d",counter);

}
  • 3
    Undefined behaviour != required to crash. It can do anything, including working 'properly'. – HolyBlackCat Nov 08 '17 at 19:58
  • Subtracting pointers results to an `int`. So `difference=(char *)(pointer_2-pointer_1);` does not make sense. – Constantine Georgiou Nov 08 '17 at 20:00
  • The difference between two addresses is not itself an address. As clearly stated, it is the "difference of the subscripts". Using %p does not make it one either, printf is not obliged to make your program crash. – Hans Passant Nov 08 '17 at 20:01
  • 1
    @ConstantineGeorgiou Actually `ptrdiff_t`, which a signed type that's is not necessarily `int`. – Petr Skocik Nov 08 '17 at 20:01
  • The difference between two pointers outside of a common array is only an integer if the addresses are equal modulo the type size. Otherwise no integer result is sensible. In fact optimizing compilers usually take advantage of this requrement to compute the difference using a fast a modular inverse (read: multiplication) instead of division by the type size, potentially yielding something entirely different from the rounded integer result which might otherwise be expected. – doynax Nov 08 '17 at 20:14

2 Answers2

1

Subtracting two pointers does not result in a pointer ("address"), it results in integer which is the "distance" between those pointers. This only makes sense if the pointers both point into the same array. Likewise, comparing pointers only makes sense if they are in the same array.

When it doesn't make sense, the result is undefined--that does NOT mean that the program will fail, or crash, or produce an error of any kind. It means ANYTHING may happen, and you have no right to complain.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
0

You cannot test for undefined behavior, because the result is, eh, totally undefined.

Possible outcomes include getting the expected result, crashing, getting an unexpected result, or causing time travel.

In this case, and on common desktop computers, a possible outcome of comparing two unrelated pointers pointer_1>pointer_2 is that it compares the addresses stored in the two pointers. So it "works".

On computers with a segmented memory, like a 286, a memory address is composed of a pair segment:offset. Comparing two segment values doesn't say anything about which one represents the highest memory address, as it is just an index into a segment descriptor table containing the real address.

So if your arrays are in two different segments (very common, because the segments were small), comparing the pointers for order didn't make much sense and subtracting them didn't even work.

So the language standard says that you cannot do that, because sometimes it doesn't work.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203