Practical 6(c): strlen and strcmp
Chapter Twenty-One
Syllabus topic Module 1, Practical 6(c): "Write a program to using strlen(), strcmp() function ."
Pages 72 to 75 of 206
Aim
To use the strlen() and strcmp() functions.
Both come from one header
#include <string.h>Without it the compiler does not know these functions exist, and in C17 that is an error, not a warning.
strlen: how long is this string
strlen(s) counts the characters in s up to but not including the terminating null.
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[20] = "Mumbai";
char b[] = "";
char c[] = "BSc IT";
printf("strlen(\"%s\") = %zu\n", a, strlen(a));
printf("strlen(\"%s\") = %zu (the empty string)\n", b, strlen(b));
printf("strlen(\"%s\") = %zu (the space counts)\n", c, strlen(c));
printf("sizeof a = %zu, strlen(a) = %zu\n", sizeof a, strlen(a));
return 0;
}strlen("Mumbai") = 6
strlen("") = 0 (the empty string)
strlen("BSc IT") = 6 (the space counts)
sizeof a = 20, strlen(a) = 6The last line is the distinction this function is always asked about.
sizeof a | strlen(a) | |
|---|---|---|
| Answers | how big is the box | how much is in it |
| Counts the null | yes | no |
| Decided | when the program is compiled | when the function runs |
| Is it a function | no, an operator | yes |
For char a[20] = "Mumbai" | 20 | 6 |
strlen returns a size_t, an unsigned type, whose format specifier is %zu. Two consequences follow, and the second bites.
Print it with %zu, not %d. With -Wall the compiler says so.
strlen(s) - 1 on an empty string is not minus 1. It is an enormous positive number, because an unsigned type cannot be negative and subtracting one from zero wraps to the largest value. A loop written for (i = strlen(s) - 1; i >= 0; i--) with i unsigned never ends. Cast to int when you need to go backwards, as [Practical 6(b): Is This String a Palindrome?] does.
strcmp: which of these two comes first
strcmp(a, b) compares two strings and returns a number that tells you their order:
| Return value | Meaning |
|---|---|
| 0 | the strings are identical |
| negative | a comes before b |
| positive | a comes after b |
The comparison is character by character from the left. At the first pair that differs, the character codes decide, and the rest of both strings is irrelevant.
#include <stdio.h>
#include <string.h>
int main(void)
{
printf("strcmp(\"apple\", \"apple\") = %d\n", strcmp("apple", "apple"));
printf("strcmp(\"apple\", \"banana\") = %d\n", strcmp("apple", "banana"));
printf("strcmp(\"banana\", \"apple\") = %d\n", strcmp("banana", "apple"));
printf("strcmp(\"Apple\", \"apple\") = %d\n", strcmp("Apple", "apple"));
printf("strcmp(\"app\", \"apple\") = %d\n", strcmp("app", "apple"));
return 0;
}strcmp("apple", "apple") = 0
strcmp("apple", "banana") = -1
strcmp("banana", "apple") = 1
strcmp("Apple", "apple") = -1
strcmp("app", "apple") = -1Read those five lines carefully, because each one answers a viva question.
Identical strings give 0. Not 1. This is the whole trap and it has its own section below.
Practical 6(c): strlen and strcmp
apple against banana is negative, because at the first character a is 97 and b is 98.
Apple against apple is negative, because a capital A is 65 and a small a is 97. Every capital letter comes before every small letter in ASCII, which is why an ordinary alphabetical sort puts Zebra before apple.
app against apple is negative. The first three characters match; then app has its terminating null, which is 0, against l, which is 108. A string that is a prefix of another always comes first.
The standard promises only the sign of the value, not its size. This library returns minus 1 and 1; another may return the difference of the character codes, minus 1 and 1 or minus 25 and 25. Test the sign, never the value. A program that says if (strcmp(a, b) == -1) is relying on something no standard guarantees.
The trap: 0 means equal
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[] = "ravi", b[] = "ravi";
if (strcmp(a, b))
printf("WRONG: the program thinks they are different\n");
else
printf("RIGHT: they are the same\n");
if (strcmp(a, b) == 0)
printf("The correct test: they are the same\n");
return 0;
}RIGHT: they are the same
The correct test: they are the sameThe first if gives the right answer here for the wrong reason, and that is why it is dangerous. In C, a condition is true when it is not zero. strcmp returns 0 for equal strings, so if (strcmp(a, b)) is true exactly when the strings are different. Writing it that way and reading it as "if a equals b" gets the answer backwards on every pair that differs, and right on every pair that matches, which is the worst possible failure pattern for testing.
Always write it out: if (strcmp(a, b) == 0) for equal, != 0 for different.
And the other half of the same lesson:
if (a == b) /* WRONG for strings */That compares two addresses. Two separate arrays are at two different addresses, so it is false even when the contents match. == works on numbers and characters; strings need strcmp.
Both functions, in one program that does something
#include <stdio.h>
#include <string.h>
int main(void)
{
char first[50], second[50];
int result;
printf("Enter the first string: ");
scanf("%49[^\n]", first);
printf("Enter the second string: ");
scanf(" %49[^\n]", second);
printf("\"%s\" has %zu characters\n", first, strlen(first));
printf("\"%s\" has %zu characters\n", second, strlen(second));
result = strcmp(first, second);
if (result == 0)
printf("The two strings are equal\n");
else if (result < 0)
printf("\"%s\" comes before \"%s\"\n", first, second);
else
printf("\"%s\" comes after \"%s\"\n", first, second);
return 0;
}banana
appleEnter the first string: Enter the second string: "banana" has 6 characters
"apple" has 5 characters
"banana" comes after "apple"Practical 6(c): strlen and strcmp
The space at the start of the second format string, " %49[^\n]", skips the newline left behind by the first read. Without it the second read sees that newline immediately, matches nothing, and leaves second untouched. This is the commonest reason a program that reads two lines appears to skip the second one.
The other comparison functions
| Function | What it does |
|---|---|
strcmp(a, b) | compares the whole strings |
strncmp(a, b, n) | compares only the first n characters |
strcasecmp(a, b) | compares ignoring case, on most systems |
strncmp is genuinely useful: strncmp(word, "com", 3) == 0 asks whether a word begins with those three letters. strcasecmp is not in the C standard, though nearly every system has it; if a program must be portable, lower both strings yourself with tolower from ctype.h.
What beginners get wrong
if (strcmp(a, b)) read as "if equal". It is true when they differ.
Testing strcmp(a, b) == -1. Only the sign is guaranteed.
Using == on two strings. That compares addresses.
Printing strlen with %d. It returns a size_t; use %zu.
Believing strlen counts the null. It does not; the array needs one more byte than strlen reports.
Calling strlen inside a loop condition. for (i = 0; i < strlen(s); i++) recounts the whole string on every single iteration. Count once into a variable before the loop.
Forgetting #include <string.h>.
Quick revision
- Both are in
string.h. strlen(s)counts characters before the null and returns asize_t, printed with%zu.sizeofis the size of the array;strlenis the length of the string in it.strcmp(a, b)returns 0 if equal, negative if a comes first, positive if b does.- Only the sign is guaranteed, never the value.
- Equal is
strcmp(a, b) == 0. A bareif (strcmp(a, b))means different. ==on strings compares addresses and is always the wrong test.- A leading space in a
scanfformat skips the leftover newline.
What goes in your journal
Aim, the algorithm, the program using both functions, and the output for two pairs: two equal strings and two that differ. Write the three return values of strcmp into the conclusion as a small table. If there is room, add the sizeof against strlen line with its two numbers; both are asked in vivas and both fit on one line.
Test yourself
1. What does strcmp return when the strings are identical? 0.
2. char a[20] = "Mumbai"; What are sizeof a and strlen(a)? 20 and 6. sizeof is the size of the array, strlen the length of the string in it.
Practical 6(c): strlen and strcmp
3. Why is if (strcmp(a, b)) the wrong way to test for equality? Because a non-zero value is true in C, and strcmp returns non-zero exactly when the strings are different. The test means "if they differ".
4. Is strcmp("Apple", "apple") negative or positive, and why? Negative. A capital A is 65 and a small a is 97, so the capital comes first.
5. Why should you not test strcmp(a, b) == -1? Because the standard guarantees only the sign of the result. A different library may return minus 25 for the same pair.
6. Why is for (i = 0; i < strlen(s); i++) a poor loop? Because strlen is called on every iteration and walks the whole string each time. Store the length in a variable before the loop.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.