Pointer Arithmetic

53

Solution 1

First, the binky video may help. It's a nice video about pointers. For arithmetic, here is an example:

int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);

print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)

(Note that incrementing a pointer that contains a null pointer value strictly is undefined behavior. We used NULL because we were only interested in the value of the pointer. Normally, only use increment/decrement when pointing to elements of an array).

The following shows two important concepts

  • addition/subtraction of a integer to a pointer means move the pointer forward / backward by N elements. So if an int is 4 bytes big, pa could contain 0x4 on our platform after having incremented by 1.
  • subtraction of a pointer by another pointer means getting their distance, measured by elements. So subtracting pb from pa will yield 1, since they have one element distance.

On a practical example. Suppose you write a function and people provide you with an start and end pointer (very common thing in C++):

void mutate_them(int *begin, int *end) {
    // get the amount of elements
    ptrdiff_t n = end - begin;
    // allocate space for n elements to do something...
    // then iterate. increment begin until it hits end
    while(begin != end) {
        // do something
        begin++;
    }
}

ptrdiff_t is what is the type of (end - begin). It may be a synonym for "int" for some compiler, but may be another type for another one. One cannot know, so one chooses the generic typedef ptrdiff_t.

Solution 2

Here is where I learned pointers: http://www.cplusplus.com/doc/tutorial/pointers.html

Once you understand pointers, pointer arithmetic is easy. The only difference between it and regular arithmetic is that the number you are adding to the pointer will be multiplied by the size of the type that the pointer is pointing to. For example, if you have a pointer to an int and an int's size is 4 bytes, (pointer_to_int + 4) will evaluate to a memory address 16 bytes (4 ints) ahead.

So when you write

(a_pointer + a_number)

in pointer arithmetic, what's really happening is

(a_pointer + (a_number * sizeof(*a_pointer)))

in regular arithmetic.

Solution 3

I consider a good example of pointer arithmetic the following string length function:

int length(char *s)
{
   char *str = s;
   while(*str++);
   return str - s;
}

Solution 4

There are several ways to tackle it.

The intuitive approach, which is what most C/C++ programmers think of, is that pointers are memory addresses. litb's example takes this approach. If you have a null pointer (which on most machines corresponds to the address 0), and you add the size of an int, you get the address 4. This implies that pointers are basically just fancy integers.

Unfortunately, there are a few problems with this. To begin with, it may not work. A null pointer is not guaranteed to actually use the address 0. (Although assigning the constant 0 to a pointer yields the null pointer).

Further, you're not allowed to increment the null pointer, or more generally, a pointer must always point to allocated memory (or one element past), or the special null pointer constant 0.

So a more correct way of thinking of it is that pointers are simply iterators allowing you to iterate over allocated memory. This is really one of the key ideas behind the STL iterators. They're modelled to behave very much as pointers, and to provide specializations that patch up raw pointers to work as proper iterators.

A more elaborate explanation of this is given here, for example.

But this latter view means that you should really explain STL iterators, and then simply say that pointers are a special case of these. You can increment a pointer to point to the next element in the buffer, just like you can a std::vector<int>::iterator. It can point one element past the end of an array, just like the end iterator in any other container. You can subtract two pointers that point into the same buffer to get the number of elements between them, just like you can with iterators, and just like with iterators, if the pointers point into separate buffers, you can not meaningfully compare them. (For a practical example of why not, consider what happens in a segmented memory space. What's the distance between two pointers pointing to separate segments?)

Of course in practice, there's a very close correlation between CPU addresses and C/C++ pointers. But they're not exactly the same thing. Pointers have a few limitations that may not be strictly necessary on your CPU.

Of course, most C++ programmers muddle by on the first understanding, even though it's technically incorrect. It's typically close enough to how your code ends up behaving that people think they get it, and move on.

But for someone coming from Java, and just learning about pointers from scratch, the latter explanation may be just as easily understood, and it's going to spring fewer surprises on them later.

Share:
53
Antonio
Author by

Antonio

Updated on November 05, 2020

Comments

  • Antonio
    Antonio over 3 years

    Simple Rails api back end, ember front end app. I'm trying to create a new record and Ember seems to be formatting the POST request correctly:

    enter image description here

    It's hitting my controller in the create action but there are no params getting through. It's simply:

    {"format"=>"json", "controller"=>"api/v1/vehicles", "action"=>"create"}

    request.headers does not show any of the vehicle information I'm trying to create.

    I've whitelisted everything needed in the controller:

    def vehicle_params
      params.require(:vehicle).permit(:plate_num, :vehicle_type, :state)
    end
    

    I have no idea if relevant but I've set up CORS to accept everything:

      config.middleware.insert_before 0, "Rack::Cors" do
        allow do
          origins '*'
          resource '*', :headers => :any, :methods => :any
        end
      end
    

    What else do I need to check?

    • FutoRicky
      FutoRicky over 7 years
      Did you solve this issue? I'm having the same problem