What does strncmp actually do?

Viewed 241

I tried to create my own strncmp function that was required from my school project, I run my code that use the same srcmp function but with providing the limit size for which ASCII Code I want to compare: The code:

#include <stdio.h>
int     strncmp(char *s1, char *s2, unsigned int n)
{
    int i;
    int diff;

    i = 0;
    diff = 0;
    while ((s1[i] != '\0' || s2[i] != '\0') && (unsigned)i < n)
    {
        diff = s1[i] - s2[i];
        if (diff != 0)
        {
            break ;
        }
        i++;
    }
    return (diff);
}
int main(){
    char s11[] = "abcs";
    char s12[] = "zzfs";
    unsigned int p = 3;
    printf("%d", strncmp(s11, s12, p));
}

The output :

-22

It's supposed to compare the 3 characters not only the first one, Am I right ? I didn't get the idea in MAN, I'm a beginner just so you know. Thanks for your help!

2 Answers

What does strncmp actually do?

strncmp compares the first two characters in the strings. (When comparing characters, it uses their values as unsigned char, even though they are passed via pointers to char.) If the characters differ or either is a null character:

  • If the character from the first string is greater than the character from the second, strncmp returns a positive value.
  • If the first is less than the second, strncmp returns a negative value.
  • Otherwise (the characters are both null characters), strncmp returns zero.

If the characters did not differ and neither was a null character, strncmp goes on to compare the following characters in the same way, until n pairs have been compared. If no difference has been found after n pairs have been compared, strncmp returns zero.

Some implementations of strncmp may return the signed difference between the two characters that differed, but this is not required by the C standard. strncmp may simply return +1 and −1 for “greater than” and “less than” or may use other positive and negative values.

strncmp(s1, s2, n) compares up to n characters from the strings pointed to by s1 and s2. It stops if it finds a difference and returns a negative value if the character from s1, converted to an unsigned char is less than the corresponding character from s2 (also converted to an unsigned char) and a positive value it is is greater. Subtracting the values of the differing characters is a handy way to compute a return value with the correct sign.

If no difference was found before the end of both strings or n characters have been processed, whichever comes first, it returns 0.

Your code has some small issues:

  • the pointer arguments should be declared with type const char * and n with type size_t.
  • similarly, i should be defined as a size_t, defining it as an int forces you to use a cast in the comparison and will cause undefined behavior for strings with an identical prefix longer than INT_MAX and a large enough n argument.
  • you should not dereference s1[i] nor s2[i] if n has reached 0, so the test on n should be performed first.
  • the difference should be computed as diff = (unsigned char)s1[i] - (unsigned char)s2[i];
  • note also that on some very exotic platforms, where sizeof(char) == sizeof(int), the subtraction cannot be used as it may wrap around and produce incorrect results.
  • it is preferable to not use names reserved for standard functions for your own versions and it may cause clashes with the compiler's intrinsics.

Here is a modified version:

#include <stdio.h>

int my_strncmp(const char *s1, const char *s2, size_t n) {
    for (size_t i = 0; i < n; i++) {
        int diff = (unsigned char)s1[i] - (unsigned char)s2[i];
        if (diff != 0 || s1[i] == '\0')
            return diff;
    }
    return 0;
}

int main() {
    char s11[] = "abcs";
    char s12[] = "zzfs";
    size_t n = 3;
    printf("   strncmp() -> %d\n", strncmp(s11, s12, n));
    printf("my_strncmp() -> %d\n", my_strncmp(s11, s12, n));
    return 0;
}

The output values may differ but should have the same sign or should both be null.

Related