DEV Community

Discussion on: Pointer in C/C++

Collapse
 
pentacular profile image
pentacular

Do you remember that a int data type takes 2 or 4 bytes Storage in memory ?

This is incorrect.

sizeof (int) is >= 1.

It is not required to be 2 or 4.

(Note that byte in C/C++ is defined to be char, and char may have more than 8 bits).

WTF??
We can say pa is now pointed to x variable or pointed to the memory address 0x7fffbabdb6f4 which is same as the pointer px
And the is something more to notice that the memory location of var was 0x7fffbabdb6f0 and memory location of x was 0x7fffbabdb6f4.
Look closely find something amazing ? The last two digits f0 and f4 ! coincidence ?? Noh!
Do you remember that a int data type takes 2 or 4 bytes Storage in memory ?
Yeah you get it right! As var was taking memory address from 0x7fffbabdb6f0 to 0x7fffbabdb6f3, using ++ operator in pointer it jummped to the next memory address and it was 0x7fffbabdb6f4 and as there was another variable in our code , it was the memory location for x variable whichpointer pa pointed.

Unfortunately your understanding of what has happened here is incorrect, and the program only appears to work by accident.

C does not have a flat memory model, and you cannot derive a pointer from a pointer that does not point into or one past the end of the same array, and it is undefined behavior to dereference a pointer one past the end of array.

When you wrote pa++ you derived a pointer value from pa and assigned it back to pa, meaning that it is still indexing the same array, but is now pointing one past the end of the array.

Dereferencing pa at this point has undefined behavior.

By accident, on your implementation, this undefined behavior happened to access another variable, but that's purely accidental.

Collapse
 
mh_shifat profile image
5hfT

When i ran the same code in different online compilers I found the same result in case of increment of pointer.

Collapse
 
pentacular profile image
pentacular

That just means you haven't tried hard enough. :)

Tuming on asan in gcc will do the trick.

You could also try using cint, an interpreter.

Or ...

Collapse
 
sandordargo profile image
Sandor Dargo

While I usually use coliru for small sketches, if I want to try many compilers with different versions I go to wandbox.

Collapse
 
mh_shifat profile image
5hfT

Thanks for your response and explanation.

Collapse
 
sandordargo profile image
Sandor Dargo

Good points, but I'd go even further.

When you wrote pa++ you derived a pointer value from pa and assigned it back to pa, meaning that it is still indexing the same array, but is now pointing one past the end of the array.

It doesn't really index an array, it doesn't know if it points to an array and which array. It just points to a memory address and interprets what is there as an integer - without even having any notion of the array the programmer wanted to point at.

This example starts to get funnier when you declare something right after this array. While that's unspecified where the variable will be stored, you can guess for the sake of the game.

int main() {


long ar[] = {1, 2, 3, 4, 5};
double d[]={4.2, 0.42};
long *ptr;
ptr = ar;
for (int i = 0; i < 7; i++)
{
    printf("Value of *ptr = %ld\n", *ptr);
    printf("Value of ptr = %p\n", ptr);

    // Increment pointer ptr by 1
    ptr++;
}

With gcc, it'll read in ds values and even though they are doubles, as the pointer is pointing at long values, it will interpret the doubles as longs. After all, in the memory they are just 0s and 1s... (Note that on clang, based on what I saw, d will have a lower memory address, so the loop will not find it)

Collapse
 
pentacular profile image
pentacular • Edited

I think you are inferring an incorrect model of how C works by observing how some popular implementations of C work.

Let's take a look at a freely available draft standard for C.

open-std.org/jtc1/sc22/wg14/www/do...

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

and

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

What this means is that:

  1. All C objects are effectively stored in arrays.
  2. You cannot legally get from one array to another array using pointer arithmetic.

What you're observing above is undefined behavior -- you may be able to get away with it with particular compilers and architectures, but it isn't how C works. :)

Thread Thread
 
sandordargo profile image
Sandor Dargo

That's perfectly right, we are speaking about two different things. You say that getting from one array to another via pointer arithmetics is undefined behaviour. It is! In fact, that's pretty much I talked about at C++ On Sea earlier this week. Except that, I didn't speak about arrays, but STL containers and not about pointer arithmetics, but iterators.

What I tried to point at here and I see I was not clear enough, is that a pointer or an iterator doesn't know about the container it points at. It only knows the memory address and the type that it is looking for.

Let's take a practical example. We have two containers of the same type, a and b and we have a pointer to each pa and pb. Can you write a function taking the pointers and decide whether the pointers belong to the same array without having any more info available about the arrays?

#include <iostream>
#include <array>

bool f(int* pa, int* pb) {
   // TODO
   // return true of pa and pb point at the same array, false otherwise
   return true;
}

int main() {
    int a[] = {1,2,3};
    int b[] = {4,5,6};
    int* pa = a;
    int* pb = b;
    if (f(pa,pb)) {
        std::cout << "pa and pb belong to the same array" << std::endl;
    } else {
        std::cout << "pa and pb belong to the same array" << std::endl;
    }
}

As far as I understand, this is not possible, because the pointers they don't belong to a container. And this doesn't change the fact, that it's the callers responsibility to use the pointer in a sane way not trying to depend on UB. In fact, I find it quite disturbing that the article mentions C++ whereas there is no reason in 2020 to use c-style arrays and pointer arithmetics to iterate over an array...

Thread Thread
 
pentacular profile image
pentacular

Can you write a function taking the pointers and decide whether the pointers belong to the same array without having any more info available about the arrays?

You cannot introspectively determine this.

Just like you cannot introspectively determine that a pointer has a well defined value, or that a pointer points at allocated memory.

As far as I understand, this is not possible, because the pointers they don't belong to a container.

It is not possible because C and C++ do not provide introspective mechanisms to determine this.

However, they do assert that you cannot legitimately derive a pointer to one array from a pointer to another array.

(And as all objects are effectively stored in arrays in C and C++, this is a universal property and applies likewise to the substructure of STL containers, and so on.)

Which means that the association exists, regardless of if it is encoded into the program in a detectable fashion or not.

Just as memory being allocated or not may not be encoded into the program in a detectable fashion.

(For example, consider a compiler which has been able to statically determine all memory allocation your program will perform and so has hard coded every allocation at compile-time.)

The fact that you can't check it doesn't mean that it isn't significant. :)