12

I tried to implement strcmp:

int strCmp(char string1[], char string2[]) { int i = 0, flag = 0; while (flag == 0) { if (string1[i] > string2[i]) { flag = 1; } else if (string1[i] < string2[i]) { flag = -1; } else { i++; } } return flag; } 

but I'm stuck with the case that the user will input the same strings, because the function works with 1 and -1, but it's doesn't return 0. Can anyone help? And please without pointers!

1

8 Answers 8

44

Uhm.. way too complicated. Go for this one:

int strCmp(const char* s1, const char* s2) { while(*s1 && (*s1 == *s2)) { s1++; s2++; } return *(const unsigned char*)s1 - *(const unsigned char*)s2; } 

It returns <0, 0 or >0 as expected

You can't do it without pointers. In C, indexing an array is using pointers.

Maybe you want to avoid using the * operator? :-)

Sign up to request clarification or add additional context in comments.

1 Comment

while(*s1 && (*(s1++) == *(s2++))); return... (trying to save a line ;)). However, it doesn't work correctly. My best guess is that it has to do with operator precedence, but I'm not clear what exactly. I'm currently learning C.
10

First of all standard C function strcmp compares elements of strings as having type unsigned char.

Secondly the parameters should be pointers to constant strings to provide the comparison also for constant strings.

The function can be written the following way

int strCmp( const char *s1, const char *s2 ) { const unsigned char *p1 = ( const unsigned char * )s1; const unsigned char *p2 = ( const unsigned char * )s2; while ( *p1 && *p1 == *p2 ) ++p1, ++p2; return ( *p1 > *p2 ) - ( *p2 > *p1 ); } 

21 Comments

I would personally prefer while ( *p1 && *p1 == *p2 ) {++p1, ++p2}, but otherwise, nice answer.
@Superlokkus The loop could be writtten like for ( const unsigned char *p1 = ( const unsigned char * )s1, *p2 = ( const unsigned char * )s2; *p1 && *p1 == *p2; ++p1, ++p2 ); As you see the loop has no body (statement). And it has another problem: pointers p1 and p2 are needed outside the loop.;
@Superlokkus So let's change it const unsigned char *p1 = ( const unsigned char * )s1, *p2 = ( const unsigned char * )s2; for (; *p1 && *p1 == *p2; ++p1, ++p2 ); But again this loop has no body. This is confusing.
@Superlokkus I am sorry. I do not think we will be able to say something new each other.:)
@Harith It is a general approach. For example if the comparison function compares two integers of the type unsigned int then their difference never can be negative.:)
|
6

You seem to want to avoid pointer arithmetics which is a pity since that makes the solution shorter, but your problem is just that you scan beyond the end of the strings. Adding an explicit break will work. Your program slightly modified:

int strCmp(char string1[], char string2[] ) { int i = 0; int flag = 0; while (flag == 0) { if (string1[i] > string2[i]) { flag = 1; } else if (string1[i] < string2[i]) { flag = -1; } if (string1[i] == '\0') { break; } i++; } return flag; } 

A shorter version:

int strCmp(char string1[], char string2[] ) { for (int i = 0; ; i++) { if (string1[i] != string2[i]) { return string1[i] < string2[i] ? -1 : 1; } if (string1[i] == '\0') { return 0; } } } 

Comments

2

This is a 10 opcodes implementation of strcmp (GCC assumed)

int strcmp_refactored(const char *s1, const char *s2) { while (1) { int res = ((*s1 == 0) || (*s1 != *s2)); if (__builtin_expect((res),0)) { break; } ++s1; ++s2; } return (*s1 - *s2); } 

You can try this implementation and compare to others https://godbolt.org/g/ZbMmYM

Comments

0

Your problem is that you don't detect the end of the string and therefore don't return zero if both strings ends before any difference is detected.

You can simply fix this by checking for this in the loop condition:

while( flag==0 && (string1[i] != 0 | string2[i] != 0 ) ) 

Note that both strings are checked because if only one is at the end the strings are not equal and the comparison inside the loop should detect that.

Please note that the character comparison might not yield the result that you might expect. For one it's not defined whether char is signed or unsigned so you should probably cast to unsigned char for comparison.

Perhaps a cleaner solution would be to return immediately when you detect the difference, that is instead of flag = -1 you return -1 directly. But that's more a matter of opinion.

6 Comments

The && is superfluous, you know string1[i] == string2[i] at this stage.
if strin1 is zero and string 2 is not zero you continue to while into undefined behaviour
@PeterMiehle in that case string1[i]<string2[i] would be true and you'll stop returning -1.
@zakinster Good points, I've decided to skip that solution and check in the loop condition instead.
@zakinster Not exactly, you know string1[i] was equal to string2[i] the last iteration if there were any. However the second test in the while statement checks if we reached the end of any of the strings and therefore it's needed anyway - the strings "a\0z" and "a\0y" should compare equal.
|
0

My Implementation

int strcmp(const char * s1, const char * s2) { while (*s1 == *s2 && *s1++ | *s2++); int i = *s1 - *s2; return i < 0 ? -1 : i > 0 ? 1 : 0; } 

return values

-1 // <0 1 // >0 0 // ==0 

The last ternary operation is optional

The function would still in the rules of strcmp when you just return *s1 - *s2.

1 Comment

You are comparing elements past the null. See: strcmp("foobar\0b", "foobar\0a") returns 1, should return 0 (as does strcmp from the standard library). Try this: while (*s1 && *s1 == *s2) {s1++; s2++;}
0

Another elegant (but not the most "clean code") implementation, with pointers.

int a_strcmp(char* t, char* s) { for( ; *t == *s ; *s++ , *t++) if(*t == '\0') return 0; return *t - *s; } 

version without using pointers.

int b_strcmp(char t[], char s[]) { int i; for(i = 0; s[i] == t[i]; ++i) if(t[i] == '\0') return 0; return t[i] - s[i]; } 

5 Comments

You skip the first character of the strings, so strcmp("a", "b") would compare equal.
Corrected the post, Olaf, good catch, thank you!
Don't increment inside the while condition. E.g. the very first i++ will return zero/false, resulting in an equal result, even when the strings are different strcmp("abc", "abd"). Same goes for the first implementation. Consider strcmp("\0a", ""), this will break after the first character and compare non-equal, even though it should return zero. Please test both implementations with several inputs and verify that they are working as expected.
Thanks again, changed implantation using for loop where increment are more straightforward.
You don't need the asterisks in *s++ , *t++.
0

Taken from here.

#include<stdio.h> #include<string.h> //using arrays , need to move the string using index int strcmp_arry(char *src1, char *src2) { int i=0; while((src1[i]!='\0') || (src2[i]!='\0')) { if(src1[i] > src2[i]) return 1; if(src1[i] < src2[i]) return -1; i++; } return 0; } //using pointers, need to move the position of the pointer int strcmp_ptr(char *src1, char *src2) { int i=0; while((*src1!='\0') || (*src2!='\0')) { if(*src1 > *src2) return 1; if(*src1 < *src2) return -1; src1++; src2++; } return 0; } int main(void) { char amessage[] = "string"; char bmessage[] = "string1"; printf(" value is %d\n",strcmp_arry(amessage,bmessage)); printf(" value is %d\n",strcmp_ptr(amessage,bmessage)); } 

I've made a few changes to make it work like strcmp.

1 Comment

You miss-copied, left out negative signs.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.