Educational Blog

How to Compare Strings in C

Learn the correct way to compare C strings with strcmp and strncmp.

If you are learning C, string comparison is one of the first places where the language feels different from higher-level languages. A C string is not a built-in text object. It is a char array that ends with a null terminator, so comparing strings means comparing the characters one by one until you find a difference or reach the end.

That detail matters because the == operator does not compare string contents in C. It compares addresses. Two arrays with the same text may live at different memory locations, which means == can tell you they are different even when they contain identical letters. The safe way is to use the string comparison functions from <string.h> and, when needed, to write careful custom logic for special cases.

The core idea

A C string is considered equal to another C string when both sequences of characters match exactly and both end at the same point. For example, these strings are equal:

  • "cat"
  • "cat"

These are not equal:

  • "cat"
  • "cats"

These are also not equal:

  • "Cat"
  • "cat"

C string comparison is case-sensitive by default, and it stops at the first mismatch. That gives you simple, fast behavior, but it also means you must think about whitespace, casing, and hidden characters such as if your input comes from files or user input.

Use strcmp for most comparisons

The standard library function you want most of the time is strcmp.

int result = strcmp(a, b);

strcmp returns:

  • 0 when the strings are equal
  • a negative value when the first string sorts before the second
  • a positive value when the first string sorts after the second

The exact positive or negative number is not the point. You should only test whether the result is 0, < 0, or > 0.

Example

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

int main(void) {
    const char *first = "apple";
    const char *second = "apple";
    const char *third = "banana";

    printf("first vs second: %d
", strcmp(first, second));
    printf("first vs third: %d
", strcmp(first, third));

    if (strcmp(first, second) == 0) {
        printf("The strings match.
");
    }

    return 0;
}

How to read the result

ComparisonMeaning
strcmp(a, b) == 0Equal text
strcmp(a, b) < 0a comes before b lexicographically
strcmp(a, b) > 0a comes after b lexicographically

That lexicographic ordering is useful for sorting, searching, and validating user input. It is not limited to alphabetical words. It compares the raw character codes in sequence.

Why == does not work

This is the most common beginner mistake.

char a[] = "hello";
char b[] = "hello";

if (a == b) {
    /* This compares addresses, not text. */
}

Even though a and b contain the same letters, they are separate arrays. The compiler may store them in different places, so a == b is false in most real programs.

If you use pointers instead of arrays, the same rule applies:

char *a = "hello";
char *b = "hello";

if (a == b) {
    /* Still compares pointer values. */
}

If both pointers happen to point to the same literal pool location, the comparison may appear to work, but that is not a reliable test of string equality. The correct test is still strcmp(a, b) == 0.

When strncmp is better

strncmp compares only the first n characters.

#include <string.h>

if (strncmp(input, "yes", 3) == 0) {
    /* input starts with "yes" */
}

Use it when you want to check a prefix or limit comparison to a fixed number of characters. That is useful for:

  • command parsing
  • short prefixes
  • defensive checks on partially trusted buffers
  • substring-style validation

Be careful, though. strncmp("yes!", "yes", 3) == 0 is true, because only the first three characters are compared. If you need exact equality, use strcmp and check that both strings end at the same time.

Practical patterns you will actually use

1. Exact match

if (strcmp(user_input, "quit") == 0) {
    puts("Exiting...");
}

This is the standard exact-string check.

2. Case-sensitive decision tree

if (strcmp(mode, "fast") == 0) {
    run_fast();
} else if (strcmp(mode, "safe") == 0) {
    run_safe();
} else {
    puts("Unknown mode");
}

This style is common in configuration parsing and command-line tools.

3. Prefix routing

if (strncmp(command, "set", 3) == 0) {
    handle_set(command);
}

Prefix checks are useful when a command family shares a root word.

4. Sorting strings

#include <stdlib.h>
#include <string.h>

int compare_names(const void *lhs, const void *rhs) {
    const char *const *a = lhs;
    const char *const *b = rhs;
    return strcmp(*a, *b);
}

This comparator can be passed to qsort when you want alphabetic ordering.

Common pitfalls

Trailing newline characters

Input from fgets usually includes the newline if there is room in the buffer.

fgets(buffer, sizeof buffer, stdin);

If the user types hello and presses Enter, the buffer may hold "hello ", not just "hello". In that case, strcmp(buffer, "hello") will fail.

Typical fix:

buffer[strcspn(buffer, "
")] = '�';

That removes the trailing newline if present.

Uninitialized or unterminated data

String functions expect valid null-terminated strings. If you pass a buffer that is missing , strcmp may read past the intended memory and trigger undefined behavior.

That means you should not treat arbitrary character arrays as strings unless you know they are terminated properly.

Case sensitivity

strcmp("Admin", "admin") does not match. If you need case-insensitive comparison, use a platform-specific helper or normalize the input yourself.

On some systems you may see strcasecmp, but that is not part of the ISO C standard. If portability matters, do not assume it is available everywhere.

A small comparison checklist

Before comparing strings in C, check the following:

  1. Are both values valid null-terminated strings?
  2. Do you need exact equality or only a prefix?
  3. Does input contain a trailing newline?
  4. Is comparison case-sensitive or case-insensitive?
  5. Are you comparing contents, not addresses?

That checklist prevents most string bugs in small C programs.

Choosing the right function

NeedFunctionNotes
Exact full-string matchstrcmpBest default choice
Partial or prefix matchstrncmpCompare only first n characters
Sortingstrcmp in a comparatorReturns order for lexicographic sort
Input cleanup before comparisonstrcspn, manual trimmingRemove `
` and extra spaces

The table is intentionally simple: if your goal is exact comparison, start with strcmp. Only switch when your problem is about prefixes, limited-length buffers, or special input handling.

Example: building a reliable login check

Suppose your program reads a username and compares it to a known value.

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

int main(void) {
    char username[64];

    printf("Username: ");
    if (fgets(username, sizeof username, stdin) == NULL) {
        return 1;
    }

    username[strcspn(username, "
")] = '�';

    if (strcmp(username, "admin") == 0) {
        puts("Welcome, admin.");
    } else {
        puts("Access denied.");
    }

    return 0;
}

This example does three important things right:

  • It reads safely with fgets
  • It removes the newline before comparison
  • It compares content with strcmp, not pointers

That combination is the pattern you will use again and again.

If you need custom behavior

Sometimes built-in comparison is not enough. You may want to ignore spaces, normalize case, or compare only a token inside a larger string. In those cases, do the cleanup first and then compare the normalized values.

For example, if you want to accept YES, Yes, and yes, convert the text to one case before checking it. If you want to ignore surrounding whitespace, trim it before comparison. The key rule is simple: make both strings comparable in the form you actually care about, then use strcmp.

Final rule of thumb

If you remember only one thing, remember this:

  • == compares pointers
  • strcmp compares string content
  • strncmp compares only the first n characters

That distinction explains most of the confusion around C string comparison. Once you internalize it, you can safely handle user input, command parsing, and text-based control flow without guessing.

Written by

c-double.com Editorial Team

Editorial team

c-double.com publishes practical how-to guides and educational articles with clear steps and useful context.