More strings

Table of contents
  1. More strings
    1. Character functions with <ctype.h>
      1. Converting characters to uppercase
    2. Changing a complete string
    3. Mocking SpongeBob example
    4. String functions with <string.h>
    5. Finding the length with strlen()
    6. Comparing strings with strcmp()
    7. Copying strings
    8. Joining strings
    9. Finding a character with strchr()
    10. Finding part of a string with strstr()
    11. A note about user input

Handling strings in C is not always user friendly, but the standard library provides functions for common jobs such as measuring, comparing and searching strings.

This page introduces some of the functions from:

  • <ctype.h> for working with individual characters
  • <string.h> for working with strings

Character functions with <ctype.h>

The functions in <ctype.h> work with one character at a time.

Include the library with:

#include <ctype.h>

Some useful functions are:

Function Description
isalpha(c) Checks whether c is a letter
isdigit(c) Checks whether c is a digit
isspace(c) Checks whether c is a whitespace character
toupper(c) Converts a lowercase letter to uppercase
tolower(c) Converts an uppercase letter to lowercase

The checking functions return zero if the check is false and a non-zero value if it is true.

For example:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char character = '7';

    if (isdigit(character)) {
        printf("%c is a digit\n", character);
    }

    return 0;
}

Converting characters to uppercase

We can use toupper() to convert an individual character:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char letter = 'a';

    letter = toupper(letter);

    printf("%c\n", letter);

    return 0;
}

This prints:

A

If the character is not a lowercase letter, toupper() returns it unchanged.

Changing a complete string

Since a string is an array of characters, we can use a loop to apply toupper() to each character:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char name[] = "Ash Ketchum";

    for (int i = 0; name[i] != '\0'; i++) {
        name[i] = toupper(name[i]);
    }

    printf("%s\n", name);

    return 0;
}

This prints:

ASH KETCHUM

The loop stops when it reaches the terminating '\0'.

Mocking SpongeBob example

We can also use the functions from <ctype.h> to write in AlTeRnAtInG cApS:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char input[] = "Ash Ketchum";
    int make_uppercase = 1;

    for (int i = 0; input[i] != '\0'; i++) {
        if (isalpha(input[i])) {
            if (make_uppercase) {
                input[i] = toupper(input[i]);
            } else {
                input[i] = tolower(input[i]);
            }

            make_uppercase = !make_uppercase;
        }
    }

    printf("%s\n", input);

    return 0;
}

This gives:

AsH kEtChUm

The variable make_uppercase is only changed when a letter is found. Spaces and punctuation therefore do not affect the alternating pattern.

String functions with <string.h>

The functions in <string.h> work with null-terminated strings.

Include the library with:

#include <string.h>

These functions rely on the terminating '\0' to find the end of the string. If the terminator is missing, the function may continue reading beyond the end of the array.

Finding the length with strlen()

The strlen() function returns the number of characters before the terminating '\0':

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

int main(void)
{
    char name[] = "Ash Ketchum";
    size_t length = strlen(name);

    printf("Length = %zu\n", length);

    return 0;
}

This prints:

Length = 11

The space counts as a character, but the terminating '\0' is not included in the length.

strlen() returns a value of type size_t, so %zu is used to print it.

The size of the array and the length of the string are not necessarily the same:

char name[20] = "Ash";

Here:

sizeof(name)    // 20
strlen(name)    // 3

sizeof(name) gives the amount of memory allocated to the array. strlen(name) counts the characters currently stored before '\0'.

Comparing strings with strcmp()

We cannot compare the contents of two strings using ==:

if (name == "Ash") {
    // This does not compare the text in the strings
}

To compare strings, use strcmp():

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

int main(void)
{
    char name[] = "Ash";

    if (strcmp(name, "Ash") == 0) {
        printf("The strings match\n");
    }

    return 0;
}

strcmp() returns:

  • 0 if the strings are equal
  • a value less than zero if the first string comes before the second
  • a value greater than zero if the first string comes after the second

The important one to remember initially is:

strcmp(first, second) == 0

This checks whether the two strings contain the same text.

String comparisons are case-sensitive:

strcmp("Ash", "ash")

does not return zero because uppercase and lowercase letters have different character values.

Copying strings

You cannot copy one character array to another using assignment:

char source[] = "Ash";
char destination[20];

destination = source;     // Not allowed

One option is strcpy():

strcpy(destination, source);

However, strcpy() does not know how large destination is. If the source string is too long, it will write beyond the end of the array.

A simple alternative when creating formatted strings is snprintf():

#include <stdio.h>

int main(void)
{
    char destination[20];
    char source[] = "Ash Ketchum";

    snprintf(destination, sizeof(destination), "%s", source);

    printf("%s\n", destination);

    return 0;
}

The second argument tells snprintf() the total size of the destination array, including the space needed for '\0'.

If the text is too long, it is shortened to fit rather than being written beyond the end of the array.

Joining strings

snprintf() can also combine several values into one string:

#include <stdio.h>

int main(void)
{
    char first_name[] = "Ash";
    char surname[] = "Ketchum";
    char full_name[30];

    snprintf(
        full_name,
        sizeof(full_name),
        "%s %s",
        first_name,
        surname
    );

    printf("%s\n", full_name);

    return 0;
}

This produces:

Ash Ketchum

This is often clearer than repeatedly joining strings using strcat().

Finding a character with strchr()

The strchr() function searches a string for the first occurrence of a character:

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

int main(void)
{
    char name[] = "Ash Ketchum";

    if (strchr(name, ' ') != NULL) {
        printf("The string contains a space\n");
    }

    return 0;
}

If the character is found, strchr() returns its location in the string. If it cannot find the character, it returns NULL.

For now, it is enough to use the result as a check:

if (strchr(name, ' ') != NULL) {
    // The character was found
}

We will look at exactly what the returned value means when we cover pointers.

Finding part of a string with strstr()

The strstr() function searches for one string inside another:

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

int main(void)
{
    char name[] = "Ash Ketchum";

    if (strstr(name, "Ketchum") != NULL) {
        printf("Surname found\n");
    }

    return 0;
}

Like strchr(), it returns NULL if no match is found.

The comparison is case-sensitive, so searching for "ketchum" would not find "Ketchum".

A note about user input

Functions such as strlen(), strcmp() and strchr() expect a correctly null-terminated string. When a string comes from user input, you must also think about:

  • the size of the destination array
  • invalid input
  • spaces in the input
  • the newline added by fgets()
  • converting text into numbers

These are covered on the User Input Handling page.


This site uses Just the Docs, a documentation theme for Jekyll.