CoreTechED

Loading

C String Functions: Complete Guide with Examples

Learn C string functions: strlen, strcpy, strcat, strcmp, strchr, strstr, sprintf, strtok. Master safe string manipulation and avoid pitfalls.

C String Functions: Complete Guide with Examples

C String Functions: A Comprehensive Tutorial

String functions in C are built-in library functions used to perform common operations on strings, such as copying, comparing, concatenating, and searching. These functions are declared in the <string.h> header file (except sprintf, which is in <stdio.h>). Understanding string functions is essential for efficient and safe string manipulation in C.

This tutorial provides an in-depth exploration of C string functions: their syntax, usage, return values, common pitfalls, and best practices for safe string handling.


Conceptual Introduction & Fundamentals

What are String Functions?

String functions are pre-written functions that operate on C strings (null-terminated character arrays). They provide standardized, efficient implementations of common string operations, eliminating the need to write manual loops for every string task.

Why Use String Functions?

  • Efficiency: Optimized implementations by compiler/library vendors.
  • Reliability: Well-tested and standardized.
  • Readability: Code is cleaner and more maintainable.
  • Portability: Available on all standard-compliant C implementations.
  • Productivity: Write less code for common operations.

The <string.h> Header

Most string functions are declared in <string.h>. To use them:

c

#include <string.h>

Categories of String Functions

CategoryFunctions
Lengthstrlen
Copystrcpy, strncpy
Concatenatestrcat, strncat
Comparestrcmp, strncmp
Searchstrchr, strrchr, strstr
Formatsprintf (from <stdio.h>)
Tokenizestrtok

Safety Considerations

Many traditional string functions (strcpy, strcat, sprintf) do not check buffer sizes, making them prone to buffer overflows. Prefer safer alternatives:

UnsafeSafer Alternative
strcpystrncpy or snprintf
strcatstrncat or snprintf
sprintfsnprintf
getsfgets

Syntax & Core Mechanics

strlen() — String Length

Returns the number of characters in a string, excluding the null terminator.

c

#include <stdio.h> #include <string.h> int main(void) { char s[] = "Gfg"; size_t length = strlen(s); printf("Length: %zu\n", length); printf("Array size: %zu\n", sizeof(s)); /* Includes null */ return 0; }

Expected output:

text

Length: 3 Array size: 4

strcpy() — String Copy

Copies the source string (including null terminator) to the destination.

c

#include <stdio.h> #include <string.h> int main(void) { char src[] = "Hello"; char dest[20]; strcpy(dest, src); printf("dest: %s\n", dest); return 0; }

Expected output:

text

dest: Hello

strncpy() — Bounded String Copy

Copies at most n characters. If the source is shorter than n, pads with nulls.

c

#include <stdio.h> #include <string.h> int main(void) { char src[] = "Hello"; char dest[20] = "XXXXXXXXXX"; /* Pre-filled for demonstration */ strncpy(dest, src, 4); dest[4] = '\0'; /* Ensure null termination */ printf("dest: %s\n", dest); return 0; }

Expected output:

text

dest: Hell

Note: strncpy does not guarantee null termination if n <= source length. Always add null manually.

strcat() — String Concatenate

Appends source to the end of destination.

c

#include <stdio.h> #include <string.h> int main(void) { char s1[30] = "Hello, "; char s2[] = "Geeks!"; strcat(s1, s2); printf("s1: %s\n", s1); return 0; }

Expected output:

text

s1: Hello, Geeks!

strncat() — Bounded String Concatenate

Appends at most n characters from source to destination.

c

#include <stdio.h> #include <string.h> int main(void) { char s1[30] = "Hello, "; char s2[] = "Geeks!"; strncat(s1, s2, 4); printf("s1: %s\n", s1); return 0; }

Expected output:

text

s1: Hello, Geek

strcmp() — String Compare

Compares two strings lexicographically. Returns:

  • 0 if equal
  • Negative if first < second
  • Positive if first > second

c

#include <stdio.h> #include <string.h> int main(void) { char s1[] = "Apple"; char s2[] = "Applet"; int result = strcmp(s1, s2); if (result == 0) { printf("s1 and s2 are same\n"); } else if (result < 0) { printf("s1 is lexicographically smaller than s2\n"); } else { printf("s1 is lexicographically greater than s2\n"); } return 0; }

Expected output:

text

s1 is lexicographically smaller than s2

strncmp() — Bounded String Compare

Compares first n characters.

c

#include <stdio.h> #include <string.h> int main(void) { char s1[] = "Apple"; char s2[] = "Applet"; int result = strncmp(s1, s2, 4); if (result == 0) { printf("First 4 characters are same\n"); } return 0; }

Expected output:

text

First 4 characters are same

strchr() — Find First Character

Returns pointer to first occurrence of character, or NULL.

c

#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, World!"; char *result = strchr(s, 'o'); if (result != NULL) { printf("Character found at index: %ld\n", result - s); } else { printf("Character not found\n"); } return 0; }

Expected output:

text

Character found at index: 4

strrchr() — Find Last Character

Returns pointer to last occurrence of character.

c

#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, World!"; char *result = strrchr(s, 'o'); if (result != NULL) { printf("Character found at index: %ld\n", result - s); } return 0; }

Expected output:

text

Character found at index: 8

strstr() — Find Substring

Returns pointer to first occurrence of substring.

c

#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, Geeks!"; char *pos = strstr(s, "Geeks"); if (pos != NULL) { printf("Found: %s\n", pos); } else { printf("Not Found\n"); } return 0; }

Expected output:

text

Found: Geeks!

sprintf() — Format String to Buffer

Formats data into a string buffer. Declared in <stdio.h>.

c

#include <stdio.h> int main(void) { char buffer[50]; int n = 10; sprintf(buffer, "The value is %d", n); printf("%s\n", buffer); return 0; }

Expected output:

text

The value is 10

Safer alternative: snprintf

c

char buffer[50]; snprintf(buffer, sizeof(buffer), "The value is %d", n);

strtok() — Tokenize String

Splits a string into tokens based on delimiters. Modifies the original string.

c

#include <stdio.h> #include <string.h> int main(void) { char s[] = "Hello, Geeks, C!"; char *token = strtok(s, ", "); while (token != NULL) { printf("%s\n", token); token = strtok(NULL, ", "); } return 0; }

Expected output:

text

Hello Geeks C!

Note: strtok modifies the original string and is not thread-safe. Use strtok_r for reentrant version (POSIX).


Full Practical Code Example with Explanation

This program demonstrates all major string functions in a realistic scenario: a simple text processing and validation system.

Program: String Functions Demo

c

/** * string_functions_demo.c * Demonstrates all major C string functions. * Includes safe usage patterns and error handling. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <stdbool.h> #define MAX_LINE_LEN 200 #define MAX_STR_LEN 100 /* Function prototypes */ void demonstrateLength(void); void demonstrateCopy(void); void demonstrateConcatenate(void); void demonstrateCompare(void); void demonstrateSearch(void); void demonstrateFormat(void); void demonstrateTokenize(void); int readInteger(const char *prompt, int *outValue); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== C String Functions Demo ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. strlen - String Length\n"); printf("2. strcpy/strncpy - String Copy\n"); printf("3. strcat/strncat - String Concatenate\n"); printf("4. strcmp/strncmp - String Compare\n"); printf("5. strchr/strrchr/strstr - Search\n"); printf("6. sprintf - Format String\n"); printf("7. strtok - Tokenize String\n"); printf("8. Exit\n"); printf("Enter choice: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { fprintf(stderr, "Error reading choice.\n"); return EXIT_FAILURE; } choice = atoi(buffer); switch (choice) { case 1: demonstrateLength(); break; case 2: demonstrateCopy(); break; case 3: demonstrateConcatenate(); break; case 4: demonstrateCompare(); break; case 5: demonstrateSearch(); break; case 6: demonstrateFormat(); break; case 7: demonstrateTokenize(); break; case 8: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Demonstrates strlen */ void demonstrateLength(void) { printf("\n=== strlen ===\n"); char str1[] = "Hello"; char str2[] = ""; char str3[] = "A"; printf("strlen(\"%s\") = %zu\n", str1, strlen(str1)); printf("strlen(\"%s\") = %zu\n", str2, strlen(str2)); printf("strlen(\"%s\") = %zu\n", str3, strlen(str3)); printf("\nManual length calculation:\n"); size_t len = 0; while (str1[len] != '\0') { len++; } printf("Manual strlen(\"%s\") = %zu\n", str1, len); } /* Demonstrates strcpy and strncpy */ void demonstrateCopy(void) { printf("\n=== strcpy / strncpy ===\n"); char src[] = "Hello World"; char dest1[50]; char dest2[20] = "XXXXXXXXXXXXXXXX"; /* Pre-filled */ /* strcpy */ strcpy(dest1, src); printf("strcpy: dest1 = \"%s\"\n", dest1); /* strncpy with explicit null termination */ strncpy(dest2, src, 5); dest2[5] = '\0'; /* Ensure null termination */ printf("strncpy (5 chars): dest2 = \"%s\"\n", dest2); /* strncpy when source is shorter */ char shortSrc[] = "Hi"; char dest3[10] = "XXXXXXXXX"; strncpy(dest3, shortSrc, 5); /* Remaining characters are padded with nulls */ printf("strncpy (short source): dest3[0] = '%c', dest3[1] = '%c', dest3[2] = '%d'\n", dest3[0], dest3[1], dest3[2]); } /* Demonstrates strcat and strncat */ void demonstrateConcatenate(void) { printf("\n=== strcat / strncat ===\n"); char s1[50] = "Hello, "; char s2[] = "Geeks!"; char s3[50] = "Hello, "; /* strcat */ strcat(s1, s2); printf("strcat: \"%s\"\n", s1); /* strncat */ strncat(s3, s2, 4); printf("strncat (4 chars): \"%s\"\n", s3); /* Safe concatenation using snprintf */ char safe[50]; snprintf(safe, sizeof(safe), "%s%s", "Hello, ", "Geeks!"); printf("snprintf: \"%s\"\n", safe); } /* Demonstrates strcmp and strncmp */ void demonstrateCompare(void) { printf("\n=== strcmp / strncmp ===\n"); char s1[] = "Apple"; char s2[] = "Applet"; char s3[] = "apple"; printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s2, strcmp(s1, s2)); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s3, strcmp(s1, s3)); printf("strcmp(\"%s\", \"%s\") = %d\n", s1, s1, strcmp(s1, s1)); printf("strncmp(\"%s\", \"%s\", 4) = %d\n", s1, s2, strncmp(s1, s2, 4)); printf("strncmp(\"%s\", \"%s\", 5) = %d\n", s1, s2, strncmp(s1, s2, 5)); } /* Demonstrates search functions */ void demonstrateSearch(void) { printf("\n=== Search Functions ===\n"); char s[] = "Hello, World! Hello again!"; /* strchr */ char *first_o = strchr(s, 'o'); if (first_o != NULL) { printf("strchr: first 'o' at index %ld\n", first_o - s); } /* strrchr */ char *last_o = strrchr(s, 'o'); if (last_o != NULL) { printf("strrchr: last 'o' at index %ld\n", last_o - s); } /* strstr */ char *substring = strstr(s, "World"); if (substring != NULL) { printf("strstr: \"World\" found at index %ld\n", substring - s); printf(" Remaining: \"%s\"\n", substring); } /* strchr with character not in string */ char *notFound = strchr(s, 'z'); if (notFound == NULL) { printf("strchr: 'z' not found (NULL returned)\n"); } } /* Demonstrates sprintf */ void demonstrateFormat(void) { printf("\n=== sprintf / snprintf ===\n"); char buffer[100]; int age = 25; double score = 95.5; char name[] = "Alice"; /* sprintf */ sprintf(buffer, "Name: %s, Age: %d, Score: %.2f", name, age, score); printf("sprintf: \"%s\"\n", buffer); /* snprintf (safer) */ snprintf(buffer, sizeof(buffer), "Name: %s, Age: %d, Score: %.2f", name, age, score); printf("snprintf: \"%s\"\n", buffer); /* snprintf with truncation */ snprintf(buffer, 10, "Name: %s", "VeryLongNameHere"); printf("snprintf (truncated): \"%s\"\n", buffer); } /* Demonstrates strtok */ void demonstrateTokenize(void) { printf("\n=== strtok ===\n"); char s[] = "Hello, Geeks, C, Programming!"; char *delimiter = ", "; printf("Original string: \"%s\"\n", s); printf("Tokens:\n"); char *token = strtok(s, delimiter); int tokenCount = 0; while (token != NULL) { printf(" Token %d: \"%s\"\n", ++tokenCount, token); token = strtok(NULL, delimiter); } printf("After strtok, original string: \"%s\"\n", s); printf("(Original string has been modified)\n"); }

Explanation of String Functions

  1. strlen: Counts characters until null.
  2. strcpy / strncpy: Copies strings; strncpy requires manual null termination.
  3. strcat / strncat: Appends strings; strncat is safer.
  4. strcmp / strncmp: Lexicographic comparison.
  5. strchr / strrchr / strstr: Search for characters/substrings.
  6. sprintf / snprintf: Format strings into buffers.
  7. strtok: Tokenizes strings (modifies original).

Expected Output (sample run)

text

=== C String Functions Demo === --- Menu --- 1. strlen - String Length 2. strcpy/strncpy - String Copy 3. strcat/strncat - String Concatenate 4. strcmp/strncmp - String Compare 5. strchr/strrchr/strstr - Search 6. sprintf - Format String 7. strtok - Tokenize String 8. Exit Enter choice: 1 === strlen === strlen("Hello") = 5 strlen("") = 0 strlen("A") = 1 Manual length calculation: Manual strlen("Hello") = 5 --- Menu --- ... Enter choice: 7 === strtok === Original string: "Hello, Geeks, C, Programming!" Tokens: Token 1: "Hello" Token 2: "Geeks" Token 3: "C" Token 4: "Programming!" After strtok, original string: "Hello" (Original string has been modified)

Common Pitfalls, Edge Cases & Memory Considerations

1. Buffer Overflow with strcpy and strcat

These functions don’t check destination size, causing buffer overflows.

c

char dest[5]; strcpy(dest, "Hello World"); // BUG: overflow (12 chars into 5-byte buffer)

Solution: Use strncpy with manual null termination, or snprintf.

2. strncpy Not Null-Terminating

If n is less than or equal to the source length, strncpy does not add null terminator.

c

char src[] = "Hello"; char dest[5]; strncpy(dest, src, 5); // dest is not null-terminated printf("%s\n", dest); // BUG: reads past buffer

Solution: Always add null: dest[4] = '\0';

3. strlen on Uninitialized String

Calling strlen on an uninitialized string is undefined behavior.

c

char str[20]; strlen(str); // BUG: garbage data

Solution: Initialize strings: char str[20] = "";

4. strtok Modifies Original String

strtok replaces delimiters with null characters, destroying the original string.

c

char s[] = "Hello, World"; strtok(s, ", "); printf("%s\n", s); // Prints "Hello" (original modified)

Solution: Make a copy before using strtok if you need the original.

5. strtok Not Thread-Safe

strtok uses a static internal buffer, making it unsafe in multi-threaded programs.

Solution: Use strtok_r (POSIX) for thread-safe tokenization.

6. sprintf Buffer Overflow

sprintf does not check buffer size.

c

char buffer[10]; sprintf(buffer, "Value: %d", 123456789); // BUG: overflow

Solution: Use snprintf(buffer, sizeof(buffer), ...).

7. strcmp with Non-String Data

strcmp expects null-terminated strings. Passing non-string data is undefined.

c

char data[5] = {'A', 'B', 'C', 'D', 'E'}; // No null strcmp(data, "ABCDE"); // BUG: data is not a string

Solution: Ensure null termination: char data[6] = {'A', 'B', 'C', 'D', 'E', '\0'};

8. strchr Returning NULL

Dereferencing the result of strchr without checking for NULL causes crash.

c

char *result = strchr(s, 'z'); printf("%c\n", *result); // BUG: NULL dereference if not found

Solution: Always check for NULL before dereferencing.

9. String Concatenation Overhead

Repeated strcat calls in loops are inefficient (O(n²) due to repeated scanning).

Solution: Track the end position and copy directly, or use snprintf for combined formatting.

10. Memory Considerations

  • strtok uses static memory (not thread-safe).
  • strcpy and strcat do not allocate memory; they write to existing buffers.
  • Always ensure destination buffers are large enough.
  • Consider using strdup (POSIX) to create copies on the heap (remember to free).

Summary & Best Practices

C string functions provide powerful tools for string manipulation. Understanding their behavior, limitations, and safe usage patterns is essential for writing robust programs.

Key Takeaways

  • strlen returns length excluding null.
  • strcpy/strncpy copy strings; strncpy needs manual null termination.
  • strcat/strncat concatenate strings; strncat is safer.
  • strcmp/strncmp compare strings lexicographically.
  • strchr/strrchr/strstr search for characters/substrings.
  • sprintf/snprintf format strings (prefer snprintf).
  • strtok tokenizes strings (modifies original, not thread-safe).

Best Practices

  1. Prefer snprintf over sprintf for safe formatting.
  2. Use strncpy with manual null termination or snprintf instead of strcpy.
  3. Use strncat instead of strcat for bounded concatenation.
  4. Always check for NULL from search functions before dereferencing.
  5. Make a copy before using strtok if the original string is needed.
  6. Use strtok_r in multi-threaded programs.
  7. Ensure destination buffers are large enough for all operations.
  8. Initialize strings before using string functions.
  9. Use sizeof for buffer capacity when calling snprintf or fgets.
  10. Enable compiler warnings (-Wall -Wextra) to catch potential issues.

By mastering C string functions and following safe practices, you’ll write robust programs that handle text processing efficiently without buffer overflows or undefined behavior.

Leave a Reply

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