Dr. Roger Ianjamasimanana

How to use strings in C programming?

By Dr. Roger Ianjamasimanana

1. What are strings in C?

A string in C is essentially an array of characters terminated by a null character (`'\0'`), allowing functions to determine where the string ends. Unlike some other programming languages, C does not have a built-in string type, so strings are managed using character arrays.

2. Declaring strings in C

Strings can be declared in C in several ways, primarily using character arrays or pointers. Here are the common methods:

2.1 Using character arrays

char str1[] = "Hello, World!";
char str2[20] = "How are you?";

In the first example, the size of the array is automatically determined based on the string length, including the null terminator. In the second example, the array size is explicitly specified, allowing for modification or expansion of the string content.

2.2 Using pointers

char *str3 = "Hello, World!";
char *str4 = malloc(20 * sizeof(char));
strcpy(str4, "How are you?");

Using pointers allows for dynamic memory allocation and manipulation. However, it's essential to manage memory properly to avoid leaks and undefined behavior.

3. Properties of strings

3.1 Mutable strings

When strings are stored in character arrays, their contents can be modified.

//Mutable strings
# include <stdio.h>
int main()
    {
        char str[] = "Hello";
        printf("String before modification: %s\n", str );
        str[0] = 'h'; // str now contains "hello";
        printf("String after modification: %s\n", str );
        return 0;
   }

3.2 Immutable strings

String literals stored as pointers are typically immutable. Attempting to modify them leads to undefined behavior.

 // Immutable strings
# include <stdio.h>
int main()
    {
        char *str = "Hello";
        str[0] = 'h'; // This will lead to undefined behavior
        return 0;
    }

3. Common string functions in C

C provides a rich set of functions for string manipulation through the string.h library. Here are some of the most commonly used string.h functions. Scroll to the right to see the full table.

string.h functions Descriptions Example C programs Outputs
strlen() Calculates the length of a string, excluding the null terminator.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Search";
    printf("The length of str is: %lu\n", strlen(str));
    return 0;
}

The length of str is: 6
strcpy() Copies one string to another. Destination must have enough space.
#include <stdio.h>
#include <string.h>

int main(void) {
    char source[] = "Hello";
    char destination[10];
    strcpy(destination, source);
    printf("Destination: %s\n", destination);
    return 0;
}

Destination: Hello
strcat() Concatenates (appends) one string to the end of another.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str1[20] = "Hello, ";
    char str2[] = "World!";
    strcat(str1, str2);
    printf("Concatenated String: %s\n", str1);
    return 0;
}

Concatenated String: Hello, World!
strncat() Appends a specified number of characters from one string to another.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str1[15] = "Hello";
    char str2[] = ", World!";
    strncat(str1, str2, 7);
    printf("str1: %s\n", str1);
    return 0;
}

str1: Hello, Worl
strcmp() Compares two strings lexicographically.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str1[] = "Apple";
    char str2[] = "Banana";
    int result = strcmp(str1, str2);
    if(result == 0)
        printf("Strings are equal.\n");
    else if(result < 0)
        printf("str1 is less than str2.\n");
    else
        printf("str1 is greater than str2.\n");
    return 0;
}

str1 is less than str2.
strncmp() Compares a specified number of characters from two strings.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str1[] = "Open the door.";
    char str2[] = "Open the gate.";
    int result = strncmp(str1, str2, 4);
    if(result == 0)
        printf("The first 4 characters are equal.\n");
    else
        printf("The first 4 characters are not equal.\n");
    return 0;
}

The first 4 characters are equal.
strchr() Finds the first occurrence of a character in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Hello, World!";
    char *ptr = strchr(str, 'W');
    if(ptr != NULL)
        printf("Character 'W' found at position: %ld\n", ptr - str);
    else
        printf("Character 'W' not found.\n");
    return 0;
}

Character 'W' found at position: 7
strrchr() Finds the last occurrence of a character in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Hello, World!";
    char *ptr = strrchr(str, 'l');
    if(ptr != NULL)
        printf("Last 'l' found at position: %ld\n", ptr - str);
    else
        printf("Character 'l' not found.\n");
    return 0;
}

Last 'l' found at position: 10
strstr() Finds the first occurrence of a substring in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Do you want to chat with me?";
    char *ptr = strstr(str, "chat");
    if(ptr != NULL)
        printf("The substring 'chat' is found at position: %ld\n", ptr - str);
    else
        printf("The substring 'chat' is not found.\n");
    return 0;
}

The substring 'chat' is found at position: 15
memset() Fills a block of memory with a specific value.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[20] = "Hello, World!";
    memset(str + 7, 'X', 5);
    printf("Modified string: %s\n", str);
    return 0;
}

Modified string: Hello, XXXXX!
memcpy() Copies a specified number of bytes from source to destination.
#include <stdio.h>
#include <string.h>

int main(void) {
    char source[] = "Search";
    char destination[10];
    memcpy(destination, source, strlen(source) + 1); // +1 for null terminator
    printf("Destination: %s\n", destination);
    return 0;
}

Destination: Search
memmove() Copies a specified number of bytes from source to destination, handling overlapping regions safely.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "12345";
    memmove(str + 2, str, 3); // Overlapping regions
    printf("Modified string: %s\n", str);
    return 0;
}

Modified string: 12123
memcmp() Compares a specified number of bytes from two memory blocks.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str1[] = "ABCDEF";
    char str2[] = "ABCXYZ";
    int result = memcmp(str1, str2, 3);
    if(result == 0)
        printf("First 3 bytes are equal.\n");
    else
        printf("First 3 bytes are not equal.\n");
    return 0;
}

First 3 bytes are equal.
memchr() Searches for the first occurrence of a character in a memory block.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Random Character";
    char *ptr = memchr(str, 'C', strlen(str));
    if(ptr != NULL)
        printf("The character 'C' is found at position: %ld\n", ptr - str);
    else
        printf("The character 'C' is not found.\n");
    return 0;
}

The character 'C' is found at position: 7
strspn() Calculates the length of the initial segment of a string containing only characters from a specified set.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "abcdef123";
    char set[] = "abcdef";
    size_t len = strspn(str, set);
    printf("Length of initial segment matching set: %lu\n", len);
    return 0;
}

Length of initial segment matching set: 6
strcspn() This function cans the string s1 (the source string) and returns the length of the initial segment of s1 that consists entirely of characters not found in the string s2 (the reject string)
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "abcdef123";
    char set[] = "123";
    size_t len = strcspn(str, set);
    printf("Length of initial segment without set: %lu\n", len);
    return 0;
}

Length of initial segment without set: 6
strpbrk() Finds the first occurrence of any character from a set in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Random Character";
    char set[] = "XYZCharacter";
    char *ptr = strpbrk(str, set);
    if(ptr != NULL)
        printf("First matching character: %c at position: %ld\n", *ptr, ptr - str);
    else
        printf("No matching characters found.\n");
    return 0;
}

First matching character: a at position: 1
strrchr() Finds the last occurrence of a character in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Hello, World!";
    char *ptr = strrchr(str, 'l');
    if(ptr != NULL)
        printf("The last 'l' character is found at position: %ld\n", ptr - str);
    else
        printf("Character 'l' not found.\n");
    return 0;
}

The last 'l' character is found at position: 10
strdup() Duplicates a string by allocating sufficient memory and copying the content.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    char original[] = "Search";
    char *copy = strdup(original);
    if(copy != NULL) {
        printf("Original: %s\n", original);
        printf("Copy: %s\n", copy);
        free(copy);
    }
    return 0;
}

Original: Search
Copy: Search
strerror() Returns a pointer to the textual representation of an error code.
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(void) {
    FILE *fp = fopen("nonexistent.txt", "r");
    if(fp == NULL) {
        printf("Error: %s\n", strerror(errno));
    }
    return 0;
}

Error: No such file or directory
strncpy() Copies a specified number of characters from one string to another.
#include <stdio.h>
#include <string.h>

int main(void) {
    char source[] = "Random character";
    char destination[10];
    strncpy(destination, source, 9);
    destination[9] = '\0'; // Ensure null termination
    printf("Destination: %s\n", destination);
    return 0;
}
Destination: Random ch
strxfrm() Transforms a string according to the current locale for comparison purposes.
#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(void) {
    setlocale(LC_COLLATE, "en_US.UTF-8");
    char str1[] = "apple";
    char str2[] = "Banana";
    char transformed1[20], transformed2[20];
    
    strxfrm(transformed1, str1, sizeof(transformed1));
    strxfrm(transformed2, str2, sizeof(transformed2));
    
    int result = strcmp(transformed1, transformed2);
    if(result < 0)
        printf("'%s' comes before '%s'\n", str1, str2);
    else if(result > 0)
        printf("'%s' comes after '%s'\n", str1, str2);
    else
        printf("'%s' and '%s' are equal\n", str1, str2);
    
    return 0;
}

'apple' comes before 'Banana'
strcoll() Compares two strings according to the current locale.
#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(void) {
    setlocale(LC_COLLATE, "en_US.UTF-8");
    char str1[] = "apple";
    char str2[] = "Apple";
    int result = strcoll(str1, str2);
    if(result < 0)
        printf("'%s' comes before '%s'\n", str1, str2);
    else if(result > 0)
        printf("'%s' comes after '%s'\n", str1, str2);
    else
        printf("'%s' and '%s' are equal\n", str1, str2);
    return 0;
}

'apple' comes after 'Apple'
strtok() Splits a string into tokens based on specified delimiters.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Programming,Introduction,Language,C";
    char *token = strtok(str, ",");
    while(token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");
    }
    return 0;
}

Token: Programming
Token: Introduction
Token: Language
Token: C
strpbrk() Finds the first occurrence of any character from a set in a string.
#include <stdio.h>
#include <string.h>

int main(void) {
    char str[] = "Random Character";
    char set[] = "XYZChat";
    char *ptr = strpbrk(str, set);
    if(ptr != NULL)
        printf("First matching character: %c at position: %ld\n", *ptr, ptr - str);
    else
        printf("No matching characters found.\n");
    return 0;
}
First matching character: C at position: 7

4. Memory management with strings

Proper memory management is crucial when working with strings in C to avoid issues like buffer overflows and memory leaks.

4.1 Static vs dynamic allocation

Strings can be allocated statically or dynamically:

  • Static allocation: memory is allocated at compile-time. Example:
  • char str[] = "Static allocation";
  • Dynamic allocation: memory is allocated at runtime using functions like malloc(). Example:
  • char *str = malloc(20 * sizeof(char));
    strcpy(str, "Dynamic allocation");

4.2 Avoiding buffer overflows

Buffer overflows occur when data exceeds the allocated memory size, leading to undefined behavior and potential security vulnerabilities. To prevent this:

  • Always ensure that the destination array is large enough to hold the source string plus the null terminator.
  • Use functions like strncpy() which limit the number of characters copied.
#include <stdio.h>
#include <string.h>

int main(void) {
    char source[] = "This is a long string";
    char destination[10];
    strncpy(destination, source, sizeof(destination) - 1);
    destination[9] = '\0'; // Ensure null termination
    printf("Truncated String: %s\n", destination); // Outputs: This is a
    return 0;
}

5. Maintaining technical accuracy

When working with strings in C, maintaining technical accuracy is essential to ensure program correctness and efficiency. This involves understanding how strings are represented in memory, the behavior of string functions, and the implications of memory management choices. Accurate handling prevents bugs, enhances performance, and ensures that your programs behave as intended across different platforms and use cases.

6. Common mistakes when working with strings

  • Forgetting the null terminator: not including the null character can lead to undefined behavior when functions attempt to process the string.
  • Buffer overflows: as mentioned earlier, writing beyond the allocated memory can corrupt data and compromise program security.
  • Misusing string functions: incorrect usage of functions like strcpy() and strcat() without proper checks can lead to vulnerabilities.
  • Memory leaks: failing to free dynamically allocated memory results in memory leaks, which can degrade system performance over time.

7. Best practices for handling strings in c

  • Always allocate sufficient memory: ensure that your character arrays are large enough to hold the expected data plus the null terminator.
  • Use safe functions: prefer functions like strncpy() and snprintf() that allow you to specify buffer sizes.
  • Initialize strings properly: initialize your strings to prevent them from containing garbage values.
  • Free dynamically allocated memory: always pair malloc() with free() to manage memory effectively.
  • Validate input: when accepting user input, validate and sanitize it to prevent buffer overflows and other security issues.
  • Understand string literals: string literals are read-only. Attempting to modify them can lead to undefined behavior.

8. Example: reversing a string

Here's a simple program that reverses a string entered by the user:

#include <stdio.h>
#include <string.h>

void reverse(char *str) {
    int n = strlen(str);
    for(int i = 0; i < n / 2; i++) {
        char temp = str[i];
        str[i] = str[n - i - 1];
        str[n - i - 1] = temp;
    }
}

int main(void) {
    char str[100];
    
    printf("Enter a string: ");
    fflush(stdout);
    fgets(str, sizeof(str), stdin);
    
    // Remove the newline character if present
    size_t len = strlen(str);
    if(len > 0 && str[len - 1] == '\n') {
        str[len - 1] = '\0';
    }
    
    reverse(str);
    printf("Reversed string: %s\n", str);
    
    return 0;
}

Sample run:

Enter a string: Reverse me
Reversed string: em esreveR

feature-top
Readers’ comment
feature-top
Log in to add a comment
🔐 Access