1

I am writing a program in C for a basic calculator. I am trying to do this using what I have learned so far: printf() and scanf() functions. I am passing arguments into my program through the command line. I am assuming three arguments will be passed at a time which includes: first int, an operator, and the second int. I want to check if the second arg passed is an operator and then check if it's +,-,*... so on. Here is what I came up with:

int main(int argc, char **argv) {
        scanf("%d %c %d", &a, &oper, &b);
        if (oper != 43) {
                  printf("Error: Operator is not a +");
                  return(1);
        }
}

So obviously, I have omitted a lot of the code and kept the relevant part. Here I am just checking if the oper is a +. The ASCII key is 43 so I thought this would work but no luck! Any ideas? (I would like to see if I can do this just with printf and scanf if possible)

EDIT: For example if 12 b 13 was entered, it should return the error above. Same goes for '10 +a 10' or '10 ++ 10'.

romainl
  • 186,200
  • 21
  • 280
  • 313
markovv.sim
  • 161
  • 1
  • 8
  • `char ++argv`? You seem to have missed something in your books or tutorials. Either that or you need to create a proper [mcve] to show us. – Some programmer dude Nov 02 '20 at 04:50
  • And don't use [*magic numbers*](https://en.m.wikipedia.org/wiki/Magic_number_(programming)). If by `43` you mean the ASCII code for `'+' `, use the actual character instead. – Some programmer dude Nov 02 '20 at 04:53
  • Typo!! Just fixed it. – markovv.sim Nov 02 '20 at 04:54
  • The `scanf` function reads only from standard input. If you want input as command-line arguments, then you need to check the strings in `argv` (after *first* checking `argc`). There are really a lot of tutorials online on how to use command-line arguments. What have you searched for? What have you found? What do they tell you? – Some programmer dude Nov 02 '20 at 04:58
  • 1
    If you are passing command line arguments to your program, you don't need `scanf()`. `argc` tells you how many arguments were on the command line and `argv[]` holds those arguments as nul-terminated strings. (e.g. `argv[1]` is 1st argument, `argv[2]` the second, ...) note, `argv[0]` is always the program name being run. You would check `if (argc < 3) { /* error: too few args */ }`. You can use `sscanf (argv[1], "%d", &a)` to convert the values (also checking the return) Then you can `switch(*argv[2])` to switch on the 1st character in the 2nd argument, and your cases would be `'+'`, `'-'`, .. – David C. Rankin Nov 02 '20 at 04:59

2 Answers2

4

Firstly I would highly recommend looking at the man-pages for any C library function you come across, they have a lot of useful information. It seems like you are using scanf() improperly as it is not made to be used with command line arguments.

You can check for matches for a single character by comparing the argument like this:

if(argv[2][0] == '+') ...

(argv[0] is the program's file name).

If would would like to compare string you can use strcmp(). But for the operator example you can get away with just checking the first and second characters in the argument like this:

if(argv[2][0] == '+' && argv[2][0] == '\0') ...

What this does is compare the first two characters of the argument. It first checks for the '+' and then checks if that is the end of the string with by checking for the null terminator '\0'.

We can make the assumption that any argument has at least two characters, the visible character and a null terminator. Performing this on other strings has no guarantee of this however.

The other characters, specifically the numbers need to be converted from their respective ASCII values to integers. You can use atoi or strtol to do this, although atoi will most likely be easier for you.

As David C. Rankin pointed out, **argv is a double pointer which at a high level and in most cases you can treat as a double array. In C a string is actually just an array of type char, so what argv[2] is doing above is first accessing the third index of **argv, this is now de-referenced to a type char * where the string (char array) is located. This can then further be de-referenced by the [0] in argv[2][0] to look at the first char of the string.

Code example:

char **my_arrays = argv; // a array of arrays
char *array = *argv;       // de-references to index 0 in argv
char *array = *(argv + 1); // de-references to index 1 in argv
char *array = argv[0];     // de-references to index 0 in argv
char *array = argv[1];     // de-references to index 1 in argv

char first_char = *(*argv)   // the first char of the first array of argv
char first_char = *(argv[0]) // the same as above
char first_char = argv[0][0] // the same as above

A side note. All strings in C should end in a null terminator which can be represented by NULL, 0, or '\0' values. This will represent the end of the string and many C functions rely on this to know when to stop. Also NULL is technically a C macro, but you don't need to treat it any differently than 0 because it literally just expands to 0.

3
  1. It's char **argv. As Some programmer dude said, you should reread your book/tutorial.
  2. scanf doesn't read arguments. It reads from stdin.
  3. Arguments are of type char* and are stored in argv. To convert these arguments to integers, use atoi or strtol (preferably strtol). See this for more info.
  4. If you want to read from stdin using scanf, that is fine, and what you have will work as long as you instead input the data into stdin, and not as command line arguments.
  • 1
    That pretty much covers it. Good note on not using `atoi()` which will happily and silently return `0` for `atoi ("cow");` A similar StackOverflow link is [usage difference between “atoi” and “strtol” in c](https://stackoverflow.com/q/60946328/3422102). – David C. Rankin Nov 02 '20 at 05:05