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.
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:
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));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:
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);total 395marks + 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:
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);a accA classic use is copying a string:
#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;
}pointerSubtracting 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):
#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;
}folder part has 6 characters
file name: pointers.mdxWhat 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
#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;
}4
5 4 3 2 1 Key takeaway#
Finished this lesson?