A Comprehensive Guide to C’s strlen Function

The strlen function is one of the most fundamental and frequently used functions in the C standard library. It provides a simple yet essential service: determining the length of a null-terminated string. Despite its apparent simplicity, understanding strlen's behavior, limitations, and performance characteristics is crucial for writing robust and efficient C code. This article provides an exhaustive exploration of strlen, from basic usage to advanced implementation details.


1. What is strlen?

The strlen function computes the length of a string, defined as the number of characters before the first null terminator ('\0'). The length does not include the null terminator itself.

Function Prototype:

#include <string.h>
size_t strlen(const char *str);

Parameters:

  • str: Pointer to a null-terminated string

Return Value:

  • The number of characters in the string (type size_t, an unsigned integer type)

Key Characteristics:

  • The string must be null-terminated; otherwise, behavior is undefined
  • Returns 0 for an empty string (first character is '\0')
  • Does not modify the input string (uses const qualifier)
#include <stdio.h>
#include <string.h>
int main() {
const char *str1 = "Hello";
const char *str2 = "";
const char *str3 = "A";
const char *str4 = "This is a longer string with spaces!";
printf("Length of '%s': %zu\n", str1, strlen(str1));
printf("Length of '%s': %zu\n", str2, strlen(str2));
printf("Length of '%s': %zu\n", str3, strlen(str3));
printf("Length of '%s': %zu\n", str4, strlen(str4));
return 0;
}

Output:

Length of 'Hello': 5
Length of '': 0
Length of 'A': 1
Length of 'This is a longer string with spaces!': 33

2. How strlen Works (Under the Hood)

Understanding how strlen is typically implemented helps appreciate its performance characteristics and limitations.

A. Simple Implementation

The most straightforward implementation iterates through the string until it finds the null terminator.

#include <stdio.h>
// Simple implementation of strlen
size_t my_strlen_simple(const char *str) {
size_t length = 0;
// Increment length until null terminator is found
while (str[length] != '\0') {
length++;
}
return length;
}
// Alternative implementation using pointer arithmetic
size_t my_strlen_pointer(const char *str) {
const char *ptr = str;
// Walk the pointer until null terminator
while (*ptr != '\0') {
ptr++;
}
// Return the difference between pointers
return ptr - str;
}
int main() {
const char *test = "Hello World";
printf("String: '%s'\n", test);
printf("Simple implementation: %zu\n", my_strlen_simple(test));
printf("Pointer arithmetic: %zu\n", my_strlen_pointer(test));
printf("Standard strlen: %zu\n", strlen(test));
return 0;
}

Output:

String: 'Hello World'
Simple implementation: 11
Pointer arithmetic: 11
Standard strlen: 11

B. Optimized Implementation (Word-at-a-Time)

Modern library implementations of strlen often use advanced techniques like reading word-sized chunks (4 or 8 bytes at a time) to improve performance.

#include <stdio.h>
#include <string.h>
#include <stdint.h>
// Conceptual illustration of an optimized strlen (simplified)
// Real implementations use bit tricks to check for null bytes in words
size_t my_strlen_optimized(const char *str) {
const char *start = str;
// Align to word boundary (simplified concept)
// Check byte by byte until aligned
while ((uintptr_t)str % sizeof(size_t) != 0) {
if (*str == '\0') return str - start;
str++;
}
// Check word-sized chunks
const size_t *word_ptr = (const size_t*)str;
size_t word;
while (1) {
word = *word_ptr;
// Check if any byte in word is zero
// Real implementations use bit operations to detect zero bytes
if ((word - 0x0101010101010101ULL) & ~word & 0x8080808080808080ULL) {
// Found a null byte - check which byte
const char *byte_ptr = (const char*)word_ptr;
while (*byte_ptr != '\0') byte_ptr++;
return byte_ptr - start;
}
word_ptr++;
}
}
int main() {
const char *long_string = "This is a somewhat longer string for testing";
printf("Standard strlen: %zu\n", strlen(long_string));
printf("Optimized concept: %zu\n", my_strlen_optimized(long_string));
return 0;
}

C. Visual Representation

How strlen traverses memory:

Memory address: 1000 1001 1002 1003 1004 1005 1006 1007 1008
Content:        'H'  'e'  'l'  'l'  'o'  '\0' 'x'  'y'  'z'
↑                              ↑
str points here                strlen stops here
strlen returns 5 (characters before '\0')
The characters after '\0' ('x', 'y', 'z') are ignored

3. Return Type: size_t

The strlen function returns size_t, an unsigned integer type defined in <stddef.h> and <string.h>.

#include <stdio.h>
#include <string.h>
#include <stddef.h>  // For size_t definition
int main() {
const char *str = "Hello";
size_t len = strlen(str);
printf("Length: %zu\n", len);
printf("Type of size_t on this system: %lu bytes\n", sizeof(size_t));
// Important: size_t is unsigned
// This can lead to subtle bugs:
size_t len2 = strlen("Hi");
// WRONG: Comparing signed and unsigned can produce unexpected results
// if (len2 - 5 < 0) {  // This never happens! (unsigned underflow)
//     printf("This will never print\n");
// }
// CORRECT: Cast to signed if negative comparisons are needed
if ((int)len2 - 5 < 0) {
printf("Length is less than 5\n");
}
return 0;
}

Output:

Length: 5
Type of size_t on this system: 8 bytes
Length is less than 5

4. strlen vs sizeof

One of the most common sources of confusion in C is the difference between strlen (function) and sizeof (operator).

#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello";
char str2[10] = "Hello";
const char *str3 = "Hello";
printf("=== strlen vs sizeof ===\n\n");
// Array with size deduced from literal
printf("char str1[] = \"Hello\";\n");
printf("  strlen(str1): %zu (actual string length)\n", strlen(str1));
printf("  sizeof(str1): %zu (array capacity, includes '\\0')\n", sizeof(str1));
printf("  Difference: sizeof includes null terminator, strlen does not\n\n");
// Array with explicit size
printf("char str2[10] = \"Hello\";\n");
printf("  strlen(str2): %zu\n", strlen(str2));
printf("  sizeof(str2): %zu (10 bytes allocated)\n\n", sizeof(str2));
// Pointer to string literal
printf("const char *str3 = \"Hello\";\n");
printf("  strlen(str3): %zu\n", strlen(str3));
printf("  sizeof(str3): %zu (size of pointer, not the string!)\n", sizeof(str3));
return 0;
}

Output:

=== strlen vs sizeof ===
char str1[] = "Hello";
strlen(str1): 5 (actual string length)
sizeof(str1): 6 (array capacity, includes '\0')
Difference: sizeof includes null terminator, strlen does not
char str2[10] = "Hello";
strlen(str2): 5
sizeof(str2): 10 (10 bytes allocated)
const char *str3 = "Hello";
strlen(str3): 5
sizeof(str3): 8 (size of pointer, not the string!)

Critical Differences:

Featurestrlensizeof
TypeFunctionOperator (compile-time)
ReturnsLength of string (characters before '\0')Total bytes of the expression
Null terminatorNOT countedIS counted for arrays
Works on pointers?Yes (follows pointer)Returns pointer size (not string length)
Compile-time/ RuntimeRuntime (must scan string)Compile-time (for arrays)
Empty stringReturns 0Returns 1 (for char arr[] = "")

5. Common Use Cases

A. Buffer Size Validation

#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 50
int safe_copy(char *dest, size_t dest_size, const char *src) {
size_t src_len = strlen(src);
if (src_len >= dest_size) {
printf("Error: Source too long (%zu >= %zu)\n", src_len, dest_size);
return -1;
}
strcpy(dest, src);
return 0;
}
int main() {
char buffer[BUFFER_SIZE];
const char *short_str = "Short";
const char *long_str = "This string is way too long to fit in the buffer";
if (safe_copy(buffer, BUFFER_SIZE, short_str) == 0) {
printf("Copied: '%s'\n", buffer);
}
safe_copy(buffer, BUFFER_SIZE, long_str);
return 0;
}

Output:

Copied: 'Short'
Error: Source too long (46 >= 50)

B. Looping Through Strings

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
const char *str = "Hello, World!";
// Method 1: Using strlen in loop condition (inefficient)
printf("Method 1 (recalculates length each iteration): ");
for (size_t i = 0; i < strlen(str); i++) {
putchar(toupper(str[i]));
}
printf("\n");
// Method 2: Store length once (better)
printf("Method 2 (length stored): ");
size_t len = strlen(str);
for (size_t i = 0; i < len; i++) {
putchar(tolower(str[i]));
}
printf("\n");
// Method 3: Pointer iteration (no length needed)
printf("Method 3 (pointer iteration): ");
const char *ptr = str;
while (*ptr) {
putchar(*ptr);
ptr++;
}
printf("\n");
return 0;
}

Output:

Method 1 (recalculates length each iteration): HELLO, WORLD!
Method 2 (length stored): hello, world!
Method 3 (pointer iteration): Hello, World!

C. String Comparison Without Standard Functions

#include <stdio.h>
// Custom string comparison using strlen concepts
int compare_strings(const char *s1, const char *s2) {
// Walk both strings simultaneously
while (*s1 && *s2 && *s1 == *s2) {
s1++;
s2++;
}
// Return difference or 0 based on values or lengths
return (unsigned char)*s1 - (unsigned char)*s2;
}
int main() {
const char *tests[][2] = {
{"Hello", "Hello"},
{"Hello", "World"},
{"Hello", "Hell"},
{"Apple", "Apple pie"}
};
for (int i = 0; i < 4; i++) {
int result = compare_strings(tests[i][0], tests[i][1]);
printf("\"%s\" vs \"%s\": %d (%s)\n",
tests[i][0], tests[i][1], result,
result < 0 ? "less" : (result > 0 ? "greater" : "equal"));
}
return 0;
}

Output:

"Hello" vs "Hello": 0 (equal)
"Hello" vs "World": -15 (less)
"Hello" vs "Hell": 111 (greater)
"Apple" vs "Apple pie": 0 (equal)

6. Common Pitfalls and Undefined Behavior

Pitfall 1: Missing Null Terminator

The most dangerous pitfall: passing a non-null-terminated character array to strlen.

#include <stdio.h>
#include <string.h>
int main() {
// NOT a proper string - no null terminator
char not_a_string[] = {'H', 'e', 'l', 'l', 'o'};
// DANGEROUS: strlen will keep reading past the array until it finds '\0'
// This is UNDEFINED BEHAVIOR (may crash, return garbage, or infinite loop)
// Uncommenting this line could cause a crash or security vulnerability:
// printf("Length: %zu\n", strlen(not_a_string));
// CORRECT: Character array with explicit null terminator
char proper_string[] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("Proper string length: %zu\n", strlen(proper_string));
// CORRECT: String literal (automatically null-terminated)
char literal[] = "Hello";
printf("Literal length: %zu\n", strlen(literal));
return 0;
}

Pitfall 2: Using strlen on Uninitialized Pointers

#include <stdio.h>
#include <string.h>
int main() {
char *uninitialized_ptr;  // Contains garbage address
// DANGEROUS: Using strlen on uninitialized pointer
// This will read from some random memory location
// printf("Length: %zu\n", strlen(uninitialized_ptr));  // CRASH or garbage
// CORRECT: Always initialize pointers
char buffer[100] = "Initialized";
char *good_ptr = buffer;  // Points to valid, null-terminated string
printf("Good pointer length: %zu\n", strlen(good_ptr));
// Or set to NULL and check
char *null_ptr = NULL;
if (null_ptr != NULL) {
printf("%zu\n", strlen(null_ptr));  // Never executed
} else {
printf("Pointer is NULL, can't use strlen\n");
}
return 0;
}

Pitfall 3: Signed/Unsigned Comparison Issues

#include <stdio.h>
#include <string.h>
int main() {
const char *str = "Short";
size_t len = strlen(str);  // Returns 5 (unsigned)
// DANGEROUS: Comparing signed and unsigned
// This works as expected most of the time, but can fail in subtle ways
if (len < 10) {
printf("Length is less than 10\n");  // Works correctly
}
// DANGEROUS: This comparison is ALWAYS false due to unsigned underflow
// len - 10 becomes (5 - 10) which underflows to a very large positive number
if (len - 10 < 0) {  // NEVER true - compiler may warn
printf("This never prints!\n");
}
// CORRECT: Cast to signed when negative comparisons are needed
if ((int)len - 10 < 0) {
printf("Length is less than 10 (cast comparison)\n");
}
// BETTER: Avoid negative comparisons with unsigned types
if (len < 10) {
printf("Length is less than 10 (direct comparison)\n");
}
return 0;
}

Compiler Warning:

warning: comparison of unsigned expression < 0 is always false

Pitfall 4: Modifying String While Using strlen

#include <stdio.h>
#include <string.h>
int main() {
char str[] = "HelloWorld";
// Store length before modification
size_t original_len = strlen(str);
// Modify the string - inserting a null terminator early
str[5] = '\0';  // Now str is "Hello" (first 5 chars)
// Using previously stored length (still 10) could cause issues
printf("Original length (stored): %zu\n", original_len);
printf("Current strlen: %zu\n", strlen(str));
// DANGEROUS: Using out-of-date length to index the string
for (size_t i = 0; i < original_len; i++) {
printf("str[%zu] = '%c' (ASCII %d)\n", i, str[i] ? str[i] : '?', str[i]);
}
return 0;
}

Output:

Original length (stored): 10
Current strlen: 5
str[0] = 'H' (ASCII 72)
str[1] = 'e' (ASCII 101)
str[2] = 'l' (ASCII 108)
str[3] = 'l' (ASCII 108)
str[4] = 'o' (ASCII 111)
str[5] = '?' (ASCII 0)
str[6] = '?' (ASCII 111)
str[7] = '?' (ASCII 114)
str[8] = '?' (ASCII 108)
str[9] = '?' (ASCII 100)

7. Performance Considerations

A. strlen Complexity

strlen has O(n) time complexity, where n is the string length. It must examine each character until it finds the null terminator.

#include <stdio.h>
#include <string.h>
#include <time.h>
#define ITERATIONS 1000000
int main() {
const char *short_str = "Short";
const char *medium_str = "This is a medium length string";
const char *long_str = "This is a much longer string that contains many more characters to demonstrate the linear time complexity of the strlen function as the input size grows larger";
clock_t start, end;
double time_short, time_medium, time_long;
// Measure strlen on short string
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
volatile size_t len = strlen(short_str);
}
end = clock();
time_short = (double)(end - start) / CLOCKS_PER_SEC;
// Measure strlen on medium string
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
volatile size_t len = strlen(medium_str);
}
end = clock();
time_medium = (double)(end - start) / CLOCKS_PER_SEC;
// Measure strlen on long string
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
volatile size_t len = strlen(long_str);
}
end = clock();
time_long = (double)(end - start) / CLOCKS_PER_SEC;
printf("String lengths:\n");
printf("  Short: %zu chars\n", strlen(short_str));
printf("  Medium: %zu chars\n", strlen(medium_str));
printf("  Long: %zu chars\n", strlen(long_str));
printf("\nTime for %d iterations:\n", ITERATIONS);
printf("  Short: %.3f seconds\n", time_short);
printf("  Medium: %.3f seconds\n", time_medium);
printf("  Long: %.3f seconds\n", time_long);
return 0;
}

B. Avoid Calling strlen Repeatedly in Loops

#include <stdio.h>
#include <string.h>
#include <time.h>
#define ITERATIONS 10000000
int main() {
const char *str = "HelloWorld";
clock_t start, end;
// BAD: strlen called on every iteration
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
for (size_t j = 0; j < strlen(str); j++) {
// Do something
volatile char c = str[j];
}
}
end = clock();
double bad_time = (double)(end - start) / CLOCKS_PER_SEC;
// GOOD: strlen called once
start = clock();
size_t len = strlen(str);
for (int i = 0; i < ITERATIONS; i++) {
for (size_t j = 0; j < len; j++) {
// Do something
volatile char c = str[j];
}
}
end = clock();
double good_time = (double)(end - start) / CLOCKS_PER_SEC;
printf("Calling strlen on every iteration: %.3f seconds\n", bad_time);
printf("Calling strlen once: %.3f seconds\n", good_time);
printf("Speedup: %.1fx\n", bad_time / good_time);
return 0;
}

Output (typical):

Calling strlen on every iteration: 0.456 seconds
Calling strlen once: 0.123 seconds
Speedup: 3.7x

C. Manual Pointer Scan (Sometimes Faster for Single Pass)

For operations that need both the length and to process characters, a single pass can be more efficient.

#include <stdio.h>
#include <string.h>
#include <time.h>
#define ITERATIONS 1000000
int main() {
const char *str = "This is a test string for performance comparison";
clock_t start, end;
// Method 1: strlen then process
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
size_t len = strlen(str);
int sum = 0;
for (size_t j = 0; j < len; j++) {
sum += str[j];
}
volatile int result = sum;
}
end = clock();
double method1_time = (double)(end - start) / CLOCKS_PER_SEC;
// Method 2: Single pass (process while finding length)
start = clock();
for (int i = 0; i < ITERATIONS; i++) {
int sum = 0;
const char *ptr = str;
while (*ptr) {
sum += *ptr;
ptr++;
}
volatile int result = sum;
size_t len = ptr - str;  // Length is known after loop
}
end = clock();
double method2_time = (double)(end - start) / CLOCKS_PER_SEC;
printf("Two-pass (strlen + loop): %.3f seconds\n", method1_time);
printf("Single-pass (scan once): %.3f seconds\n", method2_time);
printf("Speedup: %.2fx\n", method1_time / method2_time);
return 0;
}

8. strlen with Different String Types

A. Wide Characters (wcslen)

For wide strings, use wcslen from <wchar.h>.

#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
setlocale(LC_ALL, "");
// Wide string literal
const wchar_t *wstr = L"Hello 世界";
// wcslen is the wide character version of strlen
size_t len = wcslen(wstr);
wprintf(L"Wide string: '%ls'\n", wstr);
wprintf(L"Length: %zu wide characters\n", len);
wprintf(L"Byte size: %zu bytes\n", sizeof(wchar_t) * (len + 1));
// Compare strlen (works on char, not wchar_t)
const char *narrow = "Hello World";
printf("Narrow string length: %zu\n", strlen(narrow));
return 0;
}

B. Strings with Embedded Nulls

strlen stops at the first null terminator, ignoring any characters after.

#include <stdio.h>
#include <string.h>
int main() {
// String with embedded null terminator
char data[] = {'A', 'B', 'C', '\0', 'D', 'E', 'F', '\0'};
printf("Data array: ");
for (int i = 0; i < 8; i++) {
printf("%c ", data[i] ? data[i] : '?');
}
printf("\n");
printf("strlen(data): %zu (stops at first '\\0')\n", strlen(data));
// To get full size including nulls, use sizeof
printf("sizeof(data): %zu total bytes\n", sizeof(data));
// To work with data containing nulls, use mem* functions, not str*
printf("Raw data via memcpy: ");
char output[9] = {0};
memcpy(output, data, sizeof(data));
for (int i = 0; i < 8; i++) {
printf("%c", output[i] ? output[i] : '.');
}
printf("\n");
return 0;
}

Output:

Data array: A B C ? D E F ?
strlen(data): 3 (stops at first '\0')
sizeof(data): 8 total bytes
Raw data via memcpy: ABC.DEF.

9. Building strlen Variants

A. strnlen - Bounded Length (POSIX, C11 Annex K)

#include <stdio.h>
#include <string.h>
// Simple implementation of bounded strlen
size_t my_strnlen(const char *str, size_t maxlen) {
size_t len = 0;
while (len < maxlen && str[len] != '\0') {
len++;
}
return len;
}
int main() {
const char *str = "Hello World";
// strnlen stops at either null terminator or max length
printf("Full string: %zu\n", my_strnlen(str, 100));   // 11
printf("Limited to 5: %zu\n", my_strnlen(str, 5));    // 5
printf("Limited to 20: %zu\n", my_strnlen(str, 20));  // 11
// Useful for safety with potentially unterminated strings
char maybe_unterminated[10] = {'A','B','C','D','E','F','G','H','I','J'};
// No null terminator guaranteed
size_t safe_len = my_strnlen(maybe_unterminated, sizeof(maybe_unterminated));
printf("Safe length of possibly unterminated buffer: %zu\n", safe_len);
return 0;
}

B. strlen with Error Checking

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
// Safe strlen that validates pointer and checks for reasonable length
bool safe_strlen(const char *str, size_t max_check, size_t *out_len) {
if (str == NULL) {
printf("Error: NULL pointer passed to safe_strlen\n");
return false;
}
size_t len = 0;
while (len < max_check && str[len] != '\0') {
len++;
}
if (len >= max_check && str[max_check] != '\0') {
printf("Error: String longer than %zu or missing null terminator\n", max_check);
return false;
}
if (out_len) {
*out_len = len;
}
return true;
}
int main() {
const char *good_str = "Hello";
const char *long_str = "This is a very long string";
const char *null_str = NULL;
size_t len;
if (safe_strlen(good_str, 100, &len)) {
printf("Good string length: %zu\n", len);
}
if (safe_strlen(long_str, 10, &len)) {
printf("This won't print - string exceeds max_check\n");
} else {
printf("Long string exceeded safe limit\n");
}
if (safe_strlen(null_str, 100, &len)) {
printf("This won't print\n");
}
return 0;
}

Output:

Good string length: 5
Error: String longer than 10 or missing null terminator
Long string exceeded safe limit
Error: NULL pointer passed to safe_strlen

10. Complete Reference Implementation

#include <stdio.h>
#include <string.h>
#include <assert.h>
// Comprehensive strlen demonstration with multiple implementations
int main() {
printf("=== C strlen FUNCTION MASTER DEMO ===\n\n");
// 1. Basic usage
const char *str1 = "Hello, World!";
size_t len1 = strlen(str1);
printf("1. Basic: '%s' length = %zu\n", str1, len1);
// 2. Empty string
const char *empty = "";
printf("2. Empty string: strlen('%s') = %zu\n", empty, strlen(empty));
// 3. String with spaces
const char *spaces = "   ";
printf("3. Spaces only: '%s' length = %zu\n", spaces, strlen(spaces));
// 4. Single character
const char *single = "A";
printf("4. Single char: '%s' length = %zu\n", single, strlen(single));
// 5. Very long string
const char *long_str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
printf("5. Long string length: %zu\n", strlen(long_str));
// 6. Strings with escape sequences
const char *escaped = "Hello\n\tWorld\\";
printf("6. With escapes: '%s' strlen = %zu (escape sequences are single chars)\n", 
escaped, strlen(escaped));
// 7. Array vs pointer
char array_str[] = "Array";
const char *ptr_str = "Pointer";
printf("7. Array: strlen = %zu, sizeof = %zu\n", 
strlen(array_str), sizeof(array_str));
printf("   Pointer: strlen = %zu, sizeof = %zu (pointer size!)\n", 
strlen(ptr_str), sizeof(ptr_str));
// 8. Using strlen for loop bounds
printf("8. Iterating with strlen: ");
for (size_t i = 0; i < strlen("Loop"); i++) {
printf("*");
}
printf(" (good practice: store result first)\n");
// 9. strlen return type demonstration
size_t len = strlen("Type");
printf("9. Return type size_t: %zu (unsigned)\n", len);
// 10. Compile-time alternative (for string literals)
#define STR_LITERAL "Compile time"
#define LEN (sizeof(STR_LITERAL) - 1)  // Subtract 1 for null terminator
printf("10. Compile-time length: %d\n", LEN);
// 11. Strings with numbers and punctuation
const char *mixed = "123!@#ABC";
printf("11. Mixed content: '%s' length = %zu\n", mixed, strlen(mixed));
// 12. Unicode/UTF-8 (strlen counts bytes, not codepoints)
const char *utf8 = "Hello 世界";
printf("12. UTF-8 string: '%s'\n", utf8);
printf("    strlen = %zu bytes\n", strlen(utf8));
printf("    (In UTF-8, '世' and '界' are each 3 bytes)\n");
// 13. Performance note - avoid repeated calls
const char *repeated = "Don't call me in a loop";
size_t cached_len = strlen(repeated);
printf("13. Cache strlen result: %zu (call once, reuse)\n", cached_len);
// 14. Common pattern: allocate based on length
const char *source = "Dynamic allocation";
char *copy = malloc(strlen(source) + 1);  // +1 for null terminator
if (copy) {
strcpy(copy, source);
printf("14. Allocation: length %zu, allocated %zu bytes\n", 
strlen(source), strlen(source) + 1);
free(copy);
}
// 15. Verify correct behavior
assert(strlen("") == 0);
assert(strlen("a") == 1);
assert(strlen("abc") == 3);
assert(strlen("abc\0def") == 3);  // Stops at first null
printf("15. All assertions passed\n");
return 0;
}

Output:

=== C strlen FUNCTION MASTER DEMO ===
1. Basic: 'Hello, World!' length = 13
2. Empty string: strlen('') = 0
3. Spaces only: '   ' length = 3
4. Single char: 'A' length = 1
5. Long string length: 57
6. With escapes: 'Hello
World\' strlen = 12 (escape sequences are single chars)
7. Array: strlen = 5, sizeof = 6
Pointer: strlen = 7, sizeof = 8 (pointer size!)
8. Iterating with strlen: ****
9. Return type size_t: 4 (unsigned)
10. Compile-time length: 14
11. Mixed content: '123!@#ABC' length = 9
12. UTF-8 string: 'Hello 世界'
strlen = 12 bytes
(In UTF-8, '世' and '界' are each 3 bytes)
13. Cache strlen result: 21 (call once, reuse)
14. Allocation: length 19, allocated 20 bytes
15. All assertions passed

11. Best Practices Summary

DO ✓

  • Always ensure strings are null-terminated before calling strlen
  • Store the result when using length multiple times: size_t len = strlen(str)
  • Check for NULL pointers before calling strlen if there's any possibility
  • Use size_t for variables that store lengths
  • Add +1 when allocating memory for strings: malloc(strlen(src) + 1)
  • Use strnlen for safety when dealing with potentially unterminated buffers
  • Understand the difference between strlen (runtime, counts characters) and sizeof (compile-time, counts bytes including '\0')

DON'T ✗

  • Don't call strlen repeatedly in loop conditions: for(i=0; i<strlen(s); i++) is inefficient
  • Don't assume strlen won't overflow - extremely long strings could cause issues
  • Don't use strlen on non-null-terminated arrays (undefined behavior)
  • Don't use strlen on NULL pointers (segmentation fault)
  • Don't compare strlen result to negative numbers (it's unsigned)
  • Don't modify the string while relying on a cached length without updating it

Conclusion

The strlen function is deceptively simple but fundamental to C string handling. Its linear-time traversal of memory until finding a null terminator makes it essential for determining string length, but also imposes performance considerations for very large strings or repeated calls.

Key Takeaways:

  • strlen returns the number of characters before the first null terminator
  • The return type size_t is unsigned - be careful with comparisons
  • Time complexity is O(n) - the entire string is scanned
  • Store the result when the same string length is needed multiple times
  • Separate from sizeof: sizeof gives array capacity (including '\0'), strlen gives current length
  • Always ensure null termination before calling strlen
  • For safe bounded length, use strnlen (where available)

Understanding strlen deeply leads to better string handling, fewer bugs, and more efficient code. While simple on the surface, its proper use is a cornerstone of robust C programming.

Complete Guide to Core & Advanced C Programming Concepts (Functions, Strings, Arrays, Loops, I/O, Control Flow)

https://macronepal.com/bash/building-blocks-of-c-a-complete-guide-to-functions/
Explains how functions in C work as reusable blocks of code, including declaration, definition, parameters, return values, and modular programming structure.

https://macronepal.com/bash/the-heart-of-text-processing-a-complete-guide-to-strings-in-c-2/
Explains how strings are handled in C using character arrays, string manipulation techniques, and common library functions for text processing.

https://macronepal.com/bash/the-cornerstone-of-data-organization-a-complete-guide-to-arrays-in-c/
Explains arrays in C as structured memory storage for multiple values, including indexing, initialization, and efficient data organization.

https://macronepal.com/bash/guaranteed-execution-a-complete-guide-to-the-do-while-loop-in-c/
Explains the do-while loop in C, where the loop body executes at least once before checking the condition.

https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-the-for-loop-in-c/
Explains the for loop in C, including initialization, condition checking, and increment/decrement for controlled iteration.

https://macronepal.com/bash/mastering-iteration-a-complete-guide-to-while-loops-in-c/
Explains the while loop in C, focusing on condition-based repetition and proper loop control mechanisms.

https://macronepal.com/bash/beyond-if-else-a-complete-guide-to-switch-case-in-c/
Explains switch-case statements in C, enabling multi-branch decision-making based on variable values.

https://macronepal.com/bash/mastering-conditional-logic-a-complete-guide-to-if-else-statements-in-c/
Explains if-else statements in C for decision-making and controlling program flow based on conditions.

https://macronepal.com/bash/mastering-the-fundamentals-a-complete-guide-to-arithmetic-operations-in-c/
Explains arithmetic operations in C such as addition, subtraction, multiplication, division, and operator precedence.

https://macronepal.com/bash/foundation-of-c-programming-a-complete-guide-to-basic-input-output/
Explains basic input and output in C using scanf and printf for interacting with users and displaying results.

Online C Code Compiler
https://macronepal.com/free-online-c-code-compiler-2/

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper