Skip to content
FollowtheDamnCode

Reference: string.h

Length, copying, comparing, searching, splitting, and raw memory.

6 minute read

Big idea

<string.h> works on strings (char arrays ending in '\0') and on raw memory. None of these functions know how big your arrays are — making sure there's room is always your job.

Length and copying

strlen

size_t strlen(const char *s);

The number of characters before the '\0'. See String Functions.

  • Gotcha: it walks the whole string every call — don't put it in a loop condition over a long string. Print the result with %zu. sizeof is different: it's the array's size, not the text's length.
  • Example: strlen("hello") → 5

strcpy / strncpy

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

Copy src into dest, including the '\0'.

  • Gotcha: strcpy overflows dest if it's too small. strncpy stops at n but then doesn't add '\0' if src was too long. Safer: snprintf(dest, sizeof dest, "%s", src);.
  • Example: char name[20]; strcpy(name, "Asha");

strcat / strncat

char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);

Append src to the end of dest. strncat appends at most n characters and always adds '\0'.

  • Gotcha: dest must have room for both strings plus '\0', and must already be a valid string (start with char buf[50] = "";).
  • Example: strcat(path, "/notes.txt");

Comparing

strcmp / strncmp

int strcmp(const char *a, const char *b);
int strncmp(const char *a, const char *b, size_t n);

Compare alphabetically (by character code): negative if a comes first, 0 if equal, positive if b comes first. strncmp compares at most n characters.

  • Gotcha: a == b compares addresses, not text — use strcmp(a, b) == 0. Uppercase letters sort before lowercase ("Zoo" < "apple").
  • Example: if (strncmp(line, "GET ", 4) == 0) …

Searching

strchr / strrchr

char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);

Find the first (or last) occurrence of a character; NULL if absent.

  • Example: char *dot = strrchr("photo.tar.gz", '.'); → ".gz"

strstr

char *strstr(const char *haystack, const char *needle);

Find the first occurrence of a substring; NULL if absent.

  • Example: if (strstr(msg, "error")) …

strcspn / strspn

size_t strcspn(const char *s, const char *reject);
size_t strspn(const char *s, const char *accept);

Length of the starting run of s made of characters not in reject (or only those in accept).

  • Example: line[strcspn(line, "\n")] = '\0'; — strip fgets's newline.

strtok

char *strtok(char *s, const char *delims);

Splits a string into tokens. Call with the string first, then with NULL to get the next token.

  • Gotcha: it modifies the string (writes '\0' over delimiters), so it can't be used on a literal, and it remembers its place in a hidden static variable, so you can't split two strings at once.
  • Example: for (char *t = strtok(buf, ", "); t; t = strtok(NULL, ", ")) puts(t);

Raw memory

memset

void *memset(void *p, int value, size_t bytes);

Sets every byte to value.

  • Gotcha: it works byte by byte: memset(a, 0, sizeof a) zeroes an int array, but memset(a, 1, …) makes each int 16843009, not 1.
  • Example: memset(grid, 0, sizeof grid);

memcpy / memmove

void *memcpy(void *dest, const void *src, size_t bytes);
void *memmove(void *dest, const void *src, size_t bytes);

Copy bytes bytes. memmove is safe when the two regions overlap; memcpy isn't.

  • Example: memmove(a, a + 1, (n - 1) * sizeof a[0]); — shift an array left by one

memcmp

int memcmp(const void *a, const void *b, size_t bytes);

Compares bytes, like strcmp but it doesn't stop at '\0'.

strerror

char *strerror(int errnum);

The text for an error number — usually strerror(errno). See Error Handling.

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

int main(void) {
    char buf[64] = "";
    strcat(buf, "red,green");
    strncat(buf, ",blue,yellow", 5);
    printf("%s (%zu chars)\n", buf, strlen(buf));

    printf("strcmp: %d\n", strcmp("apple", "apple") == 0);
    printf("strstr: %s\n", strstr(buf, "green"));

    for (char *t = strtok(buf, ","); t != NULL; t = strtok(NULL, ",")) {
        printf("[%s] ", t);
    }
    printf("\n");

    int a[5] = {1, 2, 3, 4, 5};
    memmove(a, a + 1, 4 * sizeof a[0]);
    for (int i = 0; i < 5; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}
output
red,green,blue (14 chars)
strcmp: 1
strstr: green,blue
[red] [green] [blue] 
2 3 4 5 5 

Run and edit it in the app.

How do you test whether the strings a and b hold the same text?

Check yourself

Which function is safe when the source and destination overlap?

What does strtok do to the string you pass it?