Search code examples
ccalculatorargvargc

Calculator program in C using Command Line Arguments (argc, argv)


I've written a program to take input arguments from command line and create a basic calculator in C. Codebelow:

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


void CheckArgumentCount(int argc);
int CheckOperands(char *argv[]);
long Calculate(long nr1, long nr2, char operation);

int main(int argc, char *argv[])
{
    long nr1 = CheckOperands(&argv[1]);
    long nr2 = CheckOperands(&argv[3]);
    int result;

    CheckArgumentCount(argc);
    result = Calculate(nr1, nr2, *argv[2]);
    printf("Result: %d", result);

    return 0;
}


void CheckArgumentCount(int argc)
{
    if (argc > 3 || argc < 3)
    {
        puts("Wrong number of arguments to perform the calculation.\n");
    }
}

int CheckOperands(char *argv[])
{
        int i = 1;
        
        while (*argv[i] != '\0')
        {
            if (*argv[i] < '0' || *argv[i] > '9')
            {
                return *argv[i];
            }
            argv++;
        }
        return atoi(argv[i]);
}


long Calculate(long nr1, long nr2, char operation)
{
    long result = 0;

    switch (operation)
    {
        case '+':
            result = nr1 + nr2;
            break;
        case '-':
            result = nr1 - nr2;
            break;
        case '*':
            result = nr1 * nr2;
            break;
        case '/':
            if (nr2 == 0)
            {
                puts("Error! Divion by zero.");
            }
            else
            {
                result = nr1 / nr2;
            }
            break;
        default:
            puts("Operator invalid.");
            break;
    }
    return result;
}

Which compiles fine, as the compiler does not show any errors. However, I get this error on zsh terminal on run when I provide 3 arguments, e.g.:

zsh: segmentation fault ./calc 1 + 3

I assume it might have to do something with my CheckOperands function? Any advice will be appreciated.


Solution

  • You need to check the argument count before you use CheckOperands, or rather before you dereference any argc[n] with n > 1.

    You want this:

    int main(int argc, char* argv[])
    {
      if (!CheckArgumentCount(argc))
        exit(1);   // if argument count differenmt from 3 exit program
      ...
    

    and this:

    int CheckArgumentCount(int argc)
    {
      if (argc != 4)   // argc is one more because if the command 
                          invocation which is argv[0]
      {
        puts("Wrong number of arguments to perform the calculation.\n");
        return 0;
      }
    
      return 1;
    }
    

    And there are more errors in CheckOperands.

    Overall corrected code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    int CheckArgumentCount(int argc);
    int CheckOperands(char* operand);
    long Calculate(long nr1, long nr2, char operation);
    
    int main(int argc, char* argv[])
    {
      if (!CheckArgumentCount(argc))
        exit(1);
    
      long nr1 = CheckOperands(argv[1]);
      long nr2 = CheckOperands(argv[3]);
      int result;
    
    
      result = Calculate(nr1, nr2, argv[2][0]);
      printf("Result: %d", result);
    
      return 0;
    }
    
    
    int CheckArgumentCount(int argc)
    {
      if (argc != 4)
      {
        puts("Wrong number of arguments to perform the calculation.\n");
        return 0;
      }
    
      return 1;
    }
    
    int CheckOperands(char* operand)
    {
      int i = 0;
    
      while (operand[i] != '\0')
      {
        if (operand[i] < '0' || operand[i] > '9')
        {
          return operand[i];
        }
    
        i++;
      }
      return atoi(operand);
    }
    
    
    long Calculate(long nr1, long nr2, char operation)
    {
      long result = 0;
    
      switch (operation)
      {
      case '+':
        result = nr1 + nr2;
        break;
      case '-':
        result = nr1 - nr2;
        break;
      case '*':
        result = nr1 * nr2;
        break;
      case '/':
        if (nr2 == 0)
        {
          puts("Error! Divion by zero.");
        }
        else
        {
          result = nr1 / nr2;
        }
        break;
      default:
        puts("Operator invalid.");
        break;
      }
      return result;
    }