-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
100: Practice Exercise: Implementing Your Own strlen and strcpy
I've always found that the best way to stop feeling "shaky" about pointers is to stop using the high-level library functions for a moment and build them from scratch. Today, we're looking at strlen and strcpy. These seem trivial because they're so common, but they are the perfect exercise for mastering how C actually views a string: as a sequence of bytes ending in a very specific marker.
Counting until the stop sign
Imagine you're standing at the beginning of a long row of lockers. You don't know how many lockers there are, but you've been told that inside one of them, there is a red flag. Your job is to count how many lockers you pass before you hit the one with the red flag. You open the first locker—no flag. That's one. You open the second—no flag. That's two. The moment you open a locker and see that red flag, you stop counting and shout out the number.
This is exactly how strlen works. In C, the "red flag" is the null terminator, '\0'. The function doesn't actually know the size of the memory allocated to the string; it just knows to keep walking forward until it hits that zero byte.
size_t my_strlen(const char *s) {
size_t length = 0;
while (s[length] != '\0') {
length++;
}
return length;
}
Notice I used const char *s. I do this because counting the length of a string shouldn't involve changing the string itself. It's a good habit to get into early—if a function doesn't need to modify data, mark it const.
Cloning a string byte by byte
Now, strcpy is a bit like taking a piece of carbon paper and tracing a drawing from one page to another. You start at the top-left corner of the original page and copy every single mark you see onto the new page. You keep going line by line, mark by mark, until you reach the very end of the drawing. If you stop too early, the copy is incomplete. If you keep going past the end, you're just drawing on blank paper (or, in C terms, corrupting memory).
When we implement this, we have to move the character from the source to the destination and then move our "finger" (the pointer) one step forward in both places. The most important part? We have to copy that null terminator too. If we don't, the destination string is just a random sequence of characters in memory with no "stop sign," and any other function trying to read it will just keep running past the end of the buffer until the program crashes.
char* my_strcpy(char *dest, const char *src) {
char *save = dest; // We save the start address to return it at the end
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0'; // The crucial "stop sign"
return save;
}
I used pointer incrementing (dest++ and src++) here instead of array indexing. It's a more "C-like" way of doing things and usually maps more directly to how the CPU actually handles memory offsets. It feels a bit weirder at first, but once it clicks, it's much faster to write.
📋 Practical Task
Exercise: Recreating the Standard String Duo
Your task is to write a small program that replaces the standard string.h functions with your own versions. This will prove you understand how the null terminator controls the flow of string operations.
Requirements:
- Implement
size_t my_strlen(const char *s). - Implement
char* my_strcpy(char *dest, const char *src). - In your
mainfunction, create a source string (e.g.,"Learning C is a journey"). - Create a destination character array large enough to hold that string.
- Use your
my_strcpyto copy the source into the destination. - Use your
my_strlento print the length of the newly copied string. - Print both strings to the console to verify they are identical.
Pro Tip: To really test your my_strcpy, try printing the destination string before you add the *dest = '\0' line in your function. You'll likely see a bunch of "garbage" characters—that's the visual proof of why the null terminator is non-negotiable.
There are no comments for now.