-1

I have an assignment where I'm supposed to make a simple arithmetic calculator in C that takes an input of a number, an operator, and a second number and performs the operation and outputs it. Sounds pretty simple right?

I'm limited to using specifically getchar() and putchar() for number input. This means that I have to read the whole input one char at a time... and I'm confused as to how I would read two chars of a number (9 and 1 of 91 for example) as one number. If getchar() read from right to left, this would be a different story. But unfortunately, it is not...

I would appreciate any pointers!

OmriSama
  • 302
  • 5
  • 11

3 Answers3

6

Here is some pseudo-code: c = getchar() num = 0 while isdigit(c) num = (num * 10) + (c - '0') c = getchar()

This accumulates the number, recognizing that each new digit to the right effectively multiplies the digits seen already by 10. It stops accumulating when a non-digit is seen, so parsing strings like 91+3 works.

Craig S. Anderson
  • 6,966
  • 4
  • 33
  • 46
  • I like this answer the most because it *is* correct assuming `c` is an `int`. This is despite the missing sign handling which wasn't mentioned in the question, so is only a minor issue. In fact, I would suggest that the bigger issue is that the value for `c` which terminates the loop is easily forgotten about, potentially leading to the `'+'` in the example being discarded accidentally. If I were going to put this into a modular function as some of the answers below do, I'd put `ungetc(c, stdin);` following the loop... Nice job, Craig. – autistic Apr 08 '15 at 03:20
0

If each input will be given separated then you can try using a loop.

char c = getchar();
int num = 0;
int neg = 0;

if(c == '-') {
   neg = 1;
   c = getchar();
}

while(isdigit(c)) {
    num = num * 10;
    num = num + (c - '0');
    c = getchar();
}

if(neg) {
    num = num * -1;
}

Basically you accumulate each number one char at a time. However, you need to make room for the next character that's incomming. So you need to multiply the number by 10 to shift it 1 digit to the left.

jor
  • 793
  • 7
  • 13
  • It's not necessary that each input is given separately, just adjust the exit condition for the second loop... – Matteo Italia Apr 07 '15 at 06:14
  • I have a question... Supposing `char` is an unsigned type (which it can very well be) and that means the only values it can store are positive, how is `c` ever supposed to compare equal to `EOF`? Doesn't it make sense that since `getchar` returns an `int`, `c` should also be an `int`? I put it to you that the only character values `getchar` returns are `unsigned char` values, and that `EOF` is not a character value; It's an error mode. Because `getchar` could return one of 257 values (assuming `CHAR_BIT == 8`), ***not*** 256, `c` should be an `int`. – autistic Apr 07 '15 at 06:51
  • @undefinedbehaviour, I just did a little research and you are correct. I have updated answer to use the isdigit() instead. – jor Apr 07 '15 at 07:21
  • @jor That doesn't fix the problem. In fact, it compounds the problem. I think you've missed my point. – autistic Apr 08 '15 at 01:32
  • The `isdigit` manual says: [The *c* argument is an `int`, the value of which the application shall ensure is a character representable as an **`unsigned char`** or equal to the value of the macro `EOF`. If the argument has any other value, the behavior is undefined.](http://pubs.opengroup.org/onlinepubs/009695399/functions/isdigit.html) – autistic Apr 08 '15 at 01:41
-1

define ENTER '\n'

int read_num()
{
    int num = 0;
    int c;

    c = getchar() - '0';
    num = (c < 0) ? 0 : c;

    while ((c = getchar()) != ENTER) {
        c -= '0';
        num *= 10;
        num = (num == 0 || num < 0) ? num - c: num + c;
    }

    return num;
}

PS: new code

#include <stdio.h>

int readnum()
{
    unsigned int c;
    int num = 0;
    int dec;
    int sign = 0;
    
    while ( (c = getchar()) != '\n') {
        
        dec = c - '0';
        if ( dec >= 0 && dec <= 9) {
            num *= 10;
            num = (sign == 1 || num < 0) ? num - dec: num + dec;
        } else if (c == '-') {
            sign = 1;
        } else if (c == '+')
            sign = 0;
        
    }
    return num;
}

int main()
{
    printf("%d\n", readnum());
    return 0;
}

Other solution:

#define ENTER '\n'

int read_num()
{
    int num = 0;
    int c;
    int signal = 1;
    
    while ((c = getchar()) != ENTER) {
        
        if (signal == 1 && (c == '-' || c == '+')) {
                signal = (c == '-') ? -1 : 1;
        } else {
            num = num * 10 + (c - '0');
        }
    }

    return num * signal;
}
Community
  • 1
  • 1
  • `num = (c < 0) ? 0 : c;`, you say? – autistic Apr 08 '15 at 01:43
  • This verifies that the first byte read is a negative sign. If so, add zero, since the signal can only be assigned when a number is read. – please delete me Apr 08 '15 at 02:51
  • There is nothing wrong with the code, the problem is that you do not understand. getchar returns the corresponding integer a key typed, if he enter the negative sign, to make getchar () - '0', will give a negative number, this number is not part of the typed sequence, what we want is only whether he is entering a negative number (starting with -). Do not confuse with EOF, see I'm doing an arithmetic (getchar () - '0'), EOF does not enter in this case. – please delete me Apr 08 '15 at 04:06
  • [Here](http://www.iso-9899.info/n1570.html#5.2.1) is the section of the C standard defining character sets... Can you show me which section requires the `'-'` character to be less than `'0'`? – autistic Apr 08 '15 at 04:21
  • if char is '-' getchar() - '0' = -3 (45 - 48 in decimal) – please delete me Apr 08 '15 at 04:24
  • Right, so if `c` is `EOF` then `num` is `(EOF * 10 + EOF) * 10 + EOF ...` ad infinitum... and if ASCII isn't the character set used, and `'-' > '0'` then that's a valid digit? – autistic Apr 08 '15 at 04:26
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/74679/discussion-between-undefined-behaviour-and-chrislley-alves). – autistic Apr 08 '15 at 04:29
  • Forget EOF! EOF does not apply after the arithmetic (getchar () - '0'). After subtraction, I will have a negative value if passed any value below decimal of '0', then this value is a valid number, so add in a 0. See the second code, it is simpler. – please delete me Apr 08 '15 at 04:39
  • `EOF` is not a character value; It's an error mode and should be handled as an error mode. Hence [this testcase](http://ideone.com/t4Lvy3) I produced in chat, with a `printf` statement for your benefit, where `EOF` is repeated ad infinitum despite no '`EOF` characters' being input. – autistic Apr 08 '15 at 04:48
  • See also [this testcase](http://ideone.com/NCY3K1) where a valid number is input, and then `EOF` is encountered directly after the valid number (where one might expect "`ENTER`")... – autistic Apr 08 '15 at 04:51
  • I'm not reading file numbers, I'm reading the keyboard, you can type EOF keyboard? See ascii table for details. – please delete me Apr 08 '15 at 04:57
  • Sure. `stdin` is a `FILE *`, after all. If you're on Windows, press `CTRL+Z`. If you're on Linux, try `CTRL+d`. If you have problems with those, there are other ways to close `stdin`. – autistic Apr 08 '15 at 08:55
  • I said that this function is not to read integer from files. EOF only applies to reading data files, such as forwarding (pipe) in linux, and etc. example: $ ./getnum – please delete me Apr 08 '15 at 10:56
  • K&R is neither the C standard nor the single unix specification, and you've accused both of those of being incorrect in a different question... Not to mention, I cited the standard earlier in this discussion, too. – autistic Apr 08 '15 at 12:21
  • I will not discuss! Will study, program, and test before speaking. THERE IS NO ENTRY (-1) FROM KEYBOARD! OK????? – please delete me Apr 08 '15 at 18:29
  • `stdin` is not a keyboard. – autistic Apr 08 '15 at 22:40