strcmp function return value in another function - c

I know what strcmp returns but I don't know what it returns in this code.
firstly I have this function:
static int match_str(const void *str1, const void *str2)
{
return !strcmp((const char *)str1, (const char *)str2);
//if not equal return 1.
}
and then I have this
if (match_str) return 1; // not equal so return
else{ my code goes on} // equal so continue
What I don't understand is if str1 equals to str2, the match_str should returns 0. and then the code moves on.
but it adds a '!' operater. it seems like if they are equal strcmp=0, it returns to "!0 " which means"!0=1 " . but if returns to 1. it seems like if they are equal, it will stop.
Actually, it continues if they are equal.
I really confused why " return !strcmp " works rather than "return strcmp", what is the purpose of using '!' here.
thanks

From C Standard##6.5.3.3p5
5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).
>> What I don't understand is if str1 equals to str2, the match_str should returns 0. and then the code moves on.
Because of use of ! operator with strcmp in return statement (return !strcmp(.....)), the match_str() will return 1 if string matches and 0 if they don't match.
>> I really confused why " return !strcmp " works rather than "return strcmp", what is the purpose of using '!' here.
The strcmp() returns 0 if string matches and non zero value if they do not match because it compares two null-terminated strings lexicographically. The author of function match_str() actually wanted to return 1 if string matches and seems that, having this thought in mind, s/he has given name (match_str) to the function. The caller of match_str() function should be aware of this while using match_str() function.
if (match_str(str1, str2)) {
//strings are equal
} else {
//strings are not equal
}

Related

Why is the output different in the short version of if condition when compared to its expanded version?

int a = 0;
a = 7 > 2 ? printf("6") : printf("4");
printf ("%d",a);
The ouput of this block is :
61
I tried the code in its expanded form
int a = 0 ;
if(7>2)
{
printf("6");
}
else
{
printf("4");
}
printf("%d",a);
Here I the output was:
60
I would like to get an explanation on why the output differs.
The first statement assigns the return value of printf to a. printf returns the number of bytes that were written. In this case that is 1. In the second expanded version, a is not assigned. Here is an actually equivalent version to the original:
int a = 0;
if(7>2)
{
a = printf("6");
}
else
{
a = printf("4");
}
printf("%d",a);
They are completely different.
To make them identical:
int a = 0 ;
if(7>2)
{
a = printf("6");
}
else
{
a = printf("4");
}
printf("%d",a);
cond?val1:val2 is the ternary operator. It is not supposed to be a control structure (like if, for or while). It is an operator. To build expression (things that have a value) rather than instruction (things that does things).
Frontier is fuzzier in C than in other languages, because instructions have a value (including void) and expression have potential side-effects.
But, well, you use cond?val1:val2 when you want to get the result. As you did, since you assigned the result to a.
And the result here is the result of printf("6"), that is 1, since printf returns the number of printed characters. Note that there is no real doubt, since even if 7 were smaller than 2, result would still have been 1. Since you print that result, it is normal to have a 1 printed after the 6.
(Just to be clear, even if I assume you know that already, what you did is print string "6" and then number 1, which is the result of 1st printf. Exactly as if you did
printf("%d",printf("6"));
which 1st prints "6", then pass the result to the outer printf to print what the inner printf returned, that is 1)
In your second code, you do nothing to change a's value, and you ignore the result of printf.
Your examples aren't equivalent. To be equivalent, the second one should say a=printf(... everywhere. After which a will get assigned the number of characters printed, 1.
The conditional operator (e1 ? e2 : e3) is not a "short version of if condition", although it has some similarities with an if ... else construct. The conditional operator yields a value (which you assign to a in your first example); an if ... else construct does not have a value.
So, your first example assigns a value to a, because it is written in the form of an assignment statement; that value is the 1 returned by the call to the printf function. To get similar behaviour in your second example, as others have said, you need to also assign the value returned by printf inside the if ... else blocks.
Alternatively, to make the first case work like the second, you can skip the assignment and use the conditional operation to determine the argument that is passed to the printf call:
int main(void)
{
int a = 0;
printf(7 > 2 ? "6" : "4");
printf("%d", a);
return 0;
}

Confusion with operator '!' in c

I've seen the operator ! being used in multiple places differently and I still don't get how it actually works. My basic understanding is it reverses the value from true to false and vice versa. If it reversed to true the statement triggers. Let's take an example.
int main(void)
{
int a = 5;
if (!(a == 6))
{
printf("unlike\n");
}
if (!(a == 5))
{
printf("like\n");
}
}
In the code above since a is 5 it ends up printing "unlike" because the false statement that a is 6 got reversed. Now let's take another example.
int main(void)
{
string i = "abc";
string j = "cab";
string k = "abc";
if (!strcmp(i, j))
{
printf("unlike\n");
}
if (!strcmp(i, k))
{
printf("like\n");
}
}
The string type has been taken from the cs50.h header and strcmp from string.h. strcmp returns value 0 if the two strings are alike and if unlike depending on the alphabetical order returns a positive or negative value. Now if we follow the logic in the previous example, since i and j are unlike, and false it should be reversed to true and unlike should be the output. But I tried running the code and the result was like.
I am confused. Can anyone please explain this to me clearly? Feel free to use other examples too. I could always get away with not using ! but I just want to learn what it is and how to properly use it.
A boolean in C is an integer with zero for false and non-zero for true.
strcmp returns 0 when the compared strings are identical and a non-zero value depending on the difference otherwise. Therefore, strcmp(i,k) is seen as "false". The ! then changes this to "true", which leads to your current output.
In the first case a = 5. then if (!(a == 6)); here a = 6 is not true (false), so it's something like this. if (!(false)) it means if (true). That's why it prints "unlike".
strcmp(i, j) returns 0 if the strings i and j match; otherwise, it will return a non-zero value. In your case,
(!strcmp(i, j))
Here i and j are not equal so strcmp will return a non-zero value because i != j. So !(1) means not(1) means 0, so the if condition is false because of zero. Therefore it'll not execute the printf("unlike\n") line.
(!strcmp(i, k))
Here i and k are same so strcmp will return 0. !(0) means not(0) = 1 so the if condition is true. It will execute the printf("like\n") line.

What does the exclamation point in if (!strcmp() ... do?

Can someone explain what the exclamation point in the if statement does (i.e. !strmcp)?
string names[] = {"EMMA", "RODRIGO", "BRIAN", "DAVID"};
// Search for EMMA
for (int i = 0; i < 4; i++)
{
if (!strcmp(names[i], "EMMA"))
{
printf("Found\n");
return 0;
}
}
printf("Not found\n");
return 1;
For an if statement, if the expression evaluates to 0, then the block of code following the if statement is not executed. Any other value (positive or negative), will result in executing the code block. The function strcmp uses 0 to say that strings are equal because less than 0 is used to differ from greater than 0.
So in this code, we want printf("Found\n"); to be executed when the strings are equal. Since strcmp results in 0, we need to negate the value so that it becomes 1 which will result in executing that code block.
strcmp() returns 0 if the strings are identical, so you need to negate it, if you use it in an if clause to assert a true statement.
If your clause is if(0), the code inside the condition will not be executed.
For completion, it returns negative if the first different character found is lower in the first string, for instance:
first parameter string: "abca"
second parameter string :abcd"
This will return negative. If it's the other way arround it will return positive.
Also, string is not usually used in C (I refer you to Jonathan Leffler's commment), you can use char*:
char *names[] = {"EMMA", "RODRIGO", "BRIAN", "DAVID"};
Unary operator ! is called the logical NOT operator (cf., for example, this definition at cppreference.com). ! expression returns 1 if expression evaluates to 0, and it returns 0 if expression evaluates to anything else but 0.
So the condition in if (!0) gives 1; this means, the condition is met and the if-block is entered. It has the same meaning as if(0==0)
Consequently, the meaning of
if(!strcmp(names[i], "EMMA"))
in your code is exactly the same as
if(0==strcmp(names[i], "EMMA"))
And you already know when strcmp returns 0...
The exclamation point is the C's boolean negation character.
It means give me the boolean opposite of the value. A boolean is either true or false, which are 1 or 0 in the C Language.
In C, if statements execute their conditional statements if the argument is true.
if (a) means if a is true (i.e. non-zero)
if (!a) means if a is false (i.e. 0)
Therefore:
if (a) is the same as if (a != 0)
if (!a) is the same as if (a == 0)
Sometimes you'll see code that uses two exclamation points in a row "!!"
For example:
int a = !!b;
That ensures a will be ONLY 0 or 1, regardless of what the value of b is.
If b is ANY non-zero value, the ! operator will treat it as though it is true true, which it treats as being the same as 1
So:
!0 == 1
!1 == 0
!52 == 0
!25692 == 0
The second ! does the boolean inversion again, so:
!!0 == 0
!!1 == 1
!!52 == 1
!!25692 == 1
In C any non zero value is considered ad the logical truth, zero i considered as logical false. ! is a logical negation. So !0 (not false) will be the truth and if(!strcmp(str1,str2)) {statements} statements will be executed when str1 will be same as str2

Is it a bug in str_replace?

I searched for a string replacement function and found this question
What is the function to replace string in C?
If I use the code from the answer, it works but it looks wrong and gives a warning:
/home/dac/osh/util.c: In function ‘str_replace’:
/home/dac/osh/util.c:867:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
for (count = 0; tmp = strstr(ins, rep); ++count) {
It looks like it's maybe a bug with = and == . Is it a bug or did I misunderstand? Should it be == instead?
No, it's not. In this case, the value of tmp is actually intended to be used as the condition.
The return value of strstr:
char * strstr(char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
To remove the warning, try this:
for (count = 0; (tmp = strstr(ins, rep)) != NULL; ++count) {
No, it's not a bug. As per the body of the loop:
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
it actually uses tmp for something. The continuation condition in that for statement will assign the result of strstr() to tmp then execute the body as long as it's non-zero (i.e., as long as it found the string). That's because strstr() returns NULL only if the string cannot be found.
I suspect this is just gcc being paranoid in that it realises the continuation condition (the middle bit) on a for statement usually tends to be a comparison and you may have accidentally used = rather then ==.
That's why the diagnostic states warning: suggest ... rather than error: what the heck? :-) If you want to get rid of the warning (which isn't a bad position to take), simply do what it suggests and surround the entire continuation condition with parentheses.
[ strstr reference ] states the return value for char * strstr (char *str1,const char *str2 ) is :
A pointer to the first occurrence in str1 of the entire sequence of
characters specified in str2, or a null pointer if the sequence is not
present in str1.
Now for a little more C terminology, when you do :
tmp = strstr(ins, rep)
the main intent of C is to evaluate the expression as a whole and C evaluates it to the return value of strstr(ins, rep) here. The side effect is assigning this return value to tmp. The error :
suggest parentheses around assignment used as truth value
is a way gcc helps you to avoid a careless mistake, say typing a=b instead of a==b, I believe. Note that in the first case the value of b is used as truth value, but in the second case the result of is a equal b is used a truth value. By putting a () around tmp = strstr(ins, rep) you give the compiler the green signal to evaluate the value of the expression as truth value.
Side Note :
Putting () around tmp = strstr(ins, rep) makes it a full expression, and full expression is considered as a sequence point. A sequence point is a point in program execution at which all side effects are evaluated before going on to the next step.

Why does strcmp() return 0 when its inputs are equal?

When I make a call to the C string compare function like this:
strcmp("time","time")
It returns 0, which implies that the strings are not equal.
Can anyone tell me why C implementations seem to do this? I would think it would return a non-zero value if equal. I am curious to the reasons I am seeing this behavior.
strcmp returns a lexical difference (or should i call it "short-circuit serial byte comparator" ? :-) ) of the two strings you have given as parameters.
0 means that both strings are equal
A positive value means that s1 would be after s2 in a dictionary.
A negative value means that s1 would be before s2 in a dictionary.
Hence your non-zero value when comparing "time" and "money" which are obviously different, even though one would say that time is money ! :-)
The nice thing about an implementation like this is you can say
if(strcmp(<stringA>, <stringB>) > 0) // Implies stringA > stringB
if(strcmp(<stringA>, <stringB>) == 0) // Implies stringA == stringB
if(strcmp(<stringA>, <stringB>) < 0) // Implies stringA < stringB
if(strcmp(<stringA>, <stringB>) >= 0) // Implies stringA >= stringB
if(strcmp(<stringA>, <stringB>) <= 0) // Implies stringA <= stringB
if(strcmp(<stringA>, <stringB>) != 0) // Implies stringA != stringB
Note how the comparison with 0 exactly matches the comparison in the implication.
It's common to functions to return zero for the common - or one-of-a-kind - case and non-zero for special cases. Take the main function, which conventionally returns zero on success and some nonzero value for failure. The precise non-zero value indicates what went wrong. For example: out of memory, no access rights or something else.
In your case, if the string is equal, then there is no reason why it is equal other than that the strings contain the same characters. But if they are non-equal then either the first can be smaller, or the second can be smaller. Having it return 1 for equal, 0 for smaller and 2 for greater would be somehow strange i think.
You can also think about it in terms of subtraction:
return = s1 - s2
If s1 is "lexicographically" less, then it will give is a negative value.
Another reason strcmp() returns the codes it does is so that it can be used directly in the standard library function qsort(), allowing you to sort an array of strings:
#include <string.h> // for strcmp()
#include <stdlib.h> // for qsort()
#include <stdio.h>
int sort_func(const void *a, const void *b)
{
const char **s1 = (const char **)a;
const char **s2 = (const char **)b;
return strcmp(*s1, *s2);
}
int main(int argc, char **argv)
{
int i;
printf("Pre-sort:\n");
for(i = 1; i < argc; i++)
printf("Argument %i is %s\n", i, argv[i]);
qsort((void *)(argv + 1), argc - 1, sizeof(char *), sort_func);
printf("Post-sort:\n");
for(i = 1; i < argc; i++)
printf("Argument %i is %s\n", i, argv[i]);
return 0;
}
This little sample program sorts its arguments ASCIIbetically (what some would call lexically). Lookie:
$ gcc -o sort sort.c
$ ./sort hi there little fella
Pre-sort:
Argument 1 is hi
Argument 2 is there
Argument 3 is little
Argument 4 is fella
Post-sort:
Argument 1 is fella
Argument 2 is hi
Argument 3 is little
Argument 4 is there
If strcmp() returned 1 (true) for equal strings and 0 (false) for inequal ones, it would be impossible to use it to obtain the degree or direction of inequality (i.e. how different, and which one is bigger) between the two strings, thus making it impossible to use it as a sorting function.
I don't know how familiar you are with C. The above code uses some of C's most confusing concepts - pointer arithmetic, pointer recasting, and function pointers - so if you don't understand some of that code, don't worry, you'll get there in time. Until then, you'll have plenty of fun questions to ask on StackOverflow. ;)
You seem to want strcmp to work like a (hypothetical)
int isEqual(const char *, const char *)
To be sure that would be true to the "zero is false" interpretation of integer results, but it would complicate the logic of sorting because, having established that the two strings were not the same, you would still need to learn which came "earlier".
Moreover, I suspect that a common implementation looks like
int strcmp(const char *s1, const char *s2){
const unsigned char *q1=s1, *q2=s2;
while ((*q1 == *q2) && *q1){
++q1; ++q2;
};
return (*q1 - *q2);
}
which is [edit: kinda] elegant in a K&R kind of way. The important point here (which is increasingly obscured by getting the code right (evidently I should have left well enough alone)) is the way the return statement:
return (*q1 - *q2);
which gives the results of the comparison naturally in terms of the character values.
There's three possible results: string 1 comes before string 2, string 1 comes after string 2, string 1 is the same as string 2. It is important to keep these three results separate; one use of strcmp() is to sort strings. The question is how you want to assign values to these three outcomes, and how to keep things more or less consistent. You might also look at the parameters for qsort() and bsearch(), which require compare functions much like strcmp().
If you wanted a string equality function, it would return nonzero for equal strings and zero for non-equal strings, to go along with C's rules on true and false. This means that there would be no way of distinguishing whether string 1 came before or after string 2. There are multiple true values for an int, or any other C data type you care to name, but only one false.
Therefore, having a useful strcmp() that returned true for string equality would require a lot of changes to the rest of the language, which simply aren't going to happen.
I guess it is simply for symmetry: -1 if less, 0 if equal, 1 if more.

Resources