Skip to content
Laviyx Learn

Try

C course menu

Pointer Arithmetic in C: Incrementing, Subtracting and Comparing Pointers

Learn pointer arithmetic in C: how adding 1 to a pointer moves by one element, not one byte, walking through arrays with pointers, subtracting pointers to count elements with ptrdiff_t, comparing pointers, and which pointer operations are undefined.

Intermediate7 min readUpdated
On this page

You can add integers to pointers and subtract pointers from each other. Pointer arithmetic is always measured in elements, not bytes.

Adding to a pointer#

If p points to an int, p + 1 points to the next int, which is sizeof(int) bytes further on:

C
int a[] = {10, 20, 30, 40};
int *p = a;                 /* points to a[0] */

printf("%d\n", *p);
printf("%d\n", *(p + 1));
printf("%d\n", *(p + 3));
printf("%d bytes apart\n", (int)((char *)(p + 1) - (char *)p));
Output
10
20
40
4 bytes apart

(int is 4 bytes on the systems GCC normally targets.) For a double *, p + 1 moves 8 bytes; for a char *, 1 byte. The compiler scales the step by the size of the pointed-to type.

Walking through an array#

p++ moves a pointer to the next element. Combined with a pointer to "one past the end", this gives a common C idiom:

C
int marks[] = {72, 88, 95, 61, 79};
int n = sizeof marks / sizeof marks[0];

int total = 0;
for (int *p = marks; p < marks + n; p++) {
    total += *p;
}
printf("total %d\n", total);
Output
total 395

marks + n is a pointer one past the last element. You may compute it and compare with it, but never dereference it.

*p++ and friends#

Precedence makes these easy to misread:

ExpressionMeans
*p++Use *p, then move p forward
(*p)++Increment the value p points to
*++pMove p forward, then use the new *p
C
char word[] = "abc";
char *p = word;
char first = *p++;      /* reads 'a', p now points to 'b' */
(*p)++;                 /* 'b' becomes 'c' */
printf("%c %s\n", first, word);
Output
a acc

A classic use is copying a string:

C
#include <stdio.h>

void copy(char *dst, const char *src) {
    while ((*dst++ = *src++) != '\0') {
        /* copies each char, including the final '\0' */
    }
}

int main(void) {
    char buf[16];
    copy(buf, "pointer");
    printf("%s\n", buf);
    return 0;
}
Output
pointer

Subtracting pointers#

Subtracting two pointers into the same array gives the number of elements between them, as a ptrdiff_t (from <stddef.h>, printed with %td):

C
#include <stdio.h>
#include <stddef.h>
#include <string.h>

int main(void) {
    const char *path = "docs/c/pointers.mdx";
    const char *slash = strrchr(path, '/');
    ptrdiff_t dir_len = slash - path;
    printf("folder part has %td characters\n", dir_len);
    printf("file name: %s\n", slash + 1);
    return 0;
}
Output
folder part has 6 characters
file name: pointers.mdx

What is not allowed#

Pointer arithmetic is only defined within one array (plus the one-past-the-end position):

  • Moving a pointer before the start or more than one past the end is undefined behavior, even without dereferencing it.
  • Subtracting or comparing (<, >) pointers into different arrays is undefined.
  • Adding two pointers together is a compile error; it has no meaning.

Practice#

Practice exercise

Using only pointers (no [] indexing), write int count_char(const char *s, char c) that counts how often c appears, and void reverse(int *a, int n) that reverses an array using two pointers moving towards each other.

Show solution
C
#include <stdio.h>

int count_char(const char *s, char c) {
    int count = 0;
    for (; *s != '\0'; s++) {
        if (*s == c) count++;
    }
    return count;
}

void reverse(int *a, int n) {
    int *left = a, *right = a + n - 1;
    while (left < right) {
        int tmp = *left;
        *left++ = *right;
        *right-- = tmp;
    }
}

int main(void) {
    printf("%d\n", count_char("mississippi", 's'));
    int nums[] = {1, 2, 3, 4, 5};
    reverse(nums, 5);
    for (int *p = nums; p < nums + 5; p++) printf("%d ", *p);
    printf("\n");
    return 0;
}
Output
4
5 4 3 2 1 

Key takeaway#

Finished this lesson?