Strings in C: Complete Guide with Examples
Strings in C: A Comprehensive Tutorial
A string in C is a sequence of characters stored in a character array and terminated by the null character '\0'. Since C does not provide a built-in string data type, strings are represented using char arrays. Understanding strings is essential for text processing, user input handling, file I/O, and many other applications.
This tutorial provides an in-depth exploration of strings in C: declaration, initialization, accessing characters, string functions, input methods, passing to functions, pointers, string literals, common pitfalls, and best practices.
Conceptual Introduction & Fundamentals
What is a String in C?
A string is a contiguous sequence of characters terminated by a null character ('\0'). The null character marks the end of the string and is used by string functions to determine where the string ends.
Example:
c
char str[] = "Geeks";
Internal representation:
text
Index: 0 1 2 3 4 5 Char: 'G' 'e' 'e' 'k' 's' '\0'
Why Strings Matter
- Text processing: Names, addresses, messages, file content.
- User input: Reading and validating user-entered data.
- File I/O: Reading and writing text files.
- Data serialization: Converting data to/from string representations.
- Communication: Network protocols, APIs.
Key Characteristics
- Strings are arrays of
char. - Null terminator
'\0'marks the end. - String length excludes the null terminator.
- String capacity includes the null terminator.
- String literals are stored in read-only memory.
String vs. Character Array
| Aspect | String | Character Array |
|---|---|---|
| Null terminator | Always present | Optional |
| Functions | String functions (strlen, strcpy, etc.) | Array operations |
| Initialization | "text" | {'t', 'e', 'x', 't'} |
| Size | Length + 1 (for null) | Exact number of elements |
Syntax & Core Mechanics
Declaration and Initialization
c
#include <stdio.h> int main(void) { /* Method 1: String literal */ char str1[] = "Geeks"; /* Creates: {'G', 'e', 'e', 'k', 's', '\0'} */ /* Method 2: Character array */ char str2[] = {'G', 'e', 'e', 'k', 's', '\0'}; /* Method 3: Fixed size with initialization */ char str3[10] = "Hello"; /* Remaining elements are '\0' */ /* Method 4: Pointer to string literal */ const char *str4 = "World"; printf("str1: %s\n", str1); printf("str2: %s\n", str2); printf("str3: %s\n", str3); printf("str4: %s\n", str4); return 0; } Expected output:
text
str1: Geeks str2: Geeks str3: Hello str4: World
Accessing Characters
Characters are accessed using array indexing (0-based).
c
#include <stdio.h> int main(void) { char str[] = "Geeks"; printf("First character: %c\n", str[0]); printf("Second character: %c\n", str[1]); printf("Last character (before null): %c\n", str[4]); printf("Null terminator: %d\n", str[5]); /* Prints 0 */ return 0; } Expected output:
text
First character: G Second character: e Last character (before null): s Null terminator: 0
Updating Characters
c
#include <stdio.h> int main(void) { char str[] = "Geeks"; str[0] = 'R'; /* Change 'G' to 'R' */ printf("Updated string: %s\n", str); return 0; } Expected output:
text
Updated string: Reeks
String Length with strlen
c
#include <stdio.h> #include <string.h> int main(void) { char str[] = "Geeks"; size_t length = strlen(str); printf("Length of \"%s\": %zu\n", str, length); printf("Size of array: %zu (includes null)\n", sizeof(str)); return 0; } Expected output:
text
Length of "Geeks": 5 Size of array: 6 (includes null)
Common String Functions
| Function | Description |
|---|---|
strlen | Returns string length (excluding null) |
strcpy | Copies one string to another |
strncpy | Copies up to n characters |
strcat | Concatenates two strings |
strncat | Concatenates up to n characters |
strcmp | Compares two strings |
strncmp | Compares up to n characters |
strchr | Finds first occurrence of character |
strstr | Finds substring |
sprintf | Writes formatted string to buffer |
c
#include <stdio.h> #include <string.h> int main(void) { char dest[50] = "Hello"; char src[] = " World"; char buffer[100]; /* strcat */ strcat(dest, src); printf("After strcat: %s\n", dest); /* strcpy */ strcpy(dest, "Goodbye"); printf("After strcpy: %s\n", dest); /* strcmp */ int result = strcmp("apple", "banana"); printf("strcmp result: %d (negative means apple < banana)\n", result); /* sprintf */ sprintf(buffer, "Value: %d, Name: %s", 42, "Alice"); printf("sprintf result: %s\n", buffer); return 0; } Expected output:
text
After strcat: Hello World After strcpy: Goodbye strcmp result: -1 (negative means apple < banana) sprintf result: Value: 42, Name: Alice
String Input
Using scanf (Single Word)
c
#include <stdio.h> int main(void) { char str[20]; printf("Enter a word: "); scanf("%19s", str); /* Limit to 19 chars + null */ printf("You entered: %s\n", str); return 0; } Sample run:
text
Enter a word: Hello You entered: Hello
Limitation: Stops at whitespace.
Using scanf with Scanset (Read Line with Spaces)
c
#include <stdio.h> int main(void) { char str[50]; printf("Enter a sentence: "); scanf("%49[^\n]", str); /* Read until newline */ printf("You entered: %s\n", str); return 0; } Sample run:
text
Enter a sentence: Hello World You entered: Hello World
Using fgets (Recommended)
c
#include <stdio.h> #include <string.h> int main(void) { char str[50]; printf("Enter a sentence: "); if (fgets(str, sizeof(str), stdin) != NULL) { /* Remove trailing newline */ str[strcspn(str, "\n")] = '\0'; printf("You entered: %s\n", str); } return 0; } Sample run:
text
Enter a sentence: Hello World You entered: Hello World
Passing Strings to Functions
c
#include <stdio.h> void printString(const char str[]) { printf("%s\n", str); } int main(void) { char str[] = "GeeksforGeeks"; printString(str); return 0; } Expected output:
text
GeeksforGeeks
Strings and Pointers
c
#include <stdio.h> int main(void) { char str[20] = "Geeks"; char *ptr = str; /* Traverse using pointer arithmetic */ while (*ptr != '\0') { printf("%c", *ptr); ptr++; } printf("\n"); return 0; } Expected output:
text
Geeks
String Literals
String literals are stored in read-only memory. Use const char * to prevent modification.
c
#include <stdio.h> int main(void) { const char *str = "Hello World"; printf("%s\n", str); /* str[0] = 'h'; // BUG: modifying read-only memory */ /* To modify, use a character array */ char mutable[] = "Hello World"; mutable[0] = 'h'; printf("%s\n", mutable); return 0; } Expected output:
text
Hello World hello World
Full Practical Code Example with Explanation
This program demonstrates strings in a realistic scenario: a simple text processing system with string manipulation.
Program: String Operations Manager
c
/** * string_operations.c * Demonstrates strings: initialization, access, modification, * string functions, input, and pointer traversal. * Manages a list of names with search and sort functionality. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <stdbool.h> #define MAX_NAMES 100 #define MAX_NAME_LEN 50 #define MAX_LINE_LEN 200 /* Function prototypes */ void demonstrateStringBasics(void); void demonstrateStringFunctions(void); void demonstrateStringInput(void); void demonstrateStringPointers(void); void demonstrateStringLiterals(void); void sortNames(char names[][MAX_NAME_LEN], int count); int searchName(const char names[][MAX_NAME_LEN], int count, const char *target); void displayNames(const char names[][MAX_NAME_LEN], int count); int readInteger(const char *prompt, int *outValue); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== String Operations Manager ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. String Basics\n"); printf("2. String Functions\n"); printf("3. String Input (fgets)\n"); printf("4. Strings and Pointers\n"); printf("5. String Literals\n"); printf("6. Name Sorting and Search\n"); printf("7. 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: demonstrateStringBasics(); break; case 2: demonstrateStringFunctions(); break; case 3: demonstrateStringInput(); break; case 4: demonstrateStringPointers(); break; case 5: demonstrateStringLiterals(); break; case 6: { char names[MAX_NAMES][MAX_NAME_LEN]; int nameCount = 0; printf("\nEnter names (type 'done' to finish):\n"); while (nameCount < MAX_NAMES) { char input[MAX_NAME_LEN]; printf("Name %d: ", nameCount + 1); fflush(stdout); if (fgets(input, sizeof(input), stdin) == NULL) { break; } input[strcspn(input, "\n")] = '\0'; if (strcmp(input, "done") == 0) { break; } strncpy(names[nameCount], input, MAX_NAME_LEN - 1); names[nameCount][MAX_NAME_LEN - 1] = '\0'; nameCount++; } printf("\nOriginal names:\n"); displayNames(names, nameCount); sortNames(names, nameCount); printf("\nSorted names:\n"); displayNames(names, nameCount); char searchTarget[MAX_NAME_LEN]; printf("\nEnter name to search: "); fflush(stdout); if (fgets(searchTarget, sizeof(searchTarget), stdin) != NULL) { searchTarget[strcspn(searchTarget, "\n")] = '\0'; int index = searchName(names, nameCount, searchTarget); if (index != -1) { printf("Found '%s' at position %d\n", searchTarget, index + 1); } else { printf("'%s' not found.\n", searchTarget); } } break; } case 7: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Demonstrates string basics */ void demonstrateStringBasics(void) { printf("\n=== String Basics ===\n"); char str1[] = "Geeks"; char str2[] = {'H', 'e', 'l', 'l', 'o', '\0'}; char str3[10] = "Hi"; printf("str1: %s\n", str1); printf("str2: %s\n", str2); printf("str3: %s\n", str3); printf("\nAccessing characters:\n"); printf("str1[0] = %c\n", str1[0]); printf("str1[1] = %c\n", str1[1]); printf("\nUpdating characters:\n"); str1[0] = 'P'; printf("str1 after update: %s\n", str1); printf("\nLength:\n"); printf("strlen(str1) = %zu\n", strlen(str1)); printf("sizeof(str1) = %zu (includes null)\n", sizeof(str1)); } /* Demonstrates string functions */ void demonstrateStringFunctions(void) { printf("\n=== String Functions ===\n"); char dest[100] = "Hello"; char src[] = " World"; char buffer[200]; /* strcat */ strcat(dest, src); printf("After strcat: %s\n", dest); /* strcpy */ strcpy(dest, "Goodbye"); printf("After strcpy: %s\n", dest); /* strcmp */ printf("strcmp(\"apple\", \"banana\") = %d\n", strcmp("apple", "banana")); printf("strcmp(\"same\", \"same\") = %d\n", strcmp("same", "same")); /* sprintf */ sprintf(buffer, "Name: %s, Age: %d, Score: %.2f", "Alice", 25, 95.5); printf("sprintf: %s\n", buffer); /* strchr */ char *ptr = strchr(dest, 'd'); if (ptr != NULL) { printf("strchr: found 'd' at position %ld\n", ptr - dest); } } /* Demonstrates string input */ void demonstrateStringInput(void) { printf("\n=== String Input ===\n"); char str[MAX_NAME_LEN]; printf("Enter your full name: "); fflush(stdout); if (fgets(str, sizeof(str), stdin) != NULL) { /* Remove trailing newline */ str[strcspn(str, "\n")] = '\0'; printf("Hello, %s!\n", str); printf("String length: %zu\n", strlen(str)); } } /* Demonstrates strings and pointers */ void demonstrateStringPointers(void) { printf("\n=== Strings and Pointers ===\n"); char str[20] = "Geeks"; char *ptr = str; printf("Using array indexing: "); for (int i = 0; str[i] != '\0'; i++) { printf("%c", str[i]); } printf("\n"); printf("Using pointer arithmetic: "); while (*ptr != '\0') { printf("%c", *ptr); ptr++; } printf("\n"); printf("Using pointer indexing: "); ptr = str; for (int i = 0; ptr[i] != '\0'; i++) { printf("%c", ptr[i]); } printf("\n"); } /* Demonstrates string literals */ void demonstrateStringLiterals(void) { printf("\n=== String Literals ===\n"); const char *literal = "Hello World"; printf("String literal: %s\n", literal); /* Attempting to modify a string literal is undefined behavior */ /* literal[0] = 'h'; // BUG: read-only memory */ /* To modify, use a character array */ char mutable[] = "Hello World"; mutable[0] = 'h'; printf("Mutable string: %s\n", mutable); /* String literal addresses */ printf("Literal address: %p\n", (void*)literal); printf("Mutable array address: %p\n", (void*)mutable); } /* Sorts names alphabetically using bubble sort */ void sortNames(char names[][MAX_NAME_LEN], int count) { for (int i = 0; i < count - 1; i++) { for (int j = 0; j < count - i - 1; j++) { if (strcmp(names[j], names[j + 1]) > 0) { char temp[MAX_NAME_LEN]; strcpy(temp, names[j]); strcpy(names[j], names[j + 1]); strcpy(names[j + 1], temp); } } } } /* Searches for a name; returns index or -1 */ int searchName(const char names[][MAX_NAME_LEN], int count, const char *target) { for (int i = 0; i < count; i++) { if (strcmp(names[i], target) == 0) { return i; } } return -1; } /* Displays all names */ void displayNames(const char names[][MAX_NAME_LEN], int count) { if (count == 0) { printf("No names to display.\n"); return; } for (int i = 0; i < count; i++) { printf("%d. %s\n", i + 1, names[i]); } } Explanation of String Usage
- String basics: Declaration, initialization, character access, modification.
- String functions:
strcat,strcpy,strcmp,sprintf,strchr. - String input:
fgetswith newline removal. - Strings and pointers: Traversal using array indexing, pointer arithmetic, and pointer indexing.
- String literals: Read-only vs. mutable strings.
- Name sorting and search: Practical application using
strcmpandstrcpy.
Expected Output (sample run)
text
=== String Operations Manager === --- Menu --- 1. String Basics 2. String Functions 3. String Input (fgets) 4. Strings and Pointers 5. String Literals 6. Name Sorting and Search 7. Exit Enter choice: 1 === String Basics === str1: Geeks str2: Hello str3: Hi Accessing characters: str1[0] = G str1[1] = e Updating characters: str1 after update: Peeks Length: strlen(str1) = 5 sizeof(str1) = 6 (includes null) --- Menu --- ... Enter choice: 3 === String Input === Enter your full name: John Michael Doe Hello, John Michael Doe! String length: 16 --- Menu --- ... Enter choice: 6 Enter names (type 'done' to finish): Name 1: Charlie Name 2: Alice Name 3: Bob Name 4: done Original names: 1. Charlie 2. Alice 3. Bob Sorted names: 1. Alice 2. Bob 3. Charlie Enter name to search: Bob Found 'Bob' at position 2
Common Pitfalls, Edge Cases & Memory Considerations
1. Missing Null Terminator
Forgetting the null terminator causes undefined behavior when using string functions.
c
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // Missing '\0' printf("%s\n", str); // BUG: reads past array Solution: Ensure null terminator: char str[] = "Hello"; or char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
2. Buffer Overflow with strcpy and strcat
These functions don’t check destination size.
c
char dest[5]; strcpy(dest, "Hello World"); // BUG: buffer overflow
Solution: Use strncpy or snprintf with size limits.
3. Using gets (Removed in C11)
gets is inherently unsafe and was removed from C11.
c
gets(str); // BUG: never use gets
Solution: Use fgets(str, sizeof(str), stdin).
4. Modifying String Literals
String literals are in read-only memory; modifying them is undefined behavior.
c
char *str = "Hello"; str[0] = 'h'; // BUG: modifying read-only memory
Solution: Use const char * for literals, or char str[] = "Hello"; for mutable strings.
5. scanf Buffer Overflow
scanf("%s", str) reads unlimited characters, causing overflow.
c
char str[10]; scanf("%s", str); // BUG: overflow if input > 9 chars Solution: Use width limit: scanf("%9s", str); or use fgets.
6. Trailing Newline with fgets
fgets includes the newline character if it fits.
c
char str[20]; fgets(str, sizeof(str), stdin); printf("[%s]\n", str); // Prints "Hello\n" Solution: Remove newline: str[strcspn(str, "\n")] = '\0';
7. strlen vs sizeof
strlen returns string length (excluding null); sizeof returns array capacity (including null).
c
char str[20] = "Hi"; strlen(str); // 2 sizeof(str); // 20
Solution: Use strlen for string length, sizeof for capacity.
8. Passing Strings to Functions
Strings decay to pointers; sizeof gives pointer size.
c
void func(char str[]) { sizeof(str); // Pointer size, not array size } Solution: Pass string length separately, or use strlen.
9. Uninitialized String
Reading an uninitialized string is undefined behavior.
c
char str[20]; printf("%s\n", str); // BUG: garbage Solution: Initialize: char str[20] = ""; or char str[20] = {0};
10. Memory Considerations
- String literals are stored in read-only memory.
- Character arrays are stored on stack (or data segment if static).
- Dynamically allocated strings (
malloc) must be freed. strlenis O(n); avoid calling it repeatedly in loops.
Summary & Best Practices
Strings in C are character arrays terminated by '\0'. They are essential for text processing and require careful handling to avoid buffer overflows and undefined behavior.
Key Takeaways
- Strings are
chararrays with null terminator. - Use
%sfor printing,strlenfor length. - Use
fgetsfor safe input (avoidgets). - String literals are read-only; use
const char *. - Array indexing and pointer arithmetic both work for traversal.
- Pass strings to functions as
char[]orchar *.
Best Practices
- Use
fgetsfor all string input; never usegetsor unboundedscanf. - Remove trailing newline from
fgetsinput. - Use
strncpyorsnprintfinstead ofstrcpyandsprintf. - Use
const char *for string literals to prevent modification. - Always ensure null terminator when building strings manually.
- Use
sizeoffor capacity,strlenfor length. - Validate input lengths before processing.
- Use
strcmpfor comparison, not==. - Free dynamically allocated strings to prevent leaks.
- Enable compiler warnings (
-Wall -Wextra) to catch string issues.
By mastering strings in C, you’ll write robust programs that handle text processing, user input, and data manipulation safely and efficiently.



