11

I have the following code. Perhaps I have not understood pointer arithmetic as well as I should have but why is int_pointer incremented by 4 instead of by 1? With char_pointer, why isn't it incremented by 4 instead of 1?

 #include <stdio.h>

 int main() {
    int i;

    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    int int_array[5] = {1, 2, 3, 4, 5};

    char *char_pointer;
    int *int_pointer;

    char_pointer = int_array; // The char_pointer and int_pointer now
    int_pointer = char_array; // point to incompatible data types.

    for(i=0; i < 5; i++) { // Iterate through the int array with the int_pointer.
        printf("[integer pointer] points to %p, which contains the char '%c'\n",
            int_pointer, *int_pointer);
        int_pointer = int_pointer + 1;
    }

    for(i=0; i < 5; i++) { // Iterate through the char array with the char_pointer.
        printf("[char pointer] points to %p, which contains the integer %d\n",
            char_pointer, *char_pointer);
        char_pointer = char_pointer + 1;
    }
 }

OUTPUT:

[integer pointer] points to 0xbffff810, which contains the char 'a'
[integer pointer] points to 0xbffff814, which contains the char 'e'
[integer pointer] points to 0xbffff818, which contains the char ' '
[integer pointer] points to 0xbffff81c, which contains the char '
[integer pointer] points to 0xbffff820, which contains the char ' '
[char pointer] points to 0xbffff7f0, which contains the integer 1
[char pointer] points to 0xbffff7f1, which contains the integer 0
[char pointer] points to 0xbffff7f2, which contains the integer 0
[char pointer] points to 0xbffff7f3, which contains the integer 0
[char pointer] points to 0xbffff7f4, which contains the integer 2
user3754974
  • 279
  • 1
  • 6
  • 15
  • 2
    `char_pointer = int_array;` This is bad. I believe it's undefined behavior to assign pointers of incompatible types. –  Aug 16 '14 at 01:54
  • @ShafikYaghmour: OP is mixing the types during the pointer assignment, but that doesn't change the pointer arithmetic behaviour. Although it violates strict aliasing. The other problem is the out-of-bound array access triggered when `int_pointer` is dereferenced in subsequent loop iterations. Did I miss something? – jweyrich Aug 16 '14 at 02:47
  • @jweyrich there are two separate forms of undefined behavior in this code and the questions can not be properly answered without covering those issues because the code is just incorrect. – Shafik Yaghmour Aug 16 '14 at 02:53
  • @ShafikYaghmour: Right, well put. I'll retract my vote and remove the dup comment. +1 on your anwer as well :-) – jweyrich Aug 16 '14 at 02:54
  • `char_pointer = int_array;` -- This is not merely undefined behavior, it's a *constraint violation*. Basically it's illegal; any conforming compiler must issue a diagnostic, though many will (unfortunately IMHO) make it a non-fatal warning. But if you change it to `char_pointer = (char*)int_array;` it's no longer a constraint violation, but you may run into undefined behavior depending on how you use the pointer. Same thing for `int_pointer = char_array;` except that you could also run into alignment problems. – Keith Thompson Aug 16 '14 at 03:22
  • I believe it's a duplicate. The crux of this question is already answered elsewhere. On top of that, it's also invalid code (due to the dereferencing), but that's tangential, it could easily be rewritten to not be UB. – Oliver Charlesworth Aug 16 '14 at 08:16
  • @remyabel: the language makes an exception for char*. – Oliver Charlesworth Aug 16 '14 at 08:18

3 Answers3

17

That's how pointers aritmetics works: if you increment the pointer by 1, the address gets increased by the size of the pointer type. So since in your machine ints are 4 bytes, incrementing an int pointer increases the address of 4 bytes.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
9

Undefined Behavior

What you have is undefined behavior, first you are violating the strict aliasing rule which basically makes it illegal to access an object through a pointer of a different type, although access through a char * is allowed. I will quote my answer here which covers this more extensively:

the strict aliasing rules which makes it illegal to access an object through a pointer of a different type, although access through a char * is allowed. The compiler is allowed to assume that pointers of different types do not point to the same memory and optimize accordingly. It also means the code invokes undefined behavior and could really do anything.

Second different pointers may have different alignment requirements and so accessing your char array through an int pointer may very well violate this requirement since the char array may not be aligned properly for an int. The draft C99 standard covers this in section 6.3.2.3 Pointers which says (emphasis mine):

A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned57) for the pointed-to type, the behavior is undefined.

A good compiler with the right set of flags should help a lot here, using clang and the following flags -std=c99 -fsanitize=undefined -Wall -Wextra -Wconversion -pedantic I see the following warnings (see it live):

warning: incompatible pointer types assigning to 'char *' from 'int [5]' [-Wincompatible-pointer-types]
char_pointer = int_array; // The char_pointer and int_pointer now
             ^ ~~~~~~~~~

warning: incompatible pointer types assigning to 'int *' from 'char [5]' [-Wincompatible-pointer-types]
int_pointer = char_array; // point to incompatible data types.
            ^ ~~~~~~~~~~

and during runtime I see the following error:

runtime error: load of misaligned address 0x7fff48833df3 for type 'int', which requires 4 byte alignment
0x7fff48833df3: note: pointer points here
00  e0 3e 83 61 62 63 64 65  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  6d 47 60 5a 1d 7f 00
             ^ 

Pointer arithmeic

So pointer arithmetic is based on the size of the type that is being pointed to. How would array access which is basically syntactic sugar for pointer arithmetic work correctly otherwise? You can a read more detailed description here and related discussion here.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

When doing pointer arithmetic it will increment by the size of what you're trying to increment. Take this for example.

int a[2];
a[0] = 1;
a[1] = 3;
a = a + 1
printf("%d\n",*a) \\ 3

It needs to move forward by the size of the thing being pointed to. What always helps me is by casting the pointer to a char first to work with bytes.

int a[2];
a[0] = 1;
a[1] = 3;
a = (char)a + sizeof(int)*1
printf("%d\n",*a) \\ 3

That is a bit more understandable and it would produce exactly what you think.

CleoR
  • 806
  • 6
  • 18
  • 1
    I think name of an array is a constant ptr whose value you can not change. Here i think line "a = a + 1" should give compilation error. – Jack Apr 15 '18 at 19:28