0

In my code, I used a tolower function in order to eliminate letters not considering their cases. ( case insensitive) but my problem is that if my first input is "HELLO" and my 2nd is "hi" the ouput would be "ello" in lowercase letters instead of "ELLO". Is there any way to fix this? Should I not use tolower function?

#include <stdio.h>
#include <conio.h>
void main()
{

 char s1[20],s2[20];
 int i,j;
 printf("\nEnter string 1:-  ");
 gets(s1);
 printf("\nEnter the string for matching:-  ");
 gets(s2);
  for(int i = 0; s1[i]; i++)
 {
  s1[i] = tolower(s1[i]);
 }
 for(int i = 0; s2[i]; i++)
 {
  s2[i] = tolower(s2[i]);
 }
 
 for (i=0;(i<20&&s1[i]!='\0');i++)
 {
  for (j=0;(j<20&&s2[j]!='\0');j++)
  {
   if (s1[i]==s2[j])
    s1[i]=' ';
  }

 }
 printf("\nString 1 after deletion process is %s",s1);

 printf("\nIts compressed form is  ");

 for (i=0;(i<20&&s1[i]!='\0');i++)
 {
  if (s1[i]!=' ')
   printf("%c",s1[i]);
 }
 getch();
}
nina
  • 9
  • 2
  • Never use gets its DEPRECATED...and dangerous. – G4143 Jan 04 '22 at 03:37
  • Tangential: note that [the `gets()` function is too dangerous to use — ever!](https://stackoverflow.com/q/1694036/15168) – Jonathan Leffler Jan 04 '22 at 03:38
  • 3
    Since the loops after the two calls to `gets()` case-convert the input to lower-case, there's no way to get the upper-case output. You can either make a copy of the input and case-convert one version and report using the other, or live with all lower-case output, or make the case-changes on the fly as you're doing the comparisons. – Jonathan Leffler Jan 04 '22 at 03:40
  • "I used a tolower function in order to eliminate letters" What do you mean, what are you trying to do? Compare strings? – yano Jan 04 '22 at 03:41
  • Is the objective to eliminate any occurrences of either `'h'` or `'i'` (in either upper-case or lower-case)? And you're replacing the eliminated characters with blanks `' '`? – Jonathan Leffler Jan 04 '22 at 03:42
  • You shouldn't use magic numbers! char s1[20],s2[20]. You should define constants that represent the sizes of the char arrays. – G4143 Jan 04 '22 at 03:45
  • 1
    Fwiw, `gets` isn't just deprecated; it was officially [**removed** from the official standard library a decade ago](https://en.cppreference.com/w/c/io/gets). The only remnants are from vendors continuing support for legacy code reasons (which is terrible, btw, since any code that uses it shouldn't ever be allowed to compile regardless; better to break it than support it). – WhozCraig Jan 04 '22 at 03:52

3 Answers3

0

Your code has security vulnerabilities because you're using gets() (if the text input by the user is larger than 19 bytes, you'll have buffer overflows on variables s1 and s2). This function is bugged, it's not fixable and should never be used. Instead use, for example, fgets(s1, sizeof(s1), stdin).

The main idea of the problem is that you must preserve the strings, so remove the loops that modify them. In this case the correct predicate for checking if each compared character is the same without regard to case would become:

        if (tolower((unsigned char)s1[i]) == tolower((unsigned char)s2[j]))
hdante
  • 7,685
  • 3
  • 31
  • 36
  • Yes, it looks like you're right and it looks like it's a bug in the specification of tolower(), which requires unsigned char instead of char. I'll update the example code. – hdante Jan 04 '22 at 18:45
0
  1. Write a function
  2. Compare the results of tolower() directly — don’t change the strings themselves
  3. Do not use gets() and scanf("%s") — both have no bounds checking

EDIT: sorry, this function simply compares two strings. It is meant to give you an idea of how to use tolower() effectively, not do your work for you. :-)

#include <iso646.h>
#include <ctype.h>

bool is_equal( const char * a, const char * b )
{
  while (*a and *b)
  {
    if (tolower( *a ) != tolower( *b ))
      return false;
    ++a;
    ++b;
  }
  if (*a or *b) return false;
  return true;
}

Now you can call the function directly.

if (is_equal( "HELLO", "hello" )) ...

Getting a string input from the user in C is always a pain, but you can use fgets() for that.

char s[100]; // the target string (array)
fgets( s, 100, stdin ); // get max 99 characters with null terminator
char * p = strchr( s, '\n' ); // find the Enter key press
if (p) *p = '\0'; // and remove it

puts( s );  // print the string obtained from user

You can always wrap all the annoying stuff for getting strings into a function.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39
  • `while (*a and *b)` loop needs a `++, b++` someplace. Only `while (*a)` needed. – chux - Reinstate Monica Jan 04 '22 at 04:18
  • Oops. Thanks. I am not liking my answer anyway... I missed the point of OP’s post. The while condition is correct, tho... let the compiler figure out stuff like that, not some unlucky newbie reusing or changing the stuff in the loop. – Dúthomhas Jan 04 '22 at 15:47
0

Is there any way to fix this? Should I not use tolower function?

Instead of changing s1[] to lower case, leave s1[] "as is" and change the compare. Still good to change s2[].

// if (s1[i]==s2[j]) s1[i]=' ';
if (tolower(((unsigned char*)s1)[i]) == s2[j]) s1[i]=' ';

tolower(int ch) is well defined for all int values in the unsigned char range and EOF. Since a char may be negative and string processing is best done as unsigned char, use the cast. Also in the s2[] processing.


Also do not use gets(). Research fgets().

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256