C Character & String Exercises

Here are 13 problems, from beginner to advanced, that use the char type and strings (arrays of characters). In every problem, the key is to keep in mind the '\0' that marks the end of a string. Write your code in the browser and press "Check": it is run with real gcc on several inputs to see whether the output is correct.

How to use these problems
  1. Read the problem and the sample run, then write your code in the box
  2. Press "▶ Run" to try it with your own input
  3. Press "✔ Check" to test the output against several prepared inputs
  4. Stuck? Open "Hint". Solved it? Compare with "Solution & explanation"
Checking rules
  • Print output exactly as in the sample run. Do not print input prompts such as "Enter a number"
  • Trailing spaces at line ends and trailing blank lines are ignored
  • Your code is saved automatically in this browser

Note: Run and Check send your code to Wandbox, a free external compiler service, and run it with gcc.

13 problems (Beginner 4 · Intermediate 5 · Advanced 4)

Strings (13 problems)

S01 Beginner

Problem 1. Count the length of a string

Read a string with no spaces (1 to 99 characters, letters, digits and symbols only) and print its length (number of characters). Don't use strlen; count it yourself.
Sample run (input is underlined)
hello Length: 5
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
A C string has a null character '\0' right after its last character. Increase an index len from 0 and stop when s[len] is '\0'; the value of len at that point is the length.
#include <stdio.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    int len = 0;
    while (s[len] != '\0') {
        len++;
    }
    printf("Length: %d\n", len);
    return 0;
}
Explanation: The size of the array (100) and the length of the string are different things. The length is determined by where '\0' is, and '\0' itself is not counted. The 99 in scanf("%99s", s) means "read at most 99 characters", leaving one slot for '\0' so that it doesn't overflow the array.
S02 Beginner

Problem 2. Print character codes

Read a string with no spaces (1 to 99 characters, letters, digits and symbols only) and print each character as "character: code", one per line. Print the character code in decimal.
Sample run (input is underlined)
ABC A: 65 B: 66 C: 67
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
A char value is really a character code (an integer). Print the same s[i] with %c to get the character, or with %d to get the number.
#include <stdio.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    for (int i = 0; s[i] != '\0'; i++) {
        printf("%c: %d\n", s[i], s[i]);
    }
    return 0;
}
Explanation: The character '0' has the code 48, which is different from the number 0. Using the facts that "'0'–'9' have consecutive codes" (guaranteed by the C standard) and "'A'–'Z' and 'a'–'z' are each consecutive" (a property of ASCII), you can do conversions like the one in the next problem. With the loop condition s[i] != '\0', you can go to the end without computing the length first.
S03 Beginner

Problem 3. Swap upper and lower case

Read a string with no spaces (1 to 99 characters, letters, digits and symbols only), change uppercase letters to lowercase and lowercase letters to uppercase, and print it. Print all other characters unchanged.
Sample run (input is underlined)
Hello123 hELLO123
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
If 'a' <= c && c <= 'z', it is lowercase. In ASCII the difference between the codes of a lowercase letter and its uppercase letter is constant, so c - 'a' + 'A' gives the uppercase letter.
#include <stdio.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    for (int i = 0; s[i] != '\0'; i++) {
        if ('a' <= s[i] && s[i] <= 'z') {
            s[i] = s[i] - 'a' + 'A';
        } else if ('A' <= s[i] && s[i] <= 'Z') {
            s[i] = s[i] - 'A' + 'a';
        }
    }
    printf("%s\n", s);
    return 0;
}
Explanation: If you change else if to if, a character converted from lowercase to uppercase is immediately converted back from uppercase to lowercase. You can also use toupper / tolower from <ctype.h> (it is safest to pass the argument cast as (unsigned char)s[i]).
S04 Beginner

Problem 4. Count occurrences of a character

Read a string with no spaces (1 to 99 characters) and a single character c, separated by a space, and print how many times c appears in the string. Upper and lower case are distinguished.
Sample run (input is underlined)
banana a Count: 3
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
Loop while s[i] != '\0' and count when s[i] == c. Single characters can be compared with ==.
#include <stdio.h>

int main(void) {
    char s[100];
    char c;
    scanf("%99s %c", s, &c);

    int count = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == c) count++;
    }
    printf("Count: %d\n", count);
    return 0;
}
Explanation: Single characters (char) can be compared with ==, but strings cannot (that would compare the addresses of the start of the arrays). Use strcmp to compare strings. The space before %c in the format "%99s %c" skips the space after the string (because %c would otherwise read a space as a character).
S05 Intermediate

Problem 5. Reverse a string

Read a string with no spaces (1 to 99 characters) and print it with its characters in reverse order. Don't just print it backwards: reverse the contents of the array itself first, then print it with printf("%s\n", s).
Sample run (input is underlined)
hello olleh
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
If the length is len, swap from both ends: s[0] with s[len - 1], s[1] with s[len - 2], and so on. You are done after len / 2 swaps.
#include <stdio.h>
#include <string.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    size_t len = strlen(s);
    for (size_t i = 0; i < len / 2; i++) {
        char tmp = s[i];
        s[i] = s[len - 1 - i];
        s[len - 1 - i] = tmp;
    }
    printf("%s\n", s);
    return 0;
}
Explanation: If you keep swapping up to len times, after the halfway point the characters are swapped back to where they were. The partner position is len - 1 - i, not len - i (s[len] is '\0', and moving it to the front gives an empty string). strlen returns a size_t, so if you make the index a size_t too, you won't get warnings about mixing signed and unsigned.
S06 Intermediate

Problem 6. Palindrome check

Read a string with no spaces (1 to 99 characters) and print "Palindrome" if it reads the same forwards and backwards (a palindrome), or "Not a palindrome" otherwise. Upper and lower case are distinguished.
Sample run (input is underlined)
level Palindrome
Your code
"Run" executes your code with the input above. "Check" tests it against 6 prepared inputs.
As in the previous problem, move inward from both ends, comparing s[i] with s[len - 1 - i]. If even one pair differs, it is not a palindrome, so set a flag to 0 and break.
#include <stdio.h>
#include <string.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    size_t len = strlen(s);
    int is_pal = 1;
    for (size_t i = 0; i < len / 2; i++) {
        if (s[i] != s[len - 1 - i]) {
            is_pal = 0;
            break;
        }
    }

    if (is_pal) {
        printf("Palindrome\n");
    } else {
        printf("Not a palindrome\n");
    }
    return 0;
}
Explanation: "It is a palindrome if everything matches" — so printing "Palindrome" inside the loop with if (match) is wrong. The pattern "NG if even one place differs, OK if no difference is found by the end" is normally written with a flag variable. When the length is odd, the middle character would only be compared with itself, so you don't need to check it.
S07 Intermediate

Problem 7. Letter frequencies

Read a string of lowercase letters only (1 to 99 characters) and, for each letter that appears in it, print "letter: count", one per line, in order from a to z. Don't print letters that never appear.
Sample run (input is underlined)
banana a: 3 b: 1 n: 2
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
Prepare an array of 26 counters, int cnt[26] = {0};. A letter c becomes a number from 0 to 25 with c - 'a', so you can count with cnt[s[i] - 'a']++;.
#include <stdio.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    int cnt[26] = {0};
    for (int i = 0; s[i] != '\0'; i++) {
        cnt[s[i] - 'a']++;
    }

    for (int k = 0; k < 26; k++) {
        if (cnt[k] > 0) {
            printf("%c: %d\n", 'a' + k, cnt[k]);
        }
    }
    return 0;
}
Explanation: The key is combining the "character → index" conversion (s[i] - 'a') with the "index → character" conversion ('a' + k). If the input contains anything other than lowercase letters, the index goes outside 0–25 and you write out of bounds, so in real code you check 'a' <= s[i] && s[i] <= 'z' before counting.
S08 Intermediate

Problem 8. Sort two words in dictionary order

Read two strings with no spaces (each 1 to 99 characters, letters and digits only) separated by a space, and print the one that comes first in dictionary order (character-code order) on the first line and the other on the second line. If the two are the same, print "Same string". Use strcmp for the comparison.
Sample run (input is underlined)
banana apple apple banana
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
strcmp(a, b) returns a negative value if a comes first, 0 if they are the same, and a positive value if a comes after. If a comes after, swap the contents of a and b using a temporary array and strcpy, then print.
#include <stdio.h>
#include <string.h>

int main(void) {
    char a[100], b[100];
    scanf("%99s %99s", a, b);

    int r = strcmp(a, b);
    if (r == 0) {
        printf("Same string\n");
        return 0;
    }
    if (r > 0) {
        char tmp[100];
        strcpy(tmp, a);
        strcpy(a, b);
        strcpy(b, tmp);
    }
    printf("%s\n%s\n", a, b);
    return 0;
}
Explanation: The return value of strcmp is not necessarily −1 or 1, so test with > 0 / < 0, not == 1. Arrays can't be assigned, as in a = b;, so use strcpy to copy the contents. The comparison is by character code, so uppercase letters (65–90) come before lowercase letters (97–122) (Zoo comes before apple). Also, app is the beginning of apple, so the shorter one comes first.
S09 Intermediate

Problem 9. Count the words

Read one line of text made of letters, digits and spaces (200 characters or fewer) and print the number of words. A word is a run of characters separated by spaces; spaces may be consecutive and may appear at the start or end of the line. If the line has only spaces, the word count is 0. Read the line with fgets (the input may not end with a newline).
Sample run (input is underlined)
I have a pen Words: 4
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
Use a flag in_word meaning "we are currently inside a word". On a space (or newline), set in_word = 0; on any other character, if in_word is 0 it is the start of a word, so add 1 to the count and set in_word = 1.
#include <stdio.h>

int main(void) {
    char s[256];
    if (fgets(s, sizeof s, stdin) == NULL) {
        s[0] = '\0';
    }

    int count = 0, in_word = 0;
    for (int i = 0; s[i] != '\0'; i++) {
        if (s[i] == ' ' || s[i] == '\n') {
            in_word = 0;
        } else if (!in_word) {
            in_word = 1;
            count++;
        }
    }
    printf("Words: %d\n", count);
    return 0;
}
Explanation: Counting "number of spaces + 1" gives the wrong number when spaces are consecutive or at the start or end. Counting the starts of words is reliable. fgets also stores the newline '\n' at the end of the line in the array (unless the input doesn't end with a newline), so here the newline is treated as a separator too. scanf("%s") stops reading at a space, so it can't read a line that contains spaces.
S10 Advanced

Problem 10. Caesar cipher

Read an integer K (0 ≤ K ≤ 25) and a string with no spaces (1 to 99 characters, letters, digits and symbols only), separated by a space. Shift each letter K places forward in the alphabet and print the result (after z comes a again). Uppercase letters stay uppercase and lowercase letters stay lowercase; print non-letters unchanged.
Sample run (input is underlined)
3 abcxyz defabc
Your code
"Run" executes your code with the input above. "Check" tests it against 5 prepared inputs.
For a lowercase letter, first turn it into a number from 0 to 25 with s[i] - 'a', add K, take the remainder when divided by 26, and add 'a' to turn it back into a letter. Uppercase letters work the same way, using 'A' as the base.
#include <stdio.h>

int main(void) {
    int k;
    char s[100];
    scanf("%d %99s", &k, s);

    for (int i = 0; s[i] != '\0'; i++) {
        if ('a' <= s[i] && s[i] <= 'z') {
            s[i] = 'a' + (s[i] - 'a' + k) % 26;
        } else if ('A' <= s[i] && s[i] <= 'Z') {
            s[i] = 'A' + (s[i] - 'A' + k) % 26;
        }
    }
    printf("%s\n", s);
    return 0;
}
Explanation: With just s[i] + k, going past 'z' gives symbols such as {. Converting to a number from 0 to 25 first and then taking % 26 is the standard technique for calculations that wrap around in a circle. Encrypting twice with K=13 gives back the original (ROT13).
S11 Advanced

Problem 11. Write your own strlen and strcat

Complete the function my_strlen, which returns the length of a string, and the function my_strcat, which appends src to the end of the string dst, without using <string.h>. Use main exactly as in the template. The input is two strings with no spaces (each 1 to 49 characters), and the joined string and its length are printed.
Sample run (input is underlined)
abc def abcdef Length: 6
Your code
"Run" executes your code with the input above. "Check" tests it against 4 prepared inputs.
my_strcat has two steps. (1) Find the position of '\0' in dst (that is where writing starts). (2) From there, copy src one character at a time, and write a '\0' at the end as well.
#include <stdio.h>

int my_strlen(const char *s) {
    int len = 0;
    while (s[len] != '\0') {
        len++;
    }
    return len;
}

void my_strcat(char *dst, const char *src) {
    int i = my_strlen(dst);
    int j = 0;
    while (src[j] != '\0') {
        dst[i] = src[j];
        i++;
        j++;
    }
    dst[i] = '\0';
}

int main(void) {
    char a[100], b[50];
    scanf("%49s %49s", a, b);
    my_strcat(a, b);
    printf("%s\n", a);
    printf("Length: %d\n", my_strlen(a));
    return 0;
}
Explanation: If you forget the final dst[i] = '\0';, there is no telling what follows the joined text, and printf may print garbage or keep reading past the end of the array. Also, the destination array a must be large enough for both lengths + 1 character (here 49 + 49 + 1 ≤ 100). The standard strcat doesn't check the size either, so the caller is responsible. The const on a parameter is a promise that "this function doesn't modify the contents".
S12 Advanced

Problem 12. Anagram check

Read two strings of lowercase letters only (each 1 to 99 characters) separated by a space, and print "Anagram" if rearranging the letters of one gives the other (an anagram), or "Not an anagram" otherwise. Identical strings also count as anagrams.
Sample run (input is underlined)
listen silent Anagram
Your code
"Run" executes your code with the input above. "Check" tests it against 6 prepared inputs.
If every letter appears the same number of times, they are anagrams. In int cnt[26] = {0};, add +1 for each letter of the first string and −1 for each letter of the second, then check whether all 26 counts are 0.
#include <stdio.h>

int main(void) {
    char a[100], b[100];
    scanf("%99s %99s", a, b);

    int cnt[26] = {0};
    for (int i = 0; a[i] != '\0'; i++) {
        cnt[a[i] - 'a']++;
    }
    for (int i = 0; b[i] != '\0'; i++) {
        cnt[b[i] - 'a']--;
    }

    int ok = 1;
    for (int k = 0; k < 26; k++) {
        if (cnt[k] != 0) {
            ok = 0;
            break;
        }
    }

    if (ok) {
        printf("Anagram\n");
    } else {
        printf("Not an anagram\n");
    }
    return 0;
}
Explanation: If you only check "is every letter of a contained in b", you miss cases where the counts differ, such as aab and abb. Comparing counts also naturally judges strings of different lengths (abc and ab) as different. Another approach is to sort each string and then compare them with strcmp.
S13 Advanced

Problem 13. Run-length encoding

Read a string of letters only (1 to 99 characters) and print it with each run of the same character replaced by "the character followed by how many times it repeats". For example, aaabccdddd becomes a3b1c2d4. Runs of a single character also get the count 1. Upper and lower case are treated as different characters.
Sample run (input is underlined)
aaabccdddd a3b1c2d4
Your code
"Run" executes your code with the input above. "Check" tests it against 6 prepared inputs.
Remember the character c at index i, and increase i and the count while s[i] == c. When you reach a different character (or '\0'), print "c and the count" and start counting the next run from there.
#include <stdio.h>

int main(void) {
    char s[100];
    scanf("%99s", s);

    int i = 0;
    while (s[i] != '\0') {
        char c = s[i];
        int count = 0;
        while (s[i] == c) {
            count++;
            i++;
        }
        printf("%c%d", c, count);
    }
    printf("\n");
    return 0;
}
Explanation: Because c is a letter, the inner while (s[i] == c) always stops when it reaches '\0' and never leaves the array. You can also write it by comparing s[i] == s[i + 1], but then it is easy to forget to print the last run, so be careful. The count can have two or more digits, so print it with %d ('0' + count breaks at 10 or more).

Review these lessons

← Back to all practice problems