Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does while(*s++ == *t++) not work to compare two strings

I'm implementing strcmp(char *s, char *t) which returns <0 if s<t, 0 if s==t, and >0 if s>t by comparing the fist value that is different between the two strings.

implementing by separating the postfix increment and relational equals operators works:

for (; *s==*t; s++, t++)
    if (*s=='\0')
        return 0;
return *s - *t;

however, grouping the postfix increment and relational equals operators doesn't work (like so):

while (*s++ == *t++)
    if (*s=='\0')
        return 0;
return *s - *t;

The latter always returns 0. I thought this could be because we're incrementing the pointers too soon, but even with a difference in the two string occurring at index 5 out of 10 still produces the same result.

Example input: strcomp("hello world", "hello xorld");

return value: 0

My hunch is this is because of operator precedence but I'm not positive and if so, I cannot exactly pinpoint why.

Thank you for your time!

like image 673
Matthew Follegot Avatar asked Apr 18 '20 20:04

Matthew Follegot


People also ask

Can you compare strings with ==?

You should not use == (equality operator) to compare these strings because they compare the reference of the string, i.e. whether they are the same object or not. On the other hand, equals() method compares whether the value of the strings is equal, and not the object itself.

What happens when you compare two strings with the == operator?

In String, the == operator is used to comparing the reference of the given strings, depending on if they are referring to the same objects. When you compare two strings using == operator, it will return true if the string variables are pointing toward the same java object. Otherwise, it will return false .

Can you compare strings in C++ with ==?

In C++ we can compare two strings using compare() function and the == operator.

How do you compare two strings together?

The equals() method compares two strings, and returns true if the strings are equal, and false if not. Tip: Use the compareTo() method to compare two strings lexicographically.


3 Answers

Because in the for loop, the increment (s++, t++ in your case) is not called if the condition (*s==*t in your case) is false. But in your while loop, the increment is called in that case too, so for strcomp("hello world", "hello xorld"), both pointers end up pointing at os in the strings.

like image 73
numzero Avatar answered Oct 31 '22 03:10

numzero


Since you always increment s and t in the test, you should refer to s[-1] for the termination in case of equal strings and s[-1] and t[-1] in case they differ.

Also note that the order is determined by the comparison as unsigned char.

Here is a modified version:

int strcmp(const char *s, const char *t) {
    while (*s++ == *t++) {
        if (s[-1] == '\0')
            return 0;
    }
    return (unsigned char)s[-1] - (unsigned char)t[-1];
}

Following the comments from LL chux, here is a fully conforming implementation for perverse architectures with non two's complement representation and/or CHAR_MAX > INT_MAX:

int strcmp(const char *s0, const char *t0) {
    const unsigned char *s = (const unsigned char *)s0;
    const unsigned char *t = (const unsigned char *)t0;

    while (*s++ == *t++) {
        if (s[-1] == '\0')
            return 0;
    }
    return (s[-1] > t[-1]) - (s[-1] < t[-1]);
}
like image 22
chqrlie Avatar answered Oct 31 '22 02:10

chqrlie


Everyone is giving the right advice, but are still hardwired to inlining those increment operators within the comparison expression and doing weird off by 1 stuff.

The following just feels simpler and easier to read. No pointer is ever incremented or decremented to an invalid address.

while ((*s == *t) && *s)
{
    s++;
    t++;
}
return *s - *t;
like image 44
selbie Avatar answered Oct 31 '22 03:10

selbie