C Strings
Introduction to Strings in C
In C, a string is a sequence of characters stored in memory and terminated by a null character '\0'
. Unlike some higher-level languages, C doesn't have a dedicated string data type - instead, strings are represented as arrays of characters.
The null character '\0'
(ASCII value 0) marks the end of a string, allowing functions to know where the string terminates.
String Declaration and Initialization
There are several ways to declare and initialize strings in C:
// Method 1: Using string literal (recommended)
char greeting[] = "Hello, World!";
// Method 2: Character by character (with explicit null terminator)
char message[] = {'H', 'e', 'l', 'l', 'o', '\0'};
// Method 3: Specifying size explicitly (size must include space for '\0')
char name[20] = "John";
// Method 4: Declaring first, initializing later
char title[50];
strcpy(title, "C Programming");
When declaring a string with a specific size, always ensure there's enough space for all characters plus the null terminator!
String Memory Representation
Let's look at how a string is stored in memory:
char greeting[] = "Hello";
This is stored as:
Index | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
Value | 'H' | 'e' | 'l' | 'l' | 'o' | '\0' |
Notice that the array has 6 elements even though "Hello" has only 5 characters. The extra element holds the null terminator.
Reading and Writing Strings
Reading Strings
There are several ways to read strings in C:
#include <stdio.h>
char name[50];
// Using scanf (stops at whitespace)
scanf("%s", name);
// Using gets (dangerous, deprecated - can cause buffer overflow)
// gets(name); // Avoid using this!
// Using fgets (safer alternative)
fgets(name, 50, stdin);
Never use gets()
in your code! It doesn't check the buffer size and can lead to serious security vulnerabilities.
Writing Strings
To output strings:
#include <stdio.h>
char name[] = "John Doe";
// Using printf
printf("%s\n", name);
// Using puts (automatically adds a newline)
puts(name);
String Input Pitfalls
When using scanf()
to read strings:
- It stops reading at the first whitespace
- It doesn't check buffer boundaries
Example of a safer approach:
#include <stdio.h>
int main() {
char name[50];
printf("Enter your full name: ");
// Limit input to 49 characters to leave room for '\0'
scanf("%49s", name);
printf("Hello, %s!\n", name);
return 0;
}
For reading input with spaces, fgets()
is preferred:
#include <stdio.h>
#include <string.h>
int main() {
char fullName[50];
printf("Enter your full name: ");
fgets(fullName, 50, stdin);
// Remove the newline character that fgets captures
fullName[strcspn(fullName, "\n")] = '\0';
printf("Hello, %s!\n", fullName);
return 0;
}
String Constants vs Character Arrays
There's an important distinction between these two declarations:
// String literal (read-only)
const char *str1 = "Hello";
// Character array (modifiable)
char str2[] = "Hello";
str1
is a pointer to a read-only string literalstr2
is a modifiable array of characters
Attempting to modify str1
would result in undefined behavior (likely a program crash):
str1[0] = 'h'; // ERROR: Trying to modify a string literal
str2[0] = 'h'; // OK: Modifying a character array
Common String Operations
String Length
To find the length of a string (excluding the null terminator):
#include <stdio.h>
#include <string.h>
int main() {
char message[] = "Hello, World!";
// Using strlen() function
int length = strlen(message);
printf("Length of string: %d\n", length);
return 0;
}
String Comparison
To compare strings:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "apple";
// Returns 0 if equal, <0 if str1 < str2, >0 if str1 > str2
printf("Comparing str1 and str2: %d\n", strcmp(str1, str2));
printf("Comparing str1 and str3: %d\n", strcmp(str1, str3));
return 0;
}
String Copying
To copy one string to another:
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Source string";
char destination[50];
// Copy source to destination
strcpy(destination, source);
// Safer alternative with size limit
strncpy(destination, source, 49);
destination[49] = '\0'; // Ensure null termination
printf("Destination: %s\n", destination);
return 0;
}
String Concatenation
To join strings:
#include <stdio.h>
#include <string.h>
int main() {
char first[50] = "Hello, ";
char second[] = "World!";
// Append second to first
strcat(first, second);
// Safer alternative with size limit
strncat(first, " Welcome!", 49 - strlen(first));
printf("Result: %s\n", first);
return 0;
}
String Manipulation Example
Let's see a comprehensive example that demonstrates various string operations:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void printReverse(char *str);
void toUppercase(char *str);
int main() {
char input[100];
char copy[100];
// Get input from user
printf("Enter a string: ");
fgets(input, 100, stdin);
// Remove newline character
input[strcspn(input, "\n")] = '\0';
// Create a copy
strcpy(copy, input);
// Get and display string length
printf("Length: %lu\n", strlen(input));
// Convert to uppercase
toUppercase(copy);
printf("Uppercase: %s\n", copy);
// Print in reverse
printf("Reversed: ");
printReverse(input);
printf("\n");
return 0;
}
// Function to print a string in reverse
void printReverse(char *str) {
int length = strlen(str);
for (int i = length - 1; i >= 0; i--) {
printf("%c", str[i]);
}
}
// Function to convert string to uppercase
void toUppercase(char *str) {
for (int i = 0; str[i]; i++) {
str[i] = toupper(str[i]);
}
}
Common String-Related Pitfalls
-
Buffer Overflow
cchar name[5];
strcpy(name, "John Doe"); // Overflows the buffer! -
Forgetting Null Terminator
cchar str[5];
str[0] = 'H'; str[1] = 'i';
// Without str[2] = '\0', this isn't a proper string -
Using
==
for Comparisoncchar str1[] = "hello";
char str2[] = "hello";
if (str1 == str2) { // WRONG: Compares addresses, not content
printf("Equal\n");
}
if (strcmp(str1, str2) == 0) { // CORRECT
printf("Equal\n");
}
Conclusion
Strings in C are arrays of characters terminated by a null character. While C doesn't provide a built-in string type, the standard library offers various functions to manipulate strings effectively.
For safe string handling:
- Always ensure enough buffer space
- Use bounded functions like
strncpy()
instead ofstrcpy()
- Always ensure strings are null-terminated
- Use
strcmp()
for string comparison, not==
In the next section, we'll explore the C standard library functions for string manipulation in more detail.
Practice Exercises
- Write a program that reads a string and prints the frequency of each character.
- Create a function that checks if a string is a palindrome.
- Implement a function that removes all spaces from a string.
- Write a program that counts the number of words in a string.
- Create a function that reverses a string in-place (without using a second array).
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)