0

I am working on building a calculator in C, and have encountered a problem regarding scanf for characters. I have defined a "string" called operationValue, but when I try to do the scanf function (the one that I have a comment right next to it), it immediately prints out an invalid character instead of the operation I typed in. I needed the string instead of just a character because I have the other operation for powers and roots, but even they don't work when I type them in. When I complete the code it prints "Not Valid Operation."

Sorry if this is not what is conventional in stack overflow, but this is the first time I'm on here. If the pieces of code are too long or something, please help me edit it so I can learn not to do that next time.

#include <stdio.h>

void theOperation(double num1, char operationValue, double num2)
{
    if(operationValue == "+")
    {
        printf("%lf\n", num1 + num2);
    } else if(operationValue == "-")
    {
        printf("%lf\n", num1 - num2);

    } else if(operationValue == "*")
    {
        printf("%lf\n", num1 * num2);

    } else if(operationValue == "/")
    {
        printf("%lf\n", num1 / num2);
    } else if(operationValue == "pow")
    {
        printf("%lf\n", pow(num1, num2));
    } else if(operationValue == "root")
    {
        printf("%lf\n", pow(num1, (1/num2)));
    } else
    {
        printf("Not valid operation");
    }
}


int main()
{
    double num1, num2;
    char operationValue[10];

    printf("This is a calculator.\n");
    printf("Enter first number: ");
    scanf("%lf", &num1);
    printf("%lf\n", num1);

    printf("Enter operation: ");
    scanf(" %s", &operationValue);
    printf("%c\n", operationValue);     // This line fails when I type in any operation I define: '+', '-', '*', '/' 'pow' 'root'

    printf("Enter second number: ");
    scanf("%lf", &num2);
    printf("%lf\n", num2);

    theOperation(num1, operationValue, num2);

    return 0;
}
KingLogic
  • 140
  • 13
  • It's time to learn about how to use `switch`. – tadman Jul 04 '20 at 18:11
  • 1
    Are you sure the function definition is the same way you call it? `int theOperation(num1, operationValue, num2)`. It has no types. – Weather Vane Jul 04 '20 at 18:12
  • @tadman I have tried switch, but it doesn't work and gave me the error message "error: case label does not reduce to an integer constant." This link https://stackoverflow.com/questions/14069737/switch-case-error-case-label-does-not-reduce-to-an-integer-constant told me to use if/else statements. – KingLogic Jul 04 '20 at 18:12
  • You can't `switch` on strings, you can only do it on `char`, like in your second version. Note that your second version is incomplete, as arguments *must* have types. – tadman Jul 04 '20 at 18:14
  • It's worth noting that `operationValue == "+"` is basically junk C code, it won't ever succeed, as that *compares raw pointers*, not the C strings they point to. You need to use `strcmp` to compare strings in C. – tadman Jul 04 '20 at 18:14
  • `if(operationValue == "+") ` looks like a problem. The function definition is devoid of types, but you cannot compare either a string or a character like that. – Weather Vane Jul 04 '20 at 18:14
  • @tadman The first version is what I really want. The second version is just a failed attempt at trying to debug it. – KingLogic Jul 04 '20 at 18:15
  • Code like `int theOperation(num1, operationValue, num2)` is missing type information. If it does, your compiler isn't checking properly. At best it will presume all arguments are of type `int`, which they aren't. – tadman Jul 04 '20 at 18:16
  • 1
    25 warnings on 2 errors. Start with the mentioned issues like e.g. `"+"` => `'+' `. – reichhart Jul 04 '20 at 18:16
  • Even before I called the function, the printf gave me a weird character. – KingLogic Jul 04 '20 at 18:16
  • I have edited my code. I now find that the other stuff could be seen as irrelevant to my problem. – KingLogic Jul 04 '20 at 18:18
  • Compiler warnings are only irrelevant if you know exactly why they were caused and why they can be tolerated. Ideally, aim for no warnings, because if you tolerate "irrelevelant" warnings it makes the worse ones hard to spot. – Weather Vane Jul 04 '20 at 18:21
  • 1
    use `scanf("%s", operationValue)` if you want to read multiple characters. You then print it with `printf("%s", operationValue)` – Andy Jul 04 '20 at 18:22
  • I kept the string for the operation and used `strcmp()`. See answer below. – reichhart Jul 04 '20 at 18:42
  • 1
    @Andy `scanf("%s", operationValue)` is considered as bad because it may cause buffer overrun. Maximum length to read should be specified. – MikeCAT Jul 04 '20 at 18:42
  • Use `%9s` here due to `char[10]`. – reichhart Jul 04 '20 at 18:45
  • I updated my answer by using `switch()` _and_ `strcmp()` by first checking the first char of operation. – reichhart Jul 04 '20 at 19:17

5 Answers5

2

The code has several defects:

  1. The function signature given:

    int theOperation(num1, operationValue, num2)
    

    is incorrect. You must define the datatype alongside the identifier.

  2. The function returns int but nowhere used.

  3. A variable char[10] passed into a function which accepts char, which will obviously give unexpected results.

  4. If you want to use mathematical functions like pow(), sqrt(), floor(), etc., you must define the header file math.h. They're not available in stdio.h (that only contains I/O operation functions and subroutines).


Code redefined:

#include <stdio.h>

// return type set to: void, datatypes defined for function parameters
void theOperation(double num1, char operationValue, double num2)
{
    double result = 0;

    // calculating the results based on operations
    switch (operationValue) {
        case '+': result = num1 + num2; break;
        case '-': result = num1 - num2; break;
        case '*': result = num1 * num2; break;
        case '/': result = num1 / num2; break;

        default:
            printf("No such operation found.\n");
            break;
    }

    printf("Result: %lf\n", result);
}


int main(void)
{
    double num1, num2;
    char operationValue;

    printf("This is a calculator.\n");
    printf("Enter first and second number: ");
    scanf("%lf %lf", &num1, &num2);
    printf("%lf %lf\n", num1, num2);

    printf("Enter operation: ");
    scanf(" %c", &operationValue);
    printf("%c\n", operationValue);

    // the operation execution
    theOperation(num1, operationValue, num2);

    return 0;
}

The explanation is pretty much simple.

The scanf() takes the necessary data from the user and then passes the parameters to the function theOperation() with their appropriate arguments. Thereafter, the switch statements tries to match which expression is given in case statements are identical to the operationValue.

When it does finds one, it simply evaluates the expression and prints the result.

Note: If you just want to compare single letters like +, -, *, /, etc. then you still don't need to use character array to compare them using strcmp() or anything.


It gives the following output:

This is a calculator.
Enter first and second number: 10 50
10.000000 50.000000
Enter operation: -
-
Result: -40.000000
Rohan Bari
  • 7,482
  • 3
  • 14
  • 34
2

Use the "%s" for reading and printing the operator:

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

void theOperation(double num1, char* operationValue, double num2)
{
    if(strcmp(operationValue, "+") == 0)
    {
        printf("%lf\n", num1 + num2);
    } else if(strcmp(operationValue, "-") == 0)
    {
        printf("%lf\n", num1 - num2);

    } else if(strcmp(operationValue,"*") == 0)
    {
        printf("%lf\n", num1 * num2);

    } else if(strcmp(operationValue,"/") == 0)
    {
        printf("%lf\n", num1 / num2);
    } else if(strcmp(operationValue,"pow") == 0)
    {
        printf("%lf\n", pow(num1, num2));
    } else if(strcmp(operationValue, "root") == 0)
    {
        printf("%lf\n", pow(num1, (1/num2)));
    } else
    {
        printf("Not valid operation");
    }
}


int main()
{
    double num1, num2;
    char operationValue[10];

    printf("This is a calculator.\n");
    printf("Enter first number: ");
    scanf("%lf", &num1);
    printf("%lf\n", num1);

    printf("Enter operation: ");
    scanf(" %9s", &operationValue);
    printf("%c\n", operationValue);

    printf("Enter second number: ");
    scanf("%lf", &num2);
    printf("%lf\n", num2);

    theOperation(num1, operationValue, num2);

    return 0;
}

Scanf() docs: https://www.tutorialspoint.com/c_standard_library/c_function_scanf.htm

-- EDIT --

I have updated the code to a working one.

I also updated the scanf() for reading the operator like @M. Nejat Aydin commented for prevent buffer overrun

C. Celora
  • 429
  • 1
  • 3
  • 12
1
  • %c in scanf() is for reading one character. You should use %(max length)s to read strings (that don't contain whitespace characters). The (max length) should be buffer size minus one (for terminating null-character). Also note that %(max length)s will take char*, so you shouldn't put & before arrays.
  • %c in printf() is for printing one character. You should use %s to print strings.
#include <stdio.h>

int main()
{
    double num1, num2;
    char operationValue[10];
    
    printf("This is a calculator.\n");
    printf("Enter first number: ");
    scanf("%lf", &num1);
    printf("%lf\n", num1);
    
    printf("Enter operation: ");
    scanf(" %9s", operationValue);
    printf("%s\n", operationValue);
    
    printf("Enter second number: ");
    scanf("%lf", &num2);
    printf("%lf\n", num2);


    return 0;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
0

It wasn't too hard to fix your code by adding types and ensuring the arguments get passed through correctly:

#include <stdio.h>
#include <stdlib.h>

void theOperation(double num1, char operationValue, double num2)
{
    switch (operationValue) {
        case '+':
            printf("%lf\n", num1 + num2);
            break;
        case '-':
            printf("%lf\n", num1 - num2);
            break;
        case '/':
            printf("%lf\n", num1 / num2);
            break;
        case '*':
            printf("%lf\n", num1 * num2);
            break;
        default:
            printf("Not valid operation");
    }
}

int main()
{
    double num1, num2;
    char operationValue;

    printf("This is a calculator.\n");
    printf("Enter first number: ");
    scanf("%lf", &num1);
    printf("%lf\n", num1);

    printf("Enter operation: ");
    scanf(" %c", &operationValue);
    printf("%c\n", operationValue);

    printf("Enter second number: ");
    scanf("%lf", &num2);
    printf("%lf\n", num2);

    theOperation(num1, operationValue, num2);

    return 0;
}
tadman
  • 208,517
  • 23
  • 234
  • 262
  • I realize that the switch works for just these four basic operations. But when I put in the more complex operations like pow(num1, num2), it fails. – KingLogic Jul 04 '20 at 18:21
  • Please, don't say "fails", tell us *exactly* what the problem is, especially in terms of compiler errors. – tadman Jul 04 '20 at 18:36
  • 1
    Adding pow should be as easy as `case '^':` and then `pow()` but you *must* `#include `. – tadman Jul 04 '20 at 18:37
0

I made fixes in function parameters, strings vs. chars and wrong scanf format chars, taking all your operations including "pow" and "root" and combining it with switch():

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

void theOperation(double num1, const char *operationValue, double num2)
{
  switch(*operationValue) {
    case '+': printf("%lf\n", num1 + num2); break;
    case '-': printf("%lf\n", num1 - num2); break;
    case '*': printf("%lf\n", num1 * num2); break;
    case '/': printf("%lf\n", num1 / num2); break;
    default: {
      if(!strcmp(operationValue, "pow")) {
        printf("%lf\n", pow(num1, num2));
      } else if(!strcmp(operationValue, "root")) {
        printf("%lf\n", pow(num1, (1/num2)));
      } else printf("Not valid operation\n");
      break;
    }
  }
}

int main()
{
  double num1, num2;
  char operationValue[10];
  
  printf("This is a calculator.\n");
  printf("Enter first number: ");
  scanf("%lf", &num1);
  printf("%lf\n", num1);
  
  printf("Enter operation: ");
  scanf("%9s", operationValue);
  printf("operation entered: %s\n", operationValue);
  
  printf("Enter second number: ");
  scanf("%lf", &num2);
  printf("%lf\n", num2);

  theOperation(num1, operationValue, num2);

  return 0;
}

Output example with "power":

$ gcc -Wall -o calc calc.c ;./calc 
This is a calculator.
Enter first number: 2
2.000000
Enter operation: pow
operation entered: pow
Enter second number: 3
3.000000
8.000000

This is an important line:

scanf("%9s", operationValue);

(Read a string with up to 9 chars.)

reichhart
  • 813
  • 7
  • 13