Skip to content

Pointer Arithmetic

What sets C pointer apart from pointers in other programming languages is that in C, we can explicitly operate on it. The operations that can be done are typically just a simple addition/subtraction with numbers. Adding or subtracting two pointers are non-standard but may be allowed. In particular, subtracting two pointers typically finds the difference in subscripts of two array elements (only if allowed in the first place). As we will discuss array in later time, we will ignore this for now.

Incrementing/Decrementing Pointer

First, let us consider incrementing a number. If we start with a = 2, performing a++ will increment the value stored in variable a from 2 to 3. That is rather straightforwards.

Now, if we extend this idea to pointer, we have to be careful. If we simply think of the address as an integer, then we may falsely believe that the address will be incremented by one. But remember that different data types have different size.

Type Size Usage
int 4 bytes Whole numbers
float 4 bytes Real numbers
double 8 bytes Real numbers
char 1 byte Characters

As will be made clearer when we talk about array next time, when we increment a pointer, we do not want to just increment the address by one. Instead, we want to point to the start of the next address of the same type. As such, incrementing an integer pointer will actually increment the address by 4. This is because each address holds one byte of data. So the start of the next address of the same type will be 4 more than the current address.

Similarly, incrementing a double pointer will add 8 to the address and incrementing a char pointer will add 1 to the address. This is summarised in the program below.

IncrementPointers.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int a; float b; char c; double d;
int *ap; float *bp; 
char *cp; double *dp;

ap = &a; bp = &b; cp = &c; dp = &d;
printf("%p %p %p %p\n", ap, bp, cp, dp);

ap++; bp++; cp++; dp++;
printf("%p %p %p %p\n", ap, bp, cp, dp);

ap += 3;
printf("%p\n", ap);

If you look at the actual run, you can ignore the actual value printed. Instead, look at the difference between the two addresses. You may get something like:

1
2
3
0x7ffdcea0c548 0x7ffdcea0c544 0x7ffdcea0c543 0x7ffdcea0c538
0x7ffdcea0c54c 0x7ffdcea0c548 0x7ffdcea0c544 0x7ffdcea0c540
0x7ffdcea0c558

Since the output is in hexadecimal, we have to do hexadecimal subtraction. But if you simply look a the difference (e.g., between 0x7ffdcea0c548 and 0x7ffdcea0c54c), you can see that the difference is basically the last hexadecimal digit. The difference between 8 and c is exactly 4. Note that for char, the difference is only one as shown in the difference between 0x7ffdcea0c543 and 0x7ffdcea0c544.

Sometime, you have to be careful since the we can easily forgot that we are dealing with hexadecimal. If you look at the output for double, it may seem that the difference between 0x7ffdcea0c538 and 0x7ffdcea0c540 is only 2! But this is wrong because in hexadecimal, that's actually a difference of 8. Remember, 8+8 = 16 and 16 in hexadecimal is 10. In this case, we simply increment the number to its left by 1 and set the current number to 0.

BasicPointer.c

Try to trace the following execution on your own before checking the result of the actual run. More importantly, you should practice using box-and-arrow diagram.

BasicPointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int i = 10, j = 20;
int *p;

p = &i;
printf("value of i is %d\n", *p);

*p = *p + 2;

p = &j;
*p = i;

printf("value of j is %d\n", j);

BasicPointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int i = 10, j = 20;
int *p; // p is a pointer to some int variable

p = &i; // p now stores the address of variable i
printf("value of i is %d\n", *p);

// *p accesses the value of pointed/referred variable
*p = *p + 2; // increment *p (which is i) by 2
             // same effect as: i = i + 2;
p = &j;      // p now stores the address of variable j
*p = i;      // value of *p (which is j now) becomes 12
             // same effect as: j = i;
printf("value of j is %d\n", j);

Pointer.c

Try to trace the following execution on your own before checking the result of the actual run. More importantly, you should practice using box-and-arrow diagram.

Pointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>

int main(void) {
  double a, *b;

  b = &a;
  *b = 12.34;
  printf("%f\n", a);

  return 0;
}
Quick Quiz

What is the output if the printf statement is changed to the following?

  1. printf("%f\n", *b)
  2. printf("%f\n", b)
  3. printf("%f\n", *a)
  4. printf("%p\n", b)
  1. 12.340000
  2. Compile with warning but run with some random value
  3. Error because a is not a pointer
  4. The hexadecimal value of the address of variable a

Pointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <stdio.h>

int main(void) {
  double a,   // a is an integer
         *b;  // b is an integer pointer

  b = &a;     // b now points to the address of variable a
  *b = 12.34; // value of *b (which is a) becomes 12.34
              // same effect as: a = 12.34;
  printf("%f\n", a);

  return 0;
}

TracePointer.c

Try to trace the following execution on your own before checking the result of the actual run. More importantly, you should practice using box-and-arrow diagram.

TracePointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int a = 8, b = 15, c = 23;
int *p1, *p2, *p3;

p1 = &b;
p2 = &c;
p3 = p2;
printf("1: %d %d %d\n", *p1, *p2, *p3);

*p1 *= a;
while (*p2 > 0) {
  *p2 -= a;
  (*p1)++;
}
printf("2: %d %d %d\n", *p1, *p2, *p3);
printf("3: %d %d %d\n", a, b, c);

TracePointer.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int a = 8, b = 15, c = 23; // {a: 8, b: 15, c: 23}
int *p1, *p2, *p3;         // {a: 8, b: 15, c: 23, p1: ?, p2: ?, p3: ?}

p1 = &b;  // {a: 8, b: 15, c: 23, p1: &b, p2: ?, p3: ?}
p2 = &c;  // {a: 8, b: 15, c: 23, p1: &b, p2: &c, p3: ?}
p3 = p2;  // {a: 8, b: 15, c: 23, p1: &b, p2: &c, p3: &c}
printf("1: %d %d %d\n", *p1, *p2, *p3); // 1: 15 23 23
// equivalent to printing (b c c)

*p1 *= a; // {a: 8, b: 120, c: 23, p1: &b, p2: &c, p3: &c}
          // same effect as: b *= a;
while (*p2 > 0) { // while (c > 0) {
  *p2 -= a;       //   c -= a;
  (*p1)++;        //   b++;
} // {a: 8, b: 123, c: -1, p1: &b, p2: &c, p3: &c}
printf("2: %d %d %d\n", *p1, *p2, *p3); // 2: 123 -1 -1
// equivalent to printing (b c c)
printf("3: %d %d %d\n", a, b, c);       // 3: 8 123 -1