Hello! Welcome to the final lesson in our "Pointer Arithmetic and Arrays" module.
In the last session, we mastered traversing generic arrays using a "moving pointer," understanding how ptr++ automatically scales to the size of the data type it points to. We saw this is a clean and powerful alternative to traditional indexing.
Today, we'll apply this exact skill to a special, ubiquitous type of array in C: the string. You'll learn how to use pointers to parse, copy, and compare strings with the efficiency and style of a seasoned C programmer. For someone in automotive software, where you're often parsing CAN messages, SOME/IP payloads, or diagnostic logs, this direct, low-level string manipulation is an indispensable skill.
Strings: Null-Terminated Character Arrays
In C, a "string" is not a built-in type. It's a convention: a contiguous block of characters in memory, followed by a special null terminator character (\0).
This null terminator is the key. While for a generic array we need to pass its size to a function, the null terminator acts as a "sentinel" that tells functions where the string ends. This allows us to process strings using only a pointer to their first character.

A Critical Distinction: char s[] vs. char *s
Before we start manipulating strings, we must understand a crucial difference in how they can be declared. This is a common source of bugs and crashes, especially the infamous "segmentation fault."
char s[] = "Hello";declares a character array on the stack. The contents of the string literal"Hello"are copied into this array. This memory is modifiable.char *s = "Hello";declares a pointer that points to a string literal. String literals are often stored in a read-only section of the program's memory (e.g., the.rodatasegment). Attempting to modify this memory results in undefined behavior.
Given your work with functional safety (ISO 26262) and MISRA-C, understanding this distinction is non-negotiable. Modern best practice, which MISRA-C enforces, is to declare pointers to literals as const to catch modification attempts at compile-time: const char *s = "Hello";.
To see a clear explanation and demonstration of this difference, please watch the following video.
String In Char Array VS. Pointer To String Literal | C Programming Tutorial
This video from Portfolio Courses, 'String In Char Array VS. Pointer To String Literal', expertly explains the memory and modifiability differences between declaring a string as a character array versus a pointer to a literal.
Watch the video from the beginning to 04:39 to understand the core difference and the segmentation fault it can cause. Then, watch the conclusion from 08:57 to 09:48, which introduces the best practice of using const.
Traversing Strings with Pointers
With the null terminator as our guide, traversing a string becomes a simple while loop. The loop continues as long as the character the pointer points to is not \0.
Let's implement our own version of strlen, which calculates the length of a string.
Method 1: Using a separate pointer
#include <stddef.h> // For size_t
size_t my_strlen(const char *str) {
const char *p = str; // Create a new pointer to iterate with
while (*p != '\0') {
p++;
}
return p - str; // Use pointer subtraction!
}
Notice how we use pointer subtraction, a concept from our earlier lesson, to calculate the length. We subtract the starting address (str) from the final address (p) to get the number of elements between them.
Method 2: The Idiomatic C while loop
In C, any non-zero value is "true" and zero is "false". Since the null character \0 has a value of 0, we can write the loop more compactly. This is the style you'll see in most professional C code.
#include <stddef.h>
size_t my_strlen_idiomatic(const char *str) {
const char *p = str;
while (*p) { // The loop runs as long as *p is not the null character
p++;
}
return p - str;
}
Re-implementing Standard Library Functions
The best way to master pointer-based string manipulation is to re-implement the standard functions found in <string.h>. Let's tackle strcpy, which copies a source string into a destination buffer.
The following video shows how to build this function using pointer arithmetic. This is far more efficient than an index-based approach because it often results in fewer instructions for the CPU.
Create Your Own strcpy() String Copy Function | C Programming Example
This video, 'Create Your Own strcpy()', provides a perfect demonstration of converting an index-based string copy to a more efficient pointer-based one.
Please watch the second implementation from 06:12 to 10:28. Pay close attention to how the source and destination pointers are dereferenced for the copy and then incremented to move to the next character.
The Ultimate C Idiom: strcpy in One Line
The pointer-based strcpy can be condensed into a single, highly expressive line that is a hallmark of expert C programming.
void my_strcpy(char *dest, const char *src) {
while (*dest++ = *src++);
}
Let's break down this dense but powerful expression, *dest++ = *src++, and what happens in each iteration of the while loop:
*srcis evaluated: The character at the currentsrcaddress is read.- The value is assigned to
*dest: The character is copied to the currentdestaddress. - The result of the assignment is evaluated by
while. The expressiona = bevaluates to the value ofb. The loop continues as long as this value is not\0(zero). - When
\0is finally copied fromsrctodest, the assignment expression evaluates to 0, causing thewhileloop to terminate. - Side Effect: The post-increment operators (
++) ondestandsrccause both pointers to advance to the next character after all of the above has happened.
This single line elegantly handles the character copy, the loop termination check, and the pointer advancement for both source and destination.
For more examples of this compact style, the following resource is an excellent reference.
Pointer Arithmetic with Strings
The article 'Pointer Arithmetic with Strings' from GeeksforGeeks provides a concise cookbook of standard string functions implemented using pointer arithmetic. It's a great reference for common C idioms.
Skim through the entire article, paying particular attention to the implementations of compare, copy, length, and concatenate. Notice the consistent pattern of using while loops with pointer dereferencing and incrementing.
Test your understanding!
Let's analyze the compare function from the GeeksforGeeks article you just reviewed.
int compare(char *s1, char *s2) {
while (*s1 && (*s1++ == *s2++));
return *s1 - *s2;
}
Explain, step by step, how this function determines that "Geeks" is "less than" "Geeksfor". What are the final values of *s1 and *s2 right before the return statement?
Show answer
- The
whileloop compares characters froms1ands2one by one. The loop continues as long as the character ins1is not null (*s1) AND the characters are equal (*s1++ == *s2++). - The first 5 characters ('G', 'e', 'e', 'k', 's') are identical. In each of these iterations, the comparison
*s1++ == *s2++is true, and both pointers are incremented. - After the 5th iteration,
s1points to the null terminator (\0) of the string"Geeks". s2points to the character'f'in"Geeksfor".- The loop condition
*s1is now checked. Since*s1is\0(which evaluates to false), the loop terminates. The second part of the condition (*s1++ == *s2++) is not even evaluated due to short-circuiting. - The function proceeds to the
returnstatement.- The final value of
*s1is\0(ASCII value 0). - The final value of
*s2is'f'(ASCII value 102).
- The final value of
- The function returns
*s1 - *s2, which is0 - 102, resulting in-102. A negative value indicates that the first string is lexicographically smaller than the second, which is the correct behavior forstrcmp.
Conclusion
Today we've specialized our knowledge of pointer traversal and applied it to C strings, the workhorse of text manipulation. This is a significant step towards writing fast, efficient, and idiomatic C code.
Key Takeaways:
- C strings are simply character arrays terminated by a
\0null character. - This null terminator acts as a sentinel, allowing functions to process strings using only a starting pointer, without needing a separate size parameter.
- Using pointer arithmetic (
*ptr++) is the canonical and most efficient way to traverse and manipulate strings. - It is critical to distinguish between a modifiable stack-allocated character array (
char s[]) and a pointer to a non-modifiable string literal (const char *s). - Compact idioms like
while (*dest++ = *src++)are common and combine assignment, condition checking, and pointer increments into a single expression.
In our next lesson, we will begin a new module, "Pointers and Functions." The string utility functions we built today are a perfect preview. We'll formalize the concepts of pass-by-value vs. pass-by-reference and see how passing pointers to functions is the fundamental way to allow a function to modify data in its caller's scope.