Home > Back-end >  Need to write in C a logical statement calculator that takes two inputs (either a number or a letter
Need to write in C a logical statement calculator that takes two inputs (either a number or a letter

Time:12-04

The calculator should take inputs like (23>3) or (a>9) and prints if it's true or false. My main difficulty is doing it for letters. I only managed to do it for numbers. I don't know how to define the scanf to accept a letter. When a letter is compared to a number, I need to compare the letters' ASCII values. So, if I do a>9 it actually checks if 97>9 (97 is the ASCII value of 'a').

#include <stdio.h>

int main() {
    int num1, num2;
    char operator;
    printf("Please write your logical statement:");
    scanf("%d %c %d", &num1, &operator, &num2);
    if (operator=='>')
    {
        if (num1>num2)
        {
            printf("True");
        }
        else
        {
            printf("false");
        }
    }
    else if (operator =='<')
    {
        if (num1<num2)
        {
            printf("True");
        }
        else
        {
            printf("false");
        }
    }
    else if (operator == '=')
    {
        if (num1==num2)
        {
            printf("True");
        }
        else
        {
            printf("False");
        }
    }
}

How do I modify it to also accept characters?

CodePudding user response:

There are many ways you can do this. A fairly straightforward way is to read your two operands as strings and then have a function that either converts those strings into their component numbers or returns the (ASCII) value of the (single) character.

Here is such a function and a modified version of your main to use it:

#include <stdio.h>
#include <string.h> // For strlen
#include <ctype.h>  // For isalpha

int GetValue(char* input, int* value)
{
    if (sscanf(input, "%d", value) == 1) { // Successfully read a number
        return 1;
    }
    else if (strlen(input) == 1 && isalpha(input[0])) { // For single letters ...
        *value = input[0];
        return 1;
    }
    return 0; // Return zero to indicate failure
}

int main(void)
{
    char in1[10], in2[10]; // Buffers for input operands (may like to make bigger)
    char op;
    int num1, num2;

    printf("Please write your logical statement:");
    // See notes below for an explanation of the format specifiers...
    if (scanf("%9[a-zA-Z0-9] %c %9[a-zA-Z0-9]", in1, &op, in2) != 3) {
        printf("Invalid input!\n");
        return 1;
    }
    if (!GetValue(in1, &num1)) {
        printf("Invalid operand 1\n");
        return 1;
    }
    if (!GetValue(in2, &num2)) {
        printf("Invalid operand 2\n");
        return 1;
    }

    if (op == '>') {
        printf((num1 > num2) ? "True" : "False");
    }
    else if (op =='<') {
        printf((num1 < num2) ? "True" : "False");
    }
    else if (op == '=') {
        printf((num1 == num2) ? "True" : "False");
    }
    else {
        printf("unrecognized operator");
    }
    return 0;
}

A short explanation of the %9s[a-zA-Z0-9] format specifier (the "set" format described on this cppreference page): This allows any characters from the three ranges ('a' thru 'z', 'A' thru 'Z' and '0' thru '9') as input to the corresponding char[] arguments. Thus, the input (to the first field) will stop when one of your operators is seen. The '9' immediately after the '%' limits input to the two fields to 9 characters, thus preventing buffer overflow; if you change the size of your in1 and in2 arrays, then change that value accordingly (it should be no greater than one less than the size of the array, to allow for the nul-terminator).

Note that I have also added some (possible) improvements:

  1. Always check the value returned by scanf, to make sure it succeeded
  2. You can use the "conditional (ternary) operator" to make your output code (printf blocks) rather more succinct.

CodePudding user response:

One thing that you could do is to use

scanf( "%c %c %c", &digit1, &operator, &digit2 );

but this would only work if the user enters single digits, not a multi-digit number such as 23.

Instead of using the function scanf, it is generally recommended to always read an entire line of input at once, including the newline character. The function scanf can do nasty things, such as leaving the newline character on the input stream, which can cause trouble.

In order to read a whole line of input at once, I recommend using the function fgets.

I recommend that you treat all characters up to, but not including the operator character, as a separate string. You can then determine whether this string is a valid integer by using the function strtol. If it is not, you can then check the length of the string, to verify that it is only a single character. If it represents neither, then your program should print an error message and exit.

Here is an example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

//This function will convert a string to a number. If the
//string represents an actual number, it will return this
//number. If the string contains a single letter, it will
//return the ASCII code of this letter. Otherwise, the
//function will exit the program with an error message.
long convert_string_to_number( const char *str )
{
    long num;
    char *p;

    //attempt to convert the string into a number
    num = strtol( str, &p, 10 );

    if ( p == str )
    {
        //failed to convert string to number, so we must
        //now determine whether it is a single letter
        if ( strlen(str) == 1 && isalpha( (unsigned char)str[0] ) )
        {
            //return the ASCII code of the character
            return str[0];
        }
        else
        {
            printf( "Error: Operand must be either a number or a single letter!\n" );
            exit( EXIT_FAILURE );
        }
    }

    //verify that all remaining characters are whitespace
    //characters, so that input such as "6abc<23" gets
    //rejected
    for ( ; *p != '\0'; p   )
    {
        if ( !isspace( (unsigned char)*p ) )
        {
            printf( "Error: Unexpected character found!\n" );
            exit( EXIT_FAILURE );
        }
    }

    return num;
}

bool perform_operation( long num1, char operator, long num2 )
{
    switch ( operator )
    {
        case '<':
            return num1 < num2;
        case '>':
            return num1 > num2;
        case '=':
            return num1 == num2;
        default:
            printf( "Error: Invalid operator!\n" );
            exit( EXIT_FAILURE );
    }
}

int main( void )
{
    char line[200];
    char *p;
    char operator;
    long num1, num2;

    //attempt to read one line of input
    if ( fgets( line, sizeof line, stdin ) == NULL )
    {
        printf( "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    //attempt to find operator
    p = strpbrk( line, "<>=" );

    //print error message and abort if no operator found
    if ( p == NULL )
    {
        printf( "Error: No valid operator found!\n" );
        exit( EXIT_FAILURE );
    }

    //remember the operator
    operator = *p;

    //overwrite the operator with a null character, to
    //separate the input string into two strings
    *p = '\0';

    //make the pointer p point to the start of the second
    //string
    p  ;

    //attempt to convert both strings to a number
    num1 = convert_string_to_number( line );
    num2 = convert_string_to_number( p );

    //perform the actual operation and print the result
    if ( perform_operation( num1, operator, num2 ) )
    {
        printf( "True" );
    }
    else
    {
        printf( "False" );
    }
}

This program has the following behavior:

abc
Error: No valid operator found!
=
Error: Operand must be either a number or a single letter!
6abc<23
Error: Unexpected character found!
6<23
True
a=98
False
a=97
True
  • Related