2

I'm trying to create a function that will identify whether the first letter input is upper or lower case then output the rest of the string in that same case(upper/lower).

For example, "Hi there" would become "HI THERE".

I'm not familiar with fgets. Once I run it I can input and press enter and the program doesn't run. I'm not getting any compiler errors. I believe I went wrong in the void shift function.

Also, I know gets is not recommended, is fgets similar? Or is it better to use scanf?

#include <stdio.h>
#include <ctype.h>
void shift (char *my_string); // Function declaration

int main()
{
  char inputstring[50];

  printf("Enter a string\n");
  char *my_string = inputstring;
  shift(my_string); // Function
}

void shift (char *my_string) // Function definition
{
  int i =0;
  char ch;

  for(i=0; i<50; i++)
    fgets(my_string, 50, stdin);

  while(my_string[i])
  {
    if(ch>='A' && ch<= 'Z') // When first char is uppercase
    {
      putchar (toupper(my_string[i]));
      i++;
    }
    else if (ch>='a' && ch <= 'z') // When first char is lowercase
    {
      putchar(tolower(my_string[i]));
      i++
    }
  }
  return;
}
Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
Taji
  • 55
  • 1
  • 6

3 Answers3

6

You don't need to call fgets() fifty times. It reads a line from stdin and writes it to my_string. It seems you only want to read one line, not fifty (and keep only the last one). The 50 is the maximum number of characters (minus one) that will be read and written to the buffer. This limit is to prevent buffer overflow. See fgets().

Try removing the for loop on the line before the fgets() call. Also, you don't need the my_string in main(). The corrected code:

#include <stdio.h>
#include <ctype.h>
void shift (char *my_string);//function declaration

int main()
{
  char inputstring[50];

  printf("Enter a string\n");
  shift(inputstring);
}

void shift (char *my_string) //function definition
{
  int i;
  char ch;

  if ( fgets(my_string, 50, stdin) == NULL )
    return;

  ch = my_string[0];
  for ( i=0; my_string[i]; i++ )
  {
    if(ch>='A' && ch<= 'Z') //when first char is uppercase
    {
        putchar (toupper(my_string[i]));
    }
    else if (ch>='a' && ch <= 'z')//when first char is lowercase
    {
        putchar(tolower(my_string[i]));
    }
  }
  return;
}

Edit: Added ch initialization, pointed out by @thurizas. Changed while loop to for loop. Added check to return value of fgets() as suggested by @JonathanLeffler. (See his comment about the buffer size.)

e0k
  • 6,961
  • 2
  • 23
  • 30
  • 2
    I can't see where `ch` is initialized in your code (same comment about the OP code). – thurizas Jan 22 '16 at 03:18
  • 1
    You should check the return status from `fgets()` before using the input string. Also, if you type a line of 140 characters before hitting return, the first call to `fgets(my_string, 50, stdin)` will return the first 49 characters (plus a null terminator) without any newline. The second call would return the next 49 characters without any newline. Only the third call, which would return 42 characters plus the newline plus the null, gets a newline. – Jonathan Leffler Jan 22 '16 at 03:34
  • I'm a fan of [getline()](http://linux.die.net/man/3/getline) using NULL as the first argument so it allocates the buffer for you, however much it needs to be. But you have to `free()` it yourself when you're finished. Dynamic memory seems beyond the level of the original question. – e0k Jan 22 '16 at 03:44
1
  • Here is another solution for your problem,

    #include <stdio.h>
    #include <ctype.h>
    void convertTo (char *string);
    
    int main()
    {
       char inputString[50];
    
       printf("Enter a string\n");
       convertTo(inputString);
    }
    
    void convertTo (char *string)
    {
       int i;
       char ch;
    
       gets(string);
    
       ch = string[0];
       for ( i=0; string[i]; i++ )
       {
          if(ch>='A' && ch<= 'Z')
          {
             if(string[i]>='a' && string[i]<= 'z')
                string[i] = string[i] - 32;
          }
          else if (ch>='a' && ch <= 'z')
          {
             if(string[i]>='A' && string[i]<= 'Z')
                string[i] = string[i] + 32;
          }
       }
       printf("%s\n", string);
       return;
    }
    
Sagar Patel
  • 864
  • 1
  • 11
  • 22
0

All ASCII characters are represented by 7-bits. (thus the term 7-bit ASCII) The only bitwise difference between lower-case and upper-case is that bit-5 (the sixth bit) is set for lowercase and cleared (unset) for uppercase. This allows a simple bitwise conversion between lowercase and uppercase (either by adding/subtracting 32 or by simply flipping bit-5 directly.)

      +-- lowercase bit
      |
a = 01100001    A = 01000001
b = 01100010    B = 01000010
c = 01100011    C = 01000011
...

This allows a simple test and conversion if the first character is upper-case:

#include <stdio.h>

enum { MAXC = 50 };

char *shift (char *my_string);

int main (void)
{
    char inputstring[MAXC] = {0};;

    printf ("\n Enter a string: ");
    if (shift (inputstring))
        printf (" my_string is  : %s\n", inputstring);

    return 0;
}

char *shift (char *my_string)
{
    char *p;

    if (!(p = fgets (my_string, MAXC, stdin))) return NULL;

    if (*p == '\n') return NULL;   /* Enter only pressed  */

    if ('A' <= *p && *p <= 'Z')    /* test for upper case */
        for (; *p; p++)            /* convert lower/upper */
            if ('a' <= *p && *p <= 'z') *p &= ~(1 << 5);

    return my_string;
}

Example Use

$ ./bin/case_1st_to_upper

 Enter a string: this is my string
 my_string is  : this is my string

$ ./bin/case_1st_to_upper

 Enter a string: This is my string
 my_string is  : THIS IS MY STRING
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85