1

In my homework, I need to make a function that take 10 names and compares them, telling me if the names are the same or not.

First, I made a function that puts the names in an array, then I made a function that checks if they are the same or not.

For the beginning, I made a function to check letter after letter if is similar or not:

int stringCmpi (char *s1,char *s2)
{
    int i=0,diff=0;
    for(i=0; s1[i]!='\0'; i++)
    {
        if( toupper(s1[i])!=toupper(s2[i]) )
            return 1;
    }
    return 0;
} 

Then I made a function to check the strings, name after name:

int cheak ()
{
    int k;
    int j=SIZE;
    for(k=0;k<MAX;k++)
        for(j=MAX;j>=k;j--)
        {
            if(1==stringCmpi(names[k],names[j]))
            {
                return 0;
            }
            return 1;
        }
}

In the main I do:

if(cheak(names)==1)
{
    printf("\nyou repeat names\n");
}
if(cheak(names!=1))
{
    printf("\n great! the names are not repeat\n");
}

But something in my code is wrong because it compiles but is not working. So, please help me - I would appreciate it.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Idan D
  • 22
  • 3

2 Answers2

3

As KamilCuk has said in the comments, one significant problem you have is when the strings you are comparing have different lengths. Without using the standard library functions (which is, I guess, your goal), you can check for this by looking for nul terminators in different places in your compare function.

Here's one way to do that:

int stringCmpi (char *s1,char *s2)
{
    int i; // =0,diff=0; /// You don't use "diff" and "i" is initialized in the for loop!
    for(i=0; s1[i]!='\0'; i++)
    {
        if( toupper(s1[i])!=toupper(s2[i]) ) // This check will catch situations where...
            return 1; // ... s2 is SHORTER than s1, as s2[i] will be '\0' and s1 won't be!
    }
    // But we need to catch if s2 is LONGER than s1: s1[i] will now be '\0'...
    // ... so we can just check that s2[i] is ALSO '\0' (i.e. it's same length):
    if (s2[i] != '\0') return 1; // Different length strings!
    return 0;
} 

Feel free to ask for further clarification and/or explanation.

EDIT/PS: Also, as Ed Heal has mentioned, the comparison: if(cheak(names!=1)) is very suspect - probably just a typo, where you meant if(cheak(names)!=1). However, it would be much easier here just to use else!

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
2

Let's start from the function stringCmpi.

int stringCmpi (char *s1,char *s2)
{
    int i=0,diff=0;
    for(i=0; s1[i]!='\0'; i++)
    {
        if( toupper(s1[i])!=toupper(s2[i]) )
            return 1;
    }
    return 0;
} 

and let's assume that s1 is "A" and s2 is "AB". In this case the function returns 0 because the loop will stop its iteration after comparing the first character 'A' of the both string.

So this function is incorrect.

Now let's consider the function cheak

int cheak ()
{
int k;
int j=SIZE;
for(k=0;k<MAX;k++)
  for(j=MAX;j>=k;j--)
{
   if(1==stringCmpi(names[k],names[j]))
{
   return 0;
}
   return 1;
}
}

It seems that the identifier MAX means the number of strings in the array. In this case the index with the value MAX specifiers a non-existent string because the valid range of indices is [0, MAX). SO the function already has undefined behavior.

If two names are unequal you at once exit the function though the array can conatin equal names. So the function can return a wrong result.

What you need is the following.

#include <stdio.h>
#include <ctype.h>

int stringCmpi( const char *s1, const char *s2 )
{
    while ( *s1 != '\0' && 
            toupper( ( unsigned char )*s1 ) == toupper( ( unsigned char )*s2 ) )
    {
        ++s1; ++s2;
    }

    return *s1 != *s2;
} 

int check( size_t m, size_t n, char  names[const m][n] )
{
    int unique = 1;

    for (size_t i = 0 ; unique && i < m; i++ )
    {
        for ( size_t j = i + 1; unique && j < m; j++ )
        {
            unique = stringCmpi( names[i], names[j] );
        }
    }

    return unique;
}


int main(void) 
{
    {
        enum { M = 3, N = 10 };
        char names[M][N] = { "Bob", "Tome", "David" };

        if( check( M, N, names ) )
        {
            printf( "\ngreat! the names are not repeat\n" );
        }
        else
        {
            printf( "\nyou repeat names\n" );
        }           
    }

    {
        enum { M = 3, N = 10 };
        char names[M][N] = { "Bob", "Tome", "Bob" };

        if( check( M, N, names ) )
        {
            printf( "\ngreat! the names are not repeat\n" );
        }
        else
        {
            printf( "\nyou repeat names\n" );
        }           
    }

    return 0;
}

The program output is

great! the names are not repeat

you repeat names

Or if your compiler does not support variable length arrays then the program can look like

#include <stdio.h>
#include <ctype.h>

#define M   3
#define N   10

int stringCmpi( const char *s1, const char *s2 )
{
    while ( *s1 != '\0' && 
            toupper( ( unsigned char )*s1 ) == toupper( ( unsigned char )*s2 ) )
    {
        ++s1; ++s2;
    }

    return *s1 != *s2;
} 

int check( char names[][N], size_t m )
{
    int unique = 1;

    for (size_t i = 0 ; unique && i < m; i++ )
    {
        for ( size_t j = i + 1; unique && j < m; j++ )
        {
            unique = stringCmpi( names[i], names[j] );
        }
    }

    return unique;
}

int main(void) 
{
    {
        char names[M][N] = { "Bob", "Tome", "David" };

        if( check( names, M ) )
        {
            printf( "\ngreat! the names are not repeat\n" );
        }
        else
        {
            printf( "\nyou repeat names\n" );
        }           
    }
    {
        char names[M][N] = { "Bob", "Tome", "Bob" };

        if( check( names, M ) )
        {
            printf( "\ngreat! the names are not repeat\n" );
        }
        else
        {
            printf( "\nyou repeat names\n" );
        }           
    }
}    
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335