Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Surprising output of a C program when using '*' to multiply

Tags:

c

After solving the exercise 5-10 in the K&R:

Write the program expr, which evaluates a reverse Polish expression from the command line, where each operator or operand is a separate argument. For example, expr 2 3 4 + * evaluates 2*(3+4).

there appears to be the problem in expressions with '*' character, even basic ones like: 2 2 *. For some strange reason, '*' is not placed into the operator array, while all other characters like '+', '-', '/' normally are. I've isolated the part of the code (while loop) which appears to be wrong. Push function is from Chapter 4 and it is only necessary to compile the code.

#include <stdio.h>

void push(double f);

main(int argc, char *argv[])
{
    int a = 0;
    int b;
    char operator[10];

    while (--argc > 0) {
        if (isdigit(*argv[argc]))
            push(atof(argv[argc]));
        else if (*argv[argc]=='+' || *argv[argc]=='-' || *argv[argc]=='*' || *argv[argc]=='/')
            operator[a++] = *argv[argc];
    }
    for (b = 0; b < a; b++)
        printf("%c", operator[b]);
    printf("\n");

    return 0;
}

#define MAXVAL 100  /* maximum depth of val stack */

int sp = 0;     /* next free stack position */
double val[MAXVAL]; /* value stack */

/* push: push f onto value stack */
void push(double f)
{
    if (sp < MAXVAL) 
        val[sp++] = f;
    else
        printf("error: stack full, can't push %g\n", f);
}

Output

[user@machine Desktop]$ ./prog + +
++
[user@machine Desktop]$ ./prog *

[user@machine Desktop]$ ./prog * *

[user@machine Desktop]$ ./prog + / * -
-/+
like image 549
son of hades Avatar asked Dec 14 '22 19:12

son of hades


1 Answers

Your shell is interpreting * and expanding it. To the shell, '*' means "match all text", which is why commands like ls *.c work. Type echo * and you'll see what I mean. Put your arguments in single quotes to prevent the shell from interpreting them.

E.g.,

./prog '*'
./prog 2 2 '*'
./prog '2' '2' '*'

Note that if you put all arguments inside quotes, that entire thing will be given to your program as one entry in argv, which might not be what you want.

E.g., this command will fill argv[1] with the text 2 2 *, instead of breaking it up into 2, 2, and * in argv[1], argv[2], and argv[3].

./prog '2 2 *'

You can also escape individual characters that need escaping with backslash instead of quotes. Your program will get a literal * if you tell the shell \*.

E.g.,

./prog 2 2 \*

This pattern matching is commonly called globbing.

like image 144
indiv Avatar answered Jan 15 '23 16:01

indiv