I want to know what is compared when we have s1 > s2 and what is the result (for example when we compare chars their ASCII corresponding codes are compared). I read that with this operation are compared the first chars of s1 and s2, but if I try to compare with s1[0] > s2[0] the result is different, then it cannot be that.
Comparing with == means checking if the pointers point to the same object, so this:
char s1[] = "foo";
char s2[] = "foo";
if(s1 == s2)
puts("Same object");
else
puts("Different object");
would print "Different object".
< and > makes absolutely no sense unless the pointers are pointing to the same object. For instance, you could do like this:
char s[] = "asdfasdf";
char *p1 = &s[3], *p2 = &s[6];
if(p1 < p2)
// Code
If you have character arrays like for example
char s1[] = "Hello";
char s2[] = "Hello";
then in an if statement like for example this
if ( s1 == s2 ) { /*,,,*/ }
the character arrays are implicitly converted to pointers to their first elements.
So the above statement is equivalent to
if ( &s1[0] == &s2[0] ) { /*,,,*/ }
As the arrays occupy different extents of memory then the result of such a comparison will be always equal to logical false.
If you want to compare strings stored in the arrays you need to use the standard string function strcmp declared in the header <string.h>.
For example
#include <string.h>
#include <stdio.h>
//...
if ( strcmp( s1, s2 ) == 0 )
{
puts( "The strings are equal." );
}
else if ( strcmp( s1, s2 ) < 0 )
{
puts( "The first string is less than the second string." );
}
else
{
puts( "The first string is greater than the second string." );
}
You could use the following macro that might be considered a slight abuse of preprocessor.
#define STROP(a, OP, b) (strcmp(a, b) OP 0)
Examplary usage:
STROP(s1, >=, s2) // expands to `strcmp(s1,s2) >= 0`
STROP(s1, ==, s2) // expands to `strcmp(s1, s2) == 0`
Related
I am trying to write a C function that compares tho strings not as pointer equality but content equality. But I get an error
error: invalid type argument of unary ‘*’ (have ‘int’)
This is my code:
#include <stdio.h>
#include <stdlib.h>
int stringcompare(char * str1, char * str2, int strSize){
char * word1 = str1;
char * word2 = str2;
for (int i = 0; i < strSize; i++) {
if (*word1[i] != *word2[i]) {
printf("The strings are DIFFERENT!");
return 1;
}
}
printf("The strings are a MATCH!");
return 0;
}
int main(void){
char * str1 = "Hello World!";
char * str2 = "Hello World!";
stringcompare(str1, str2, 13);
}
For an array, pointed to by *ptr, an element at position i is dereferenced by *(ptr + i), which is the equivalent of ptr[i] and not *ptr[i].
This if statement
if (*word1[i] != *word2[i]) {
is incorrect because the expressions word1[i] and word2[i] have the type char. So you may not apply the dereference operator for an object of the type char.
You should write for example
if ( word1[i] != word2[i]) {
Pay attention to that the standard string function strcmp has only two parameters and it returns either negative value, or zero or a positive value depending on whether the first string is greater than the second string or is equal to the second string or is less than the second string.
It seems you mean another standard string function strncmp that indeed has three parameters..
Also you need to check whether the zero terminating character was already encountered.
Apart from this the function parameters should have the qualifier const because the passed strings are not being changed within the function.
The function can be declared and defined the following way
int stringcompare( const char *s1, const char *s2, size_t n )
{
while ( n && *s1 && *s1 == *s2 )
{
++s1;
++s2;
--n;
}
return n == 0 ? 0 : *s1 - *s2;
}
i feel kinda lost, since we started learning about pointers i kinda cant follow and i know its really important subject in C.
anyway!
so i got to make a recursive function, that will get 2 pointers:
1) pointer to index [0].
2) pointer 2 to the middle of the string.
now.. i gotta check if the first part from 0 to middle is equal from middle to end. like..... ADAMADAM.
before i transfer the string i changed entire lower letters to capitals to avoid case sensitivity... so i got something like this.. but its refusing to work.
also using constant is prohibited...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define SS 81
int CheckString(char *,int *);
int main() {
char str[SS];
int length,len,strcheck;
printf("Please enter a string:\n");
fgets(str,SS,stdin);
len=(strlen(str) - 1);
if((len>0)&&(str[len]=='\n')) // replacing '\n' key to '\0'
str[len]='\0';
length=len/2;
strcheck=CheckString(str,&length);
if (strcheck==FALSE)
printf("FALSE.\n");
else
printf("TRUE.\n");
return 0;
}
// function
int CheckString(char *str, int *i) {
if (*str != '\0')
if (*str == str[*i])
return CheckString(str+1,i++);
else
return FALSE;
return TRUE;
}
so i guess i got some problem with the pointers
It seems you mean the following
#include <stdio.h>
#include <string.h>
int CheckString(const char *s, size_t *i)
{
return s[*i] == '\0' || *s == s[*i] && CheckString(s + 1, i);
}
int main( void )
{
char *s = "ADAMADAM";
size_t i = strlen(s) / 2;
int result = CheckString(s, &i);
printf("%s\n", result ? "true" : "false");
return 0;
}
The program output
true
Note: maybe you should calculate the value for the second argument the following way
size_t i = ( strlen(s) + 1 ) / 2;
Think about this.
The outer condition in the loop inside CheckString() should be checking for *(str + *i) != '\0', or equivalently, for str[*i] != '\0'. Also, you do not need to increment *i, and certainly not i, since that is a pointer. The value *i is the distance between the characters being checked in the two halves of the string.
The modified function could look like:
int CheckString(char *str, int *i) {
if (str[*i] != '\0') {
if (*str == str[*i]) {
return CheckString(str+1,i);
} else {
return FALSE;
}
}
return TRUE;
}
The problem specification says (more or less):
I've got to make a recursive function that will get 2 pointers:
pointer 1 to index [0].
pointer 2 to the middle of the string.
I've got to check if the first part from 0 to middle is equal to the second part from middle to end, like: ADAMADAM.
As an exercise in recursion, this is fine; as a way of implementing the functionality, recursion is overkill (iteration is fine).
There is confusion (ambiguity) about the interface to the function — the wording of the question seems to suggest two char * values, but the code uses a pointer to an integer as the second argument. That's singularly peculiar. An integer value could make sense, but a pointer to an integer does not.
We need to define the conditions carefully. Taking the example string given (char str1[] = "ADAMADAM";), the two pointers might be char *p1 = &str1[0]; char *p2 = &str1[0] + strlen(str1) / 2; — meaning p1 points to the first A and p2 to the third A. Consider an alternative string: char str2[] = "MADAMADAM";; The equivalent formula would leave p1 pointing at the first M and p2 pointing at the second M.
Assuming p1 and p2 are incremented in lock-step, then:
The strings are different if, at any point before *p2 equals '\0', *p1 != *p2.
If *p2 equals '\0', then the strings are the same.
By definition, p1 and p2 point to the same array, so pointer differences are legitimate.
Further, p1 must be less than p2 to be useful; p1 equal to p2 means the strings are identical trivially.
There is a strong argument that the 'middle of the string' criterion means that either p2[p2 - p1] == '\0' or p2[p2 - p1 + 1] == '\0' (for even and odd string lengths respectively). That is, the distance between the two pointers indicates where the end of the string must be. It means that using p1 = &str[0] and p2 = &str[2] (on either of the sample strings) should fail because the end of string isn't in the right place. And if the string was "AMAMAMAM", using &str[0] and &str[2] should fail because the end of string isn't in the right place; ditto &str[0] and &str[6].
However, this 'strong argument' is also a design decision. It would be feasible to simply demand that the substring from p2 to EOS (end of string) is the same as the string from p1 for the same length. In that case, using &str[0] with either &str[2] or &str[6] (or, indeed, with the normal &str[4]) on "AMAMAMAM" would work fine.
Using some of these observations leads to this code. If you're really under instructions not to use const, simply remove the const qualifiers where they appear. The code will work the same.
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
static bool identical_halfstrings(const char *p1, const char *p2)
{
assert(p1 <= p2);
assert(strlen(p1) >= strlen(p2) + (p2 - p1));
if (*p2 == '\0')
return true;
if (*p1 != *p2)
return false;
return identical_halfstrings(p1+1, p2+1);
}
int main(void)
{
const char *strings[] =
{
"ADAMADAM",
"MADAMADAM",
"nonsense",
};
enum { NUM_STRINGS = sizeof(strings) / sizeof(strings[0]) };
for (int i = 0; i < NUM_STRINGS; i++)
{
const char *p1 = strings[i];
const char *p2 = strings[i] + strlen(strings[i]) / 2;
printf("[%s] ([%s]) = %s\n", p1, p2,
identical_halfstrings(p1, p2) ? "TRUE" : "FALSE");
}
return 0;
}
The second assertion ensures that p1 and p2 are pointing to the same string — that there isn't a null byte between the locations pointed at by p1 and p2.
Test case output:
[ADAMADAM] ([ADAM]) = TRUE
[MADAMADAM] ([MADAM]) = TRUE
[nonsense] ([ense]) = FALSE
Just for the record, an iterative version of the same function is:
static bool identical_halfstrings(const char *p1, const char *p2)
{
assert(p1 <= p2);
assert(strlen(p1) >= strlen(p2) + (p2 - p1));
while (*p2 != '\0')
{
if (*p1++ != *p2++)
return false;
}
return true;
}
It produces the same output for the sample data.
I am trying to cast s2 to make the test pass.
I store printable characters together with unsigned char values into s3.
s2 is a test string result meant to verify printable char are loaded properly in s3.
#include <stdio.h>
#include <string.h>
#define test_string_len 2
union {
char unsigned us[test_string_len];
char s1[test_string_len];
} result;
main() {
char *s2;
s2= "ab";
char unsigned s3[test_string_len];
s3[0] = 'a';
s3[1] = 'b';
s3[2] = '\0';
memcpy (result.us, s3, test_string_len);
if ( result.s1 == s2) {
printf("Pass\n");
}
printf("s2 = %s\n", s2 );
printf("s3 = %s\n", s3 );
printf("result.s1 = %s\n", s3 );
printf("result.us = %s\n", result.us );
getchar();
}
It's not possible to compare strings (or other arrays) with == in C. This is because an array such as int myarray[8]; can essentially be thought of as a pointer called myarray storing the address of the first element. In other words, == would compare the starting address of the array, rather than the contents of the actual array items being pointed to.
Instead, you must either use the strcmp or memcmp functions, or use a for() loop to cycle through each index and check that the values in each array match.
You need to change your code as follows.
if(!strcmp( result.s1,s2)) {
printf("Pass\n");
}
I am confused by strcmp(), or rather, how it is defined by the standard. Consider comparing two strings where one contains characters outside the ASCII-7 range (0-127).
The C standard defines:
int strcmp(const char *s1, const char *s2);
The strcmp function compares the string pointed to by s1 to the string
pointed to by s2.
The strcmp function returns an integer greater than, equal to, or
less than zero, accordingly as the
string pointed to by s1 is greater
than, equal to, or less than the
string pointed to by s2.
The parameters are char *. Not unsigned char *. There is no notion that "comparison should be done as unsigned".
But all the standard libraries I checked consider the "high" character to be just that, higher in value than the ASCII-7 characters.
I understand this is useful and the expected behaviour. I don't want to say the existing implementations are wrong or something. I just want to know, which part in the standard specs have I missed?
int strcmp_default( const char * s1, const char * s2 )
{
while ( ( *s1 ) && ( *s1 == *s2 ) )
{
++s1;
++s2;
}
return ( *s1 - *s2 );
}
int strcmp_unsigned( const char * s1, const char *s2 )
{
unsigned char * p1 = (unsigned char *)s1;
unsigned char * p2 = (unsigned char *)s2;
while ( ( *p1 ) && ( *p1 == *p2 ) )
{
++p1;
++p2;
}
return ( *p1 - *p2 );
}
#include <stdio.h>
#include <string.h>
int main()
{
char x1[] = "abc";
char x2[] = "abü";
printf( "%d\n", strcmp_default( x1, x2 ) );
printf( "%d\n", strcmp_unsigned( x1, x2 ) );
printf( "%d\n", strcmp( x1, x2 ) );
return 0;
}
Output is:
103
-153
-153
7.21.4/1 (C99), emphasis is mine:
The sign of a nonzero value returned by the comparison functions memcmp, strcmp,
and strncmp 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 objects being
compared.
There is something similar in C90.
Note that strcoll() may be more adapted than strcmp() especially if you have character outside the basic character set.
I know that the correct way to compare "strings" in C is by using strcmp, but now I tried comparing some character arrays with the == operator, and got some strange results.
Take a look at the following code:
int main()
{
char *s1 = "Andreas";
char *s2 = "Andreas";
char s3[] = "Andreas";
char s4[] = "Andreas";
char *s5 = "Hello";
printf("%d\n", s1 == s2); //1
printf("%d\n", s3 == s4); //0
printf("%d\n", s1 == s5); //0
}
The first printf correctly prints a 1, which signals that they are not equal. But can someone explain to me why, when comparing the character arrays, the == is returning a 0 ?
Can someone please explain to me why the first printf is returning a 1 (ie, they are equal) and the character arrays are returning a 0 ?
The == is comparing the memory address.
It's likely that your compiler is making s1 and s2 point to the same static data to save space.
ie. The "Andreas" in the first two lines of code is stored in your executable data. The C standard says these strings are constant and so has optomized the two pointers to point to the same storage.
The char[] lines create a variable by copying the data into the variable and so are stored at different address on the stack during execution.
Uh... when == prints a 1, it means they are equal. It's different from strcmp, which returns the relative order of the strings.
You are comparing addresses and not the strings. The first two are constant and will only be created once.
int main()
{
char *s1 = "Andreas";
char *s2 = "Andreas";
char s3[] = "Andreas";
char s4[] = "Andreas";
char *s5 = "Hello";
printf("%d\n", s1 == s2); //1
printf("%p == %p\n", s1, s2);
printf("%d\n", s3 == s4); //0
printf("%p != %p\n", s3, s4);
printf("%d\n", s1 == s5); //0
printf("%p != %p\n", s1, s5);
}
Output on my computer, but you get the idea:
1
0x1fd8 == 0x1fd8
0
0xbffff8fc != 0xbffff8f4
0
0x1fd8 != 0x1fe0
Wait a sec... 1 means true, 0 means false. So your explanation is partially backwards. As for why the first two strings seem to be equal: The compiler built that constant string (s1/2) just once.
s1 == s2 means "(char*) == (char*)" or that the addresses are the same.
Same thing for s3 == s4. That's the "arrays decay into pointers" at work.
And you have the meaning of the result of the comparison wrong:
0 == 0; /* true; 1 */
42 == 0; /* false; 0 */
"foo" == "bar"; /* false (the addresses are different); 0 */
All the values from s1 through s5 aren't char themselves, they're pointers to char. So what you're comparing is the memory addresses of each string, rather than the strings themselves.
If you display the addresses thus, you can see what the comparison operators are actually working on:
#include <stdio.h>
int main() {
char *s1 = "Andreas";
char *s2 = "Andreas";
char s3[] = "Andreas";
char s4[] = "Andreas";
char *s5 = "Hello";
printf("%p\n", s1); // 0x80484d0
printf("%p\n", s2); // 0x80484d0
printf("%p\n", s3); // 0xbfef9280
printf("%p\n", s4); // 0xbfef9278
printf("%p\n", s5); // 0x80484d8
}
Exactly where the strings are allocated in memory is implementation specific. In this case, the s1 and s2 are pointing to the same static memory block, but I wouldn't expect that behaviour to be portable.
You can't compare strings, but you can compare pointers.