C String Functions: Mastering string.h 🧰
Mentor's Note: Think of the
<string.h>library like a Swiss Army knife. Instead of whittling raw wood or cutting string with your bare hands using custom loops, these built-in functions let you manipulate text safely and efficiently in a single line! 💡
📚 Educational Content: In GSEB Std 11/12, CBSE Class 11/12, and BCA Semester 1 examinations, string manipulation is a staple topic. Questions often focus on the difference between safe and unsafe functions (like
strcpyvsstrncpy) and tracing code that usesstrtokorstrcmp.
By the end of this tutorial, you'll know:
- How to include and utilize the
<string.h>header file. - The syntax, parameters, and behavior of 11 essential string functions.
- The critical security difference between
strcpyandstrncpy. - How to split text into tokens using
strtokand write formatted data withsprintf. - The common traps like buffer overflows and missing null-terminators.
🌟 The Scenario: The Post Office Label Machine
Imagine you work in a high-speed post office sorting and labeling packages:
strlenis the scale. It measures the weight (number of letters) of a word label, but ignores the box itself.strcpyis a photocopier. It takes the text from one label and copies it onto a blank label. If the blank label is too small, the ink spills over the edges and ruins the office desk (buffer overflow!).strcatis glue. It takes one label and sticks it directly onto the end of another.strcmpis the inspector. It compares two address labels side-by-side to check if they are identical or which one comes first in the alphabetical directory.
📖 Concept Explanation
Because C does not have a native "String" class, all text operations are performed on character arrays. To make this easier, the C Standard Library provides the <string.h> header, which contains functions designed to manipulate null-terminated character arrays.
String Functions Reference Table
| Function | Header | Syntax | Return Type | Description |
|---|---|---|---|---|
strlen | <string.h> | strlen(const char *str) | size_t | Returns the length of str (excluding the null terminator \0). |
strcpy | <string.h> | strcpy(char *dest, const char *src) | char * | Copies src to dest (Unsafe: does not check buffer limits). |
strncpy | <string.h> | strncpy(char *dest, const char *src, size_t n) | char * | Copies up to n characters from src to dest. |
strcmp | <string.h> | strcmp(const char *s1, const char *s2) | int | Compares s1 and s2 lexicographically. |
strncmp | <string.h> | strncmp(const char *s1, const char *s2, size_t n) | int | Compares the first n characters of s1 and s2. |
strcat | <string.h> | strcat(char *dest, const char *src) | char * | Appends src to the end of dest (Unsafe). |
strncat | <string.h> | strncat(char *dest, const char *src, size_t n) | char * | Appends up to n characters from src to dest. |
strchr | <string.h> | strchr(const char *str, int ch) | char * | Returns a pointer to the first occurrence of character ch in str. |
strstr | <string.h> | strstr(const char *haystack, const char *needle) | char * | Returns a pointer to the first occurrence of substring needle in haystack. |
strtok | <string.h> | strtok(char *str, const char *delim) | char * | Splits str into tokens using delimiters. |
sprintf | <stdio.h> | sprintf(char *buf, const char *format, ...) | int | Writes formatted output into the character buffer buf. |
🔒 Security Showdown: strcpy vs strncpy
Understanding buffer overflows is essential for writing secure code.
Unsafe copy: strcpy
When you execute strcpy(dest, src), C copies characters from src to dest one-by-one until it detects the null terminator \0. If src has 20 characters and dest is only allocated 10 bytes of memory, strcpy will blindly write the remaining 10 characters into adjacent memory locations. This corrupts nearby variables and causes crashes or security exploits.
Safe copy: strncpy
To prevent this, you should use strncpy(dest, src, n), where n is the maximum capacity of dest.
If the length of src is equal to or greater than n, strncpy will copy the first n characters but will not append the null terminator (\0). If you print dest later, printf will read past the array boundary trying to find \0, resulting in garbage printouts or crashes.
Always manually terminate the string after calling strncpy!
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // Manual termination guaranteed
🧠 Algorithm & Step-by-Step Logic
Let's review the step-by-step logic of tokenizing a comma-separated string (like "Mango,Orange,Banana") using strtok:
- Start 🏁
- First Call: Pass the string and delimiter to
strtok(str, ",").strtokfinds the first comma, replaces it with\0, and returns a pointer to the start of "Mango".
- Subsequent Calls: Call
strtok(NULL, ",").- By passing
NULLas the first argument, you instructstrtokto continue from where it left off. - It replaces the next comma with
\0and returns a pointer to "Orange".
- By passing
- End Condition: Repeat step 3 until
strtokreturnsNULL, indicating no more tokens are left. - End 🏁
💻 Implementation (C99)
The following program demonstrates all key string functions, highlighting the difference between safe and unsafe copying, string searching, and tokenization.
#include <stdio.h>
#include <string.h>
// 🛒 Scenario: Office String Processor
// 🚀 Action: Showcase safety checks, concatenation, comparisons, tokenization, and formatting
int main() {
// 1. Measuring Length vs Size
char word[10] = "Apple";
printf("1. Length of '%s': %zu\n", word, strlen(word));
printf(" Memory Size of '%s': %zu bytes\n\n", word, sizeof(word));
// 2. Unsafe vs Safe String Copying
char src[] = "SuperLongMessageThatCanOverflow";
char safe_dest[15];
// Safe copying using strncpy with manual termination
strncpy(safe_dest, src, sizeof(safe_dest) - 1);
safe_dest[sizeof(safe_dest) - 1] = '\0';
printf("2. Safe Copy Result: %s\n\n", safe_dest);
// 3. String Comparison
char pass1[] = "Surat2026";
char pass2[] = "Surat2026";
char pass3[] = "surat2026"; // uppercase difference
if (strcmp(pass1, pass2) == 0) {
printf("3. pass1 and pass2 are identical.\n");
}
if (strcmp(pass1, pass3) != 0) {
printf(" pass1 and pass3 are different (case-sensitive).\n\n");
}
// 4. Safe Concatenation
char greeting[30] = "Welcome, ";
char user[] = "Vishnu Damwala!";
strncat(greeting, user, sizeof(greeting) - strlen(greeting) - 1);
printf("4. Concatenation: %s\n\n", greeting);
// 5. Searching for Characters and Substrings
char *domain = strchr(email, '@');
if (domain != NULL) {
printf("5. Domain found starting from: %s\n", domain);
}
char sentence[] = "Learning C programming is fun!";
char *match = strstr(sentence, "programming");
if (match != NULL) {
printf(" Substring found: %s\n\n", match);
}
// 6. Tokenization
char csv_data[] = "Physics,Chemistry,Maths";
printf("6. Tokenizing '%s':\n", csv_data);
char *token = strtok(csv_data, ",");
while (token != NULL) {
printf(" - Token: %s\n", token);
token = strtok(NULL, ","); // Notice NULL is passed to continue
}
printf("\n");
// 7. Writing Formatted Output to a String
char report_buffer[60];
int roll_no = 42;
float gpa = 9.8;
sprintf(report_buffer, "Student Info -> Roll: %d, GPA: %.2f", roll_no, gpa);
printf("7. Formatted String: %s\n", report_buffer);
return 0;
}
// Output:
// 1. Length of 'Apple': 5
// Memory Size of 'Apple': 10 bytes
//
// 2. Safe Copy Result: SuperLongMessa
//
// 3. pass1 and pass2 are identical.
// pass1 and pass3 are different (case-sensitive).
//
// 4. Concatenation: Welcome, Vishnu Damwala!
//
// 5. Domain found starting from: @vishnudigital.com
// Substring found: programming is fun!
//
// 6. Tokenizing 'Physics,Chemistry,Maths':
// - Token: Physics
// - Token: Chemistry
// - Token: Maths
//
// 7. Formatted String: Student Info -> Roll: 42, GPA: 9.80
📊 Sample Dry Run
Let's trace how the memory changes when strtok processes the string "A,B" with delimiter ",".
Assume csv is stored at memory address 1000.
| Step | Function Call | Pointer Returned | String state in memory | Description |
|---|---|---|---|---|
| 1 | strtok(csv, ",") | Pointer to 1000 ("A") | 'A' '\0' 'B' '\0' | strtok finds the comma at index 1, replaces it with \0, and returns start address. |
| 2 | strtok(NULL, ",") | Pointer to 1002 ("B") | 'A' '\0' 'B' '\0' | strtok resumes from index 2, reads until end of string, and returns address 1002. |
| 3 | strtok(NULL, ",") | NULL | 'A' '\0' 'B' '\0' | No more delimiters or characters. Loop terminates. |
📉 Complexity Analysis
Time Complexity ⏱️
strlen: $O(N)$ because it must iterate through the string character-by-character to find the null terminator.strcpy/strncpy: $O(N)$ where $N$ is the number of characters copied.strcmp: $O(N)$ in the worst case, as it compares characters one-by-one until a mismatch or\0is found.strstr: $O(N \times M)$ where $N$ is the length of the string and $M$ is the length of the substring (using standard naive algorithm).
Space Complexity 💾
- Auxiliary Space: $O(1)$ because all of these functions modify strings in-place or traverse them using pointers, without allocating extra heap memory.
🎨 Visual Logic & Diagrams
The diagram below illustrates how strtok replaces delimiters in memory dynamically:
🎯 Practice Problems
Easy Level 🟢
- Problem 1: Write a program to read a user's full name and count the total number of characters, excluding spaces.
- Problem 2: Implement a basic password matcher using
strcmp.
Medium Level 🟡
- Problem 3: Write a custom version of
strncatwithout using<string.h>library functions. - Problem 4: Read a string containing a path (e.g.,
"/usr/bin/gcc") and extract the file name ("gcc") usingstrrchr.
Hard Level 🔴
- Problem 5: Write a secure parser that reads a sentence from the user, splits it into words using spaces as delimiters, and builds a reverse sentence using
sprintfto output the results safely.
❓ Frequently Asked Questions
Details
Q: What is the difference between sizeof() and strlen() for a string?
sizeof() is a compile-time operator that returns the total size allocated for the array in memory, including unused space and the null terminator. strlen() is a runtime function that counts only the active characters up to (but not including) the null terminator \0.Details
Q: Why does my program crash when using strtok on a string literal?
strtok modifies the string in-place by writing null characters (\0) into it. String literals (e.g., char *str = "Hello,World";) are stored in read-only memory. Attempting to modify them results in a Segmentation Fault. You must copy the literal into a character array first (e.g., char str[] = "Hello,World";).Details
Q: Why does strcmp return non-boolean values like -1 or 2 instead of just 0 or 1?
strcmp returns the subtraction result of the first mismatched character's ASCII value. If s1 is smaller than s2, it returns a negative value. If s1 is larger, it returns a positive value. This behavior is useful for sorting strings alphabetically.✅ Summary
In this tutorial, you've learned:
- ✅
<string.h>is the essential header containing helpers for character arrays. - ✅
strncpyandstrncatare the secure, length-bounded versions ofstrcpyandstrcat. - ✅ Manual null termination is mandatory when
strncpytruncates a source string. - ✅
strtoksplits strings destructively by inserting\0characters in-place. - ✅
sprintfformats non-string data types directly into a text buffer.
💡 Interview Tips & Board Focus 👔
Common Questions
- "Why is
strcpydangerous, and how doesstrncpysolve its issues?" - "What does
strcmpreturn when two strings are compared?" - "Write your own version of
strlenwithout using<string.h>."
Answering Strategy
- When asked to write custom string functions in board exams, remember to write a loop that runs until it hits the null terminator character:
while(str[i] != '\0'). - Mention that
strncpyis preferred in production-grade software to prevent buffer-overflow vulnerabilities.
📚 Best Practices & Common Mistakes
✅ Best Practices
- Always define destination arrays with enough size to hold the text and the null character
\0. - Use the length-safe
strn...variants of string functions. - Set the last character of a destination buffer to
\0afterstrncpy.
❌ Common Mistakes ⚠️
- Forgetting that
strtokmodifies the input array. If you need the original string later, copy it first. - Accessing return pointers of
strstrorstrchrwithout checking if they areNULL(causes runtime crashes). - Writing
char dest[5]; strcpy(dest, "Surat");— the string "Surat" requires 6 bytes (including\0), so this overflows the buffer.
📚 Further Reading
Continue your learning path:
- ← Previous: Strings in C: Character Arrays & Text
- Next: Pointers in C — Address, Dereferencing, * and &
Guide Version: 2.0
Purpose: Educational content creation standards for VD Computer Tuition
---