Understanding the Header File in the C Standard Library

We are about to discuss the <string.h> header file in the C standard library. This header file provides a set of functions for manipulating strings (character arrays terminated by a null character ‘\0’) and memory blocks. I will explain the main functions in this header file in detail, including their purposes, parameters, return values, and precautions, along with some code examples. The functions in <string.h> can be divided into two main categories:

  1. String manipulation functions (starting with str): These functions operate on strings that are terminated by a null character.
  2. Memory manipulation functions (starting with mem): These functions operate on arbitrary memory blocks, regardless of their content, typically working on a byte level.

String Functions (str Series)

1. String Length

size_t strlen(const char *str);
  • Function: Calculates the length of a string (excluding the terminating null character).
  • Parameter: A pointer to the string.
  • Return Value: The number of characters in the string (excluding ‘\0’).
  • Note: If str is NULL, the behavior is undefined (usually leads to a program crash). Example:
const char *s = "Hello";
size_t len = strlen(s); // len = 5

2. String Copy

char *strcpy(char *dest, const char *src);
  • Function: Copies the string pointed to by src (including the terminating null character) to dest.
  • Parameter: dest is the destination array, src is the source string.
  • Return Value: A pointer to dest.
  • Note: dest must be large enough to hold src, otherwise it will lead to a buffer overflow (undefined behavior).
char *strncpy(char *dest, const char *src, size_t n);
  • Function: Copies the first n characters from src to dest. If the length of src is less than n, the remaining space is filled with null characters; if the length of src is greater than or equal to n, no null character is added at the end of dest (i.e., dest may not be a null-terminated string).
  • Parameter: n is the maximum number of characters to copy.
  • Return Value: A pointer to dest.
  • Note: After using this function, it is usually necessary to manually add a terminator to ensure it forms a string. Example:
char dest[10];
strcpy(dest, "Hello"); // dest contains "Hello\0"
strncpy(dest, "Hello, world!", 9); // copies 9 characters, no '\0' added, so need to manually add: dest[9] = '\0';

3. String Concatenation

char *strcat(char *dest, const char *src);
  • Function: Appends the src string to the end of the dest string (overwriting the terminating null character of dest and adding a new terminating null character at the end of the new string).
  • Parameter: dest must be large enough to hold the concatenated string (including the terminating null character).
  • Return Value: A pointer to dest.
char *strncat(char *dest, const char *src, size_t n);
  • Function: Appends the first n characters of src to the end of dest, and adds a terminating null character.
  • Parameter: n is the maximum number of characters to append (excluding the last added terminating null character).
  • Return Value: A pointer to dest. Example:
char dest[20] = "Hello";
strcat(dest, " World!"); // dest becomes "Hello World!"
strncat(dest, " Goodbye", 4); // appends 4 characters, becomes "Hello World! Goo"

4. String Comparison

int strcmp(const char *s1, const char *s2);
  • Function: Compares two strings (lexicographically).
  • Return Value:
    • If s1 equals s2, returns 0;
    • If s1 is less than s2, returns a negative integer;
    • If s1 is greater than s2, returns a positive integer.
int strncmp(const char *s1, const char *s2, size_t n);
  • Function: Compares the first n characters of two strings.
  • Return Value: Same as above. Example:
int result;
result = strcmp("apple", "apple"); // 0
result = strcmp("apple", "banana"); // negative, because 'a' < 'b'
result = strncmp("apple", "appetite", 4); // compares the first 4 characters, returns 0 if equal

5. String Search

Find Character

char *strchr(const char *s, int c);
  • Function: Finds the first occurrence of character c (treated as a char but passed as an int) in the string s.
  • Return Value: A pointer to that character; returns NULL if not found.
char *strrchr(const char *s, int c);
  • Function: Finds the last occurrence of character c in the string s.
  • Return Value: Same as above. Example:
char *s = "Hello";
char *p = strchr(s, 'l'); // p points to the first 'l', i.e., s+2
p = strrchr(s, 'l'); // p points to the last 'l', i.e., s+3

Find Substring

char *strstr(const char *haystack, const char *needle);
  • Function: Finds the first occurrence of substring needle in string haystack.
  • Return Value: A pointer to the found substring; returns NULL if not found. Example:
char *s = "Hello, world!";
char *p = strstr(s, "world"); // p points to the start of "world!"

6. String Tokenization

char *strtok(char *str, const char *delim);
  • Function: Splits the string str into a series of tokens. On the first call, str specifies the string to be split, and delim specifies the set of delimiters. On subsequent calls, str should be NULL to continue splitting the same string.
  • Note: This function modifies the original string (replacing delimiters with ‘\0’). It is not thread-safe (as it maintains static state internally). Example:
char str[] = "This is a sample string";
char *token = strtok(str, " "); // First call, returns "This"
while (token != NULL) {
    printf("%s\n", token);
    token = strtok(NULL, " "); // Subsequent calls
}
// Output: This, is, a, sample, string (one per line)

Memory Functions (mem Series)

1. Memory Copy

void *memcpy(void *dest, const void *src, size_t n);
  • Function: Copies n bytes from the location pointed to by src to the location pointed to by dest. The memory areas must not overlap (use memmove if they do).
  • Return Value: A pointer to dest.
  • Note: dest and src must not overlap (undefined behavior if they do). Example:
int src[5] = {1,2,3,4,5};
int dest[5];
memcpy(dest, src, 5 * sizeof(int)); // Copy the entire array

2. Memory Move

void *memmove(void *dest, const void *src, size_t n);
  • Function: Copies n bytes from src to dest, allowing for overlapping memory areas (it handles overlaps internally).
  • Return Value: A pointer to dest. Example:
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11); // Moves "very useful" to the back

3. Memory Comparison

int memcmp(const void *s1, const void *s2, size_t n);
  • Function: Compares the first n bytes of two memory areas (byte-wise comparison).
  • Return Value: Similar to strcmp, returns 0 if equal, non-zero if not (positive or negative indicates the size relationship). Example:
int arr1[3] = {1,2,3};
int arr2[3] = {1,2,4};
int result = memcmp(arr1, arr2, 3 * sizeof(int)); // Result is negative, because 3 < 4

4. Memory Set

void *memset(void *s, int c, size_t n);
  • Function: Sets the first n bytes of the memory area pointed to by s to the value c (byte-wise setting).
  • Return Value: A pointer to s.
  • Note: Typically used for initializing memory (e.g., zeroing out). Example:
char buf[100];
memset(buf, 0, 100); // Sets all of buf to 0
int arr[10];
memset(arr, 0, 10 * sizeof(int)); // Zeros out the integer array

5. Memory Search

void *memchr(const void *s, int c, size_t n);
  • Function: Searches for the first occurrence of character c (treated as an unsigned char) in the first n bytes of the memory area s.
  • Return Value: A pointer to that byte; returns NULL if not found. Example:
char *s = "Hello";
void *p = memchr(s, 'e', 5); // Points to s[1]

Other Functions

Error String Mapping

char *strerror(int errnum);
  • Function: Returns a string describing the error based on the error number errnum (usually from errno).
  • Return Value: A pointer to the error string. Example:
#include <errno.h>
#include <string.h>
// ...
FILE *fp = fopen("non_existent_file.txt", "r");
if (fp == NULL) {
    printf("Error: %s\n", strerror(errno));
}

Precautions

  1. Buffer Overflow: When using functions like strcpy, strcat, etc., ensure that the destination buffer is large enough, or it will lead to buffer overflow (security vulnerabilities). It is recommended to use safer versions (like strncpy, strncat) or non-standard safe functions (like strlcpy, strlcat, but not included in the C standard) or dynamically allocate sufficient space.
  2. Null Pointer: Pointers passed to these functions must not be NULL (unless specifically allowed, like in subsequent calls to strtok), otherwise it will lead to undefined behavior (program crash).
  3. String Termination: Ensure that strings are null-terminated, otherwise string functions may access out of bounds.
  4. Memory Overlap: When the source and destination memory areas overlap, memmove must be used instead of memcpy.

Safe Functions (C11 Optional)

The C11 standard introduced safe versions of functions (with a suffix _s), such as:

errno_t strcpy_s(char * restrict dest, rsize_t destsz, const char * restrict src);

These functions check the buffer size at runtime and call a constraint handler function in case of an error. However, they are not supported by all compilers and are more complex to use.

Summary

<string.h> provides a rich set of functions for string and memory operations. When using them, be aware of:

  • Buffer size and overflow issues.
  • Strings must be null-terminated.
  • Memory overlap issues. Correct use of these functions can efficiently handle strings and memory, but incorrect use can lead to program crashes or security vulnerabilities. In situations requiring safety, consider using safe versions of functions or safer string handling libraries.

Leave a Comment