Home > Software design >  How can I code the program to accept not only uppercase but also lowercase first letter?
How can I code the program to accept not only uppercase but also lowercase first letter?

Time:11-19

For example, if I run the program and type in sin, it shows error. When I write down Sin, it's ok. For example, if I run the program and type in sin, it shows error. When I write down Sin, it's ok. For example, if I run the program and type in sin, it shows error. When I write down Sin, it's ok. For example, if I run the program and type in sin, it shows error. When I write down Sin, it's ok.

/*************************************************************
                            Pavel Kivilša
                               EKF-21
                        1 laboratorinis darbas
                               2021-11
*************************************************************/

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

enum Functions { Floor, Round, Ceil, Sin, Cos, Cosh, Exp, Tan, Tanh, Sinh, Log, Log10, Sqrt, Pow, Trunc, Help };
enum Functions function_name;

int main(int argc, char* argv[]) {
    float number, number2;
    char* function[16] = { "Floor", "Round", "Ceil", "Sin", "Cos", "Cosh", "Exp", "Tan", "Tanh", "Sinh", "Log", "Log10", "Sqrt", "Pow", "Trunc", "Help" };

    char name[6];
    printf("Enter a math function: ");
    scanf("%s", name);

    for (function_name = 0; function_name <= 15; function_name  ) {
        if (strcmp(function[function_name], name) == 0) {
            break;
        }
    }


    switch (function_name) {
    case Floor:
        printf("Enter the value of floor: ");
        scanf("%f", &number);
        printf("Floor of %.2f is equal to %.2f\n", number, floor(number));
        break;
    case Round:
        printf("Enter the value of round: ");
        scanf("%f", &number);
        printf("Round of %.2f is equal to %.2f\n", number, round(number));
        break;
    case Ceil:
        printf("Enter the value of ceil: ");
        scanf("%f", &number);
        printf("Ceil of %.2f is equal to %.2f\n", number, ceil(number));
        break;
    case Sin:
        printf("Enter the value of sin: ");
        scanf("%f", &number);
        printf("Sin of %.2f is equal to %.2f\n", number, sin(number));
        break;
    case Cos:
        printf("Enter the value of cos: ");
        scanf("%f", &number);
        printf("Cos of %.2f is equal to %.2f\n", number, cos(number));
        break;
    case Cosh:
        printf("Enter the value of cosh: ");
        scanf("%f", &number);
        printf("Cosh of %.2f is equal to %.2f\n", number, cosh(number));
        break;
    case Exp:
        printf("Enter the value of exp: ");
        scanf("%f", &number);
        printf("Exp of %.2f is equal to %.2f\n", number, exp(number));
        break;
    case Tan:
        printf("Enter the value of tan: ");
        scanf("%f", &number);
        printf("Tan of %.2f is equal to %.2f\n", number, tan(number));
        break;
    case Tanh:
        printf("Enter the value of tanh: ");
        scanf("%f", &number);
        printf("Tanh of %.2f is equal to %.2f\n", number, tanh(number));
        break;
    case Sinh:
        printf("Enter the value of sinh: ");
        scanf("%f", &number);
        printf("Sinh of %.2f is equal to %.2f\n", number, sinh(number));
        break;
    case Log:
        printf("Enter the value of log: ");
        scanf("%f", &number);
        printf("Log of %.2f is equal to %.2f\n", number, log(number));
        break;
    case Log10:
        printf("Enter the value of log10: ");
        scanf("%f", &number);
        printf("Log10 of %.2f is equal to %.2f\n", number, log10(number));
        break;
    case Sqrt:
        printf("Enter the value of sqrt: ");
        scanf("%f", &number);
        printf("Sqrt of %.2f is equal to %.2f\n", number, sqrt(number));
        break;
    case Pow:
        printf("Enter the value of pow: ");
        scanf("%f", &number);
        printf("Enter the second value of pow: ");
        scanf("%f", &number2);
        printf("%.2f to the power of %.2f is equal to %.2f\n", number, number2, pow(number, number2));
        break;
    case Trunc:
        printf("Enter the value of trunc: ");
        scanf("%f", &number);
        printf("Trunc of %.2f is equal to %.2f\n", number, trunc(number));
        break;
    case Help:
        printf("The following functions can be used: Floor, Round, Ceil, Sin, Cos, Cosh, Exp, Tan, Tanh, Sinh, Log, Log10, Sqrt, Pow, Trunc.\n");
        break;
    default:
        printf("Function not found, try again by typing in Help.\n");
        break;
    }
    return 0;
}

CodePudding user response:

You are assigning to function_name

for (function_name = 0; function_name <= 15; function_name  ) {

Which is not allowed in the C compiler you are using.

error C2440: '=': cannot convert from 'int' to 'Functions' note: Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)

error C2676: binary ' ': 'Functions' does not define this operator or a conversion to a type acceptable to the predefined operator

You could turn it into a C compiler by using the /TC switch and then the above will work.

If you wish to continue using C , you need to cast. Here's how you'd do it with C-style casts:

for (function_name = (Functions)0; function_name <= 15;
     function_name = (Functions)((int)function_name   1))
{
    if (strcmp(function[function_name], name) == 0) {
        break;
    }
}

Using C style casts:

for (function_name = static_cast<Functions>(0); function_name <= 15; 
     function_name = static_cast<Functions>(static_cast<int>(function_name)   1))
{
    if (strcmp(function[function_name], name) == 0) {
        break;
    }
}

Other notes:

You are missing #include <string.h> for strcmp and scanf("%s", &name); should be scanf("%s", name); or preferably scanf("%5s", name); to not risk writing out of bounds if the user enters more than 5 characters.


The below will perhaps not be usable in the light of your current assignment but it may provide some food for thought, if not now, then perhaps later on. I'll show how you could make the program a little more generic so that you do not have to repeat the same, or similar, code in so many places.

Adding a new math function that takes one argument will require as little code as writing
{"Name", input_1, cast_1(name)} and adding a function that takes two arguments is just as easy,
{"Name", input_2, cast_2(name)} and they will then be added to the Help and to the list of math functions you can use.

You'll need these headers:

#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>    // tolower
#include <math.h>
#include <stdbool.h>  // true/false
#include <stdio.h>
#include <stdlib.h>

The below struct is what the rest of the program is revolving around.

// The definition of a function:
typedef struct Function {
    const char* name;                        // the name of the function
    double (*input)(const struct Function*); // a pointer to an input function
    void (*math_func)(void);                 // a type erased function pointer
} Function;
  • name is a pointer to a string describing one function, like "Floor".
  • input is a pointer to a function that takes one argument, a pointer to a Function object and returns a double.
  • math_func is a function pointer to one of the math functions - but with no usable type information since the math functions have different signatures. Some take one argument and some take two arguments. We will need to cast it to the proper function type before using it. This cast will be done by the function pointed out by input.

Next, define the two types of input functions we need. One reads one argument from the user and the other one reads two. They perform the above mentioned cast of math_func into the proper function type for the math function and then calls the math function.

// A function taking one parameter as input
static double input_1(const Function* f) {
    printf("Enter the argument to %s: ", f->name);
    double value;
    if(scanf(" %lf", &value) == 1) {
        // cast to the proper function pointer type
        double (*mfunc)(double) = (double (*)(double))f->math_func;
        return mfunc(value); // and call the math function
    }
    return (double)NAN; // invalid user input
}
// A function taking two parameters as input
static double input_2(const Function* f) {
    printf("Enter the first argument to %s: ", f->name);
    double value1;
    if(scanf(" %lf", &value1) == 1) {
        printf("Enter the second argument to %s: ", f->name);
        double value2;
        if(scanf(" %lf", &value2) == 1) {
            // cast to the proper function pointer type
            double (*mfunc)(double, double) = (double (*)(double, double))f->math_func;
            return mfunc(value1, value2); // and call the math function
        }
    }
    return (double)NAN; // invalid user input
}

I couldn't find a standard function to do a case insensitive equality check of strings, so I added this:

// case insensitive equality check of strings
static bool str_equal_i(const char* str_a, const char* str_b) {
    // cast to unsigned for all ctype.h functions, like tolower:
    const unsigned char* a = (const unsigned char*)str_a;
    const unsigned char* b = (const unsigned char*)str_b;
    for(; *a || *b;   a,   b) {
        if(tolower(*a) != tolower(*b)) return false;
    }
    return true;
}

Next we need a function that takes a function name as input and searches through a list of Function objects to find one with a matching name. If one is found, it'll call it and return true (for success) or false if it fails to find a matching function.

// Search for a matching math function and perform the calculation
static bool perform(const char* name, const Function* functions, size_t FCOUNT) {
    for(unsigned f = 0; f < FCOUNT;   f) {
        if(str_equal_i(functions[f].name, name)) {
            // A function with that name was found - call the input function:
            double res = functions[f].input(&functions[f]);
            if(isnan(res)) {
                puts("Error: not a number I'm afraid");
            } else {
                printf("Result: %f\n", res);
            }
            return true;
        }
    }
    return false;
}

Now it becomes tricky. Below are two helper functions that are used to cast from a function pointer to one of the real math functions to the void(*)(void) that we store in the Function objects. The syntax is ... horrible and not even https://cdecl.org/ which is usually superb when it comes to translating C declarations to "pure" English manages to decode it, so I'll try myself:

  • The first function, cast_1, is a function that takes a pointer to a function taking one double argument, returning double. cast_1 itself returns a void(*)(void).
  • The second function, cast_2, is a function that takes a pointer to a function taking two double arguments, returning double. cast_2 itself returns a void(*)(void)
//-------------------------------------------------------------------------
// In C   some of the math functions are overloaded so you need to figure
// out which overload to use.
// These functions combines resolving to the correct overload (for C  ) and
// the cast from any function pointer to a generic function pointer,
// void(*)(void), that we store in the Function object.
static void (*cast_1(double (*func)(double)))(void) {
    return (void (*)(void))func;
}

static void (*cast_2(double (*func)(double, double)))(void) {
    return (void (*)(void))func;
}

With all this, we can define an array of Function objects and a small loop to get input from the user.

int main() {
    // The table of functions
    const Function functions[] = {
        {"Floor", input_1, cast_1(floor)}, {"Round", input_1, cast_1(round)},
        {"Ceil", input_1, cast_1(ceil)},   {"Sin", input_1, cast_1(sin)},
        {"Cos", input_1, cast_1(cos)},     {"Cosh", input_1, cast_1(cosh)},
        {"Exp", input_1, cast_1(exp)},     {"Tan", input_1, cast_1(tan)},
        {"Tanh", input_1, cast_1(tanh)},   {"Sinh", input_1, cast_1(sinh)},
        {"Log", input_1, cast_1(log)},     {"Log10", input_1, cast_1(log10)},
        {"Sqrt", input_1, cast_1(sqrt)},   {"Trunc", input_1, cast_1(trunc)},
        {"Pow", input_2, cast_2(pow)}, // note how Pow is different
    };

    const size_t FCOUNT = sizeof functions / sizeof *functions;
    //-------------------------------------------------------------------------
    char name[6];
    while(true) {
        printf("Enter a math function: ");
        if(scanf(" %5s", name) != 1) {
            if(feof(stdin)) break;
            continue;
        }
        if(!perform(name, functions, FCOUNT)) {
            // Not a math function, check if it was Help:
            if(str_equal_i("Help", name)) {
                printf("The following functions can be used: ");
                for(unsigned f = 0; f < FCOUNT - 1;   f) {
                    printf("%s, ", functions[f].name);
                    if(f % 12 == 4) putchar('\n');
                }
                puts(functions[FCOUNT - 1].name);
            } else {
                puts("Function not found, try again by typing in Help.");
            }
        }
    }
    puts("\nBye bye...");
}

Full code

CodePudding user response:

To perform a case-insensitive comparison on MSVC, use stricmp:

    if (stricmp(function[function_name], name) == 0) {
        break;
    }

The equivalent on Linux is strcasecmp.

  •  Tags:  
  • c
  • Related