CoreTechED

Loading

Strings in C: Complete Guide with Examples

Learn C strings: declaration, initialization, string functions, fgets input, pointers, and string literals. Master safe string handling and avoid pitfalls.

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

AspectStringCharacter Array
Null terminatorAlways presentOptional
FunctionsString functions (strlen, strcpy, etc.)Array operations
Initialization"text"{'t', 'e', 'x', 't'}
SizeLength + 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

FunctionDescription
strlenReturns string length (excluding null)
strcpyCopies one string to another
strncpyCopies up to n characters
strcatConcatenates two strings
strncatConcatenates up to n characters
strcmpCompares two strings
strncmpCompares up to n characters
strchrFinds first occurrence of character
strstrFinds substring
sprintfWrites 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

  1. String basics: Declaration, initialization, character access, modification.
  2. String functions: strcat, strcpy, strcmp, sprintf, strchr.
  3. String input: fgets with newline removal.
  4. Strings and pointers: Traversal using array indexing, pointer arithmetic, and pointer indexing.
  5. String literals: Read-only vs. mutable strings.
  6. Name sorting and search: Practical application using strcmp and strcpy.

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.
  • strlen is 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 char arrays with null terminator.
  • Use %s for printing, strlen for length.
  • Use fgets for safe input (avoid gets).
  • String literals are read-only; use const char *.
  • Array indexing and pointer arithmetic both work for traversal.
  • Pass strings to functions as char[] or char *.

Best Practices

  1. Use fgets for all string input; never use gets or unbounded scanf.
  2. Remove trailing newline from fgets input.
  3. Use strncpy or snprintf instead of strcpy and sprintf.
  4. Use const char * for string literals to prevent modification.
  5. Always ensure null terminator when building strings manually.
  6. Use sizeof for capacity, strlen for length.
  7. Validate input lengths before processing.
  8. Use strcmp for comparison, not ==.
  9. Free dynamically allocated strings to prevent leaks.
  10. 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.

Leave a Reply

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