C provides a set of library functions for manipulating both string and non-string data; these functions are published using the "string.h" header file. Where as string-related functions data use a pointer to char ("char *"), non-string-related functions use a pointer to void ("void *"). Using
Please recall that C represents strings as an array of char types, where each char type requires one byte of storage. Also, C places '\0' (NUL termination character) as the last character to mark the end of the string.
In this section, we focus on functions that compare two (string or non-string) data with each other.
C string library provides three comparison functions: two for strings and one for non-string data. Given two strings (or non-string data), these functions compare the value present present in corresponding bytes; if they are same for both, then the two strings (or non-string) data are deemed equal.
Thus, if there are two strings: str1 (with value "Mona Lisa") and str2 (with value "Mona Lisa"), then the value present in corresponding bytes is same for both -- first byte holds 'M' for both, second byte holds 'o' for both, and so on. Thus, they are equal. On the other hand, if we were to compare two strings: str1 (with value "Mona Lisa") and str3 (with value "Mona Simpson"), then these strings store different values starting with the sixth byte and hence, are unequal.
With that, let us get the ball rolling and provide signatures of the comparison functions:
int strcmp(const char *dest, const char *src); int strncmp(const char *dest, const char *src, size_t n); int memcmp(const void* dest, const void *src, size_t n);
The first function, strcmp(), returns 0, greater than 0, or less than 0 if the string dest is same, or greater than, or less than string src. The next function, strncmp(), is similar to that of strcmp(), but it compares only the first n bytes of string src with the first n bytes of string dest. If n is greater than the size of src, then comparison is made till the NUL-termination of the src string.
Like strncmp(), memcmp() compares the first n bytes of the src buffer with the first n bytes of dest buffer; it returns 0, greater than 0, or less than 0 to if the buffer pointed by dest is equal, greater than, or less than that of object src. Note that memcmp() already takes n size_t as input, and as such, there is no function like memncmp()!
For the case when two values are different, the sign of the nonzero value returned is determined by the sign of the difference between the values of the first pair of characters (both interpreted as unsigned char) that differ in the values being compared. Thus, if we are comparing "Mona Lisa" and "Mona Simpson", then the return value would be based on the difference between 'L' and 'S'.
Let us now see three examples that provide usage of these functions. The first example uses strcmp()/strncmp() pair to compare two strings. The second example repeats the first example, but uses memcmp() instead of strcmp() and strncmp(). The third example uses memcmp() to compare non-string values.
The first example (provided below) compares a string (variable str) to two other strings (STR_LAST_SUPPER and STR_LAST_SHOW). The variable str is different than STR_LAST_SHOW and hence, strcmp() fails. However, str and STR_LAST_SHOW do have a common substring ("The Last S") and so when we use strncmp() to compare just the common substring, the comparison succeeds.
#include <stdio.h> #include <string.h> #define STR_LAST_SUPPER "The Last Supper" #define STR_LAST_SHOW "The Last Show" int main () { char str[] = "The Last Supper"; int ret; size_t len; ret = strcmp(str, STR_LAST_SUPPER); printf("[strcmp] Returned value: %2d\n", ret); ret = strcmp(str, STR_LAST_SHOW); printf("[strcmp] Returned value: %2d\n", ret); ret = strcmp(STR_LAST_SHOW, str); printf("[strcmp] Returned value: %2d\n", ret); len = strlen("The Last S"); ret = strncmp(str, STR_LAST_SHOW, len); printf("[strncmp] Returned value: %2d\n", ret); return 0; }
We provide the output below. Note that when we change the order of strings passed to strcmp() in the second and third calls, the return value also changes.
$ gcc strcmp.c -o strcmp $ $ ./strcmp [strcmp] Returned value: 0 [strcmp] Returned value: 1 [strcmp] Returned value: -1 [strncmp] Returned value: 0
Our next example repeats the logic of the earlier example -- the only difference is that, it uses memcmp() instead of strcpy()/strncpy(). Accordingly, we cast strings to void pointers (void *). The output is similar to that of earlier example and hence, we omit it.
#include <stdio.h> #include <string.h> #define STR_LAST_SUPPER "The Last Supper" #define STR_LAST_SHOW "The Last Show" int main () { char str[] = "The Last Supper"; int ret; size_t lenSubstring; ret = memcmp((void *)str, (void *)STR_LAST_SUPPER, strlen(STR_LAST_SUPPER)); printf("[memcmp] Returned value: %2d\n", ret); ret = memcmp((void *)str, (void *)STR_LAST_SHOW, strlen(STR_LAST_SHOW)); printf("[memcmp] Returned value: %2d\n", ret); ret = memcmp((void *)STR_LAST_SHOW, (void *)str, strlen(STR_LAST_SHOW)); printf("[memcmp] Returned value: %2d\n", ret); lenSubstring = strlen("The Last S"); ret = memcmp((void *)str, (void *)STR_LAST_SHOW, lenSubstring); printf("[memcmp] Returned value: %2d\n", ret); return 0; }
$ gcc memcmp.c -o memcmp $ $ ./memcmp [memcmp] Returned value: 0 [memcmp] Returned value: 1 [memcmp] Returned value: -1 [memcmp] Returned value: 0
Compared to strcmp() and strncmp(), memcmp() does have a neat trick up its sleeve! It can also compare non-string data. In that regard, our last example compares two data structures. So, here it goes!
#include <stdio.h> #include <string.h> typedef struct painting_frame { int painting_id; int width; int height; } painting_frame_t; int main () { painting_frame_t painting1 = {1001, 40, 100}; painting_frame_t painting2 = {1002, 40, 100}; int ret; /* The painting_id values are different, so comparison should fail */ ret = memcmp((void *)&painting1, (void *)&painting2, sizeof(painting_frame_t)); printf("[memcmp] Returned value: %2d\n", ret); /* Make the painting_id values same for both and then compare again */ painting2.painting_id = painting1.painting_id; ret = memcmp((void *)&painting1, (void *)&painting2, sizeof(painting_frame_t)); printf("[memcmp] Returned value: %2d\n", ret); return 0; }
As expected, the comparison fails initially since the value of painting_id is different for the two data structures. For the second memcmp() call, we keep the values of the painting_id fields same and so the comparison succeeds.
$ gcc structmemcmp.c -o structmemcmp $ $ ./structmemcmp [memcmp] Returned value: -1 [memcmp] Returned value: 0