Uppercase/lowercase conversion skipping some letters

118 views Asked by At

This is a program for converting lower case letters in a string to upper case and vice versa in C language.

In this code I am trying to take input string str from user using fgets() function but it is not working. I even tried using gets() but it is also not working. It skips taking input and execute the program. What can I do? I tried using for loop but it is not terminating on new line. Can I do it with any function or using any loop?

#include <stdio.h>
#include <string.h>

char lower(char *str);
char upper(char *str);

int main() {
    
    char *newstr;
    char ans;
    printf("Enter U for Lower case -> Upper case\nEnter L for Upper case -> Lower case:\n");
    scanf("%c", &ans);

    char str[100];
    printf("Enter the string:\n");
    fgets(str, 100, stdin);

    if (ans == 'U' || ans == 'u') {
        // newstr = upper(str);
        upper(str);
    }
    else if(ans == 'L' || ans == 'l') {
        // newstr = lower(str);
        lower(str);
    }
    else {
        printf("Try entering a valid input.");
    }
    
    // printf("%s", newstr);
    printf("%s", str);
    
    return 0;
}

char lower(char *str) {
    for (int i = 0; i < (strlen(str)); i++) {
        char c[] = { str[i], '\0' };
        if (strstr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", c)) {
            str[i] = str[i] - 32;
        }
    }
    // return str;
}

char upper(char *str) {
    for (int i = 0; i < (strlen(str)); i++) {
        char c[] = { str[i], '\0' };
        if (strstr("abcdefghijklmnopqrstuvwxyz", c)) {
            str[i] = str[i] + 32;
        }
    }
    // return str;
}
4

There are 4 answers

1
kayasthasky On

fgets() - Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.

Answer: the scanf() statement is leaving a newline character in the input buffer, which is causing fgets() to take it as an input and end the string.

You can modify your code and move the fgets() logic before the scanf statement to make it work. Additionally, if conditions can be modified a little bit to make it better using ASCII values. Below is an example of working code:

#include <stdio.h>
#include <string.h>
#define MAX 100
void lower(char *str);
void upper(char *str);
int main() {
    char str[MAX];
    printf("Enter the string:\n");
    fgets(str, MAX, stdin);
    char ans;
    printf("Enter U for Lower case -> Upper case\nEnter L for Upper case -> Lower case:\n");
    scanf("%c", &ans);
    if (ans == 'U' || ans == 'u') {
        upper(str);
    } else if (ans == 'L' || ans == 'l') {
        lower(str);
    } else {
        printf("Try entering a valid input.");
    }
    printf("%s", str);
    return 0;
}
void lower(char *str) {
    for (int i = 0; i < (strlen(str)); i++) {
        //A = 65, Z = 90
        if (str[i] >= 65 && str[i] <= 90) {
            str[i] = str[i] + 32;
        }
    }
}
void upper(char *str) {
    for (int i = 0; i < (strlen(str)); i++) {
        //a = 97, z = 122
        if (str[i] >= 97 && str[i] <= 122) {
            str[i] = str[i] - 32;
        }
    }
}
0
gulpr On
  1. If you do not want to use toupper and tolower you should use conversion table. It may also simplify the code (only one function needed)
  2. scanf leaves new line in the buffer, better read the string. Then you can sscanf the string.
  3. You function should return char *
  4. strchr suits better your needs and it is much faster.
  5. fgetsleaves ''\n`` in the string - it should be removed
#include <stdio.h>
#include <string.h>

char *convert(char *str, int direction);


int main(void){
    
    char *newstr;
    int ans;
    char str[100] = "";

    printf("Enter 1 for Lower case -> Upper case\nAnything else for Upper case -> Lower case:\n");
    fgets(str, 100, stdin);

    if(sscanf(str, "%d", &ans) != 1) { /* handle error */ }

    printf("\nEnter the string:\n");
    fgets(str, 100, stdin);
    for(char *wrk = str; *wrk; wrk++)
       if(*wrk == '\n') *wrk = 0;

    printf("\"%s\"\n", convert(str, ans != 1));
}

static char *conversionArray[2] = 
{
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    "abcdefghijklmnopqrstuvwxyz"
};


char *convert(char *str, int direction)
{
    char *wrk = str, *found;
    while(*wrk)
    {
        found = strchr(conversionArray[direction], *wrk);
        if(found) *wrk = conversionArray[!direction][found - conversionArray[direction]];
        wrk++;
    }
    return str;
}
0
chqrlie On

There are multiple problems:

  • mixing scanf() and fgets() leads to surprises as scanf() leaves the newline typed by the user pending in the input stream and fgets() reads it and returns immediately with an empty line.

  • your test for upper and lower case is very cumbersome. You should use isupper, islower and/or tolower and toupper from <ctype.h> instead of hardcoding a difference of 32 between cases that is specific to ASCII.

  • lower and upper should have a return type of char * so you can return the string pointer.

Here is a modified version:

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

char *lower(char *str);
char *upper(char *str);

int main(void) {
    char str[100];
    char *newstr;
    char ans;

    printf("Enter U for Lower case -> Upper case\n"
           "Enter L for Upper case -> Lower case:\n");
    if (!fgets(str, sizeof str, stdin))
        return 1;

    ans = (char)toupper((unsigned char)*str);
    if (ans != 'U' && ans != 'L') {
        printf("Try entering a valid input.\n");
        return 1;
    }

    printf("Enter the string:\n");
    if (!fgets(str, sizeof str, stdin))
        return 1;

    if (ans == 'U') {
        newstr = upper(str);
    } else {
        newstr = lower(str);
    }
    printf("%s", newstr);
    return 0;
}

char *lower(char *str) {
    for (size_t i = 0; str[i] != '\0'; i++) {
        str[i] = (char)tolower((unsigned char)str[i]);
    }
    return str;
}

char *upper(char *str) {
    for (size_t i = 0; str[i] != '\0'; i++) {
        str[i] = (char)toupper((unsigned char)str[i]);
    }
    return str;
}
0
Webstep Technologies On
#include <stdio.h>
#include <string.h>

void lower(char *str);
void upper(char *str);

int main() {
    
    char ans;
    printf("Enter U for Lower case -> Upper case\nEnter L for Upper case -> Lower case:\n");
    scanf(" %c", &ans);  
    char str[100];
    printf("Enter the string:\n");
    getchar();  // Consume the newline character left by the previous scanf
    fgets(str, sizeof(str), stdin);
    
    if (ans == 'U' || ans == 'u') {
        upper(str);
    }
    else if(ans == 'L' || ans == 'l') {
        lower(str);
    }
    else {
        printf("Try entering a valid input.");
    }
    
    printf("%s", str);
    
    return 0;
}

void lower(char *str) {
    for (int i = 0; i < strlen(str); i++) {
        if (str[i] >= 'A' && str[i] <= 'Z') {
            str[i] += 32;
        }
    }
}

void upper(char *str) {
    for (int i = 0; i < strlen(str); i++) {
        if (str[i] >= 'a' && str[i] <= 'z') {
            str[i] -= 32;
        }
    }
}