Juliette
Juliette

Reputation: 65

scanf mathematic expression in c

I'm a beginner in the c language learning and I have a question.
I have to write the following code: user enters a mathematical expression for example 2+3*7 and the code should send the result and take into account the priority of the * and the /.

I thought to enter the user's expression into a char array (it is forbidden to use string) in the first step.

int counter=0;
char test[50],input;

while (counter < 50 && scanf("%c", &input) != EOF ){
    test[counter] = input;
    counter++;
}

for (i = 0; i < counter; i++){
    printf("%c ", test[i]);
}

But the code didn't exit of the loop when the user does enter. What is wrong?
My second question is if it is a good idea to enter the expression into char array if I can not use string?
I can obtain all the characters of the expression in this way?

Upvotes: 2

Views: 1155

Answers (6)

Thayne
Thayne

Reputation: 7032

But the code didn't exit of the loop when the user does enter.

You're code doesn't exit the loop until it gets an EOF(which would typically mean the user presses Ctrl+D) or 50 characters have been entered, not on enter. If you want to end when the user presses enter you need to check if the last character input was a newline.

Also, if you are reading one character at a time getchar would probably be better than scanf.

Reading into a char array is fine, as long as you don't get more characters than the size of the buffer at a time, and make sure that you never overflow the buffer.

EDIT

Somewhat tongue-in-cheek, if the requirement that you can't use strings just means you can't use string.h, and whitespace isn't allowed in the expression (so "4+5" is valid but "4 + 5" isn't), you could just do this:

char test[51],input;
scanf("%50s" &input);
printf("%s", input);

The extra char in test is for the null terminator.

Upvotes: 1

You basically need to write a parser. You could first have some lexer (giving a stream of tokens from a stream of characters). Then from a stream of tokens, your parser would either build an abstract syntax tree in memory, or it could (in your simple case of expressions without variables) compute the expression during the parsing. Any good book about compilers (e.g. the dragon book) explain that in great details.

Several tools exist to generate parsers & lexers. They are (pompously) called compiler-compilers (but they should really be called parser generators). GNU bison is such a tool. But you could consider ANTLR (probably some older version, ANTLR2 or PCCTS)

What you want to achieve is a very standard exercise. There is an example (calc) given in documentation of bison; and the recursive descent parser wikipage has also very similar code.

Regarding scanf specifically, read documentation of scanf(3) & getchar(3) (and also ungetc....). You might read an entire line (to parse it easier and later) with getline(3) (or perhaps even readline(3) on the terminal) or else fgets(3)...

Upvotes: 0

John Bode
John Bode

Reputation: 123578

Note that C does not have a string data type per se; in C, a string is simply a sequence of character values terminated by a 0-valued byte (or byte sequence for multi-byte strings). Strings are stored as arrays of char, but not every array of char contains a string.

If you just want to get a sequence of characters from standard input into a buffer for further parsing, this is probably the simplest approach:

char buffer[N]; // where N is large enough for one line's worth of input;
                // let's call it 80 for now.

while ( fgets( buffer, sizeof buffer, stdin ) )
{
  // process buffer
}

fgets will read characters from the standard input stream into buffer until it either sees a newline (which it will store into buffer if there's room), or has read sizeof buffer - 1 characters. fgets will always write a 0 byte to the buffer to terminate the string. So, for example, if your buffer is sized to hold 10 characters and you type in "2 + 3 * 4Enter", then buffer will contain {'2', ' ', '+', ' ', '3', ' ', '*', ' ', '4', 0}; there isn't enough room to store the newline character, but the string is 0-terminated.

fgets will return NULL if it can't read input from the stream, so the loop above will run until there's a read error or until fgets detects an EOF condition.

However...

The usual approach for handling a situation like this is to read a character at a time from the input and process as you go; this way you don't have to worry about setting aside a buffer large enough to hold the entire expression, you only need buffers large enough to handle tokens within the larger expression (numbers and operators).

Upvotes: 0

chux
chux

Reputation: 154198

But the code didn't exit of the loop when the user does enter.

Enter or '\n' is a valid char to read with scanf("%c", &input). It is simply read just like '2' and '+'.

My second question is if it is a good idea to enter the expression into char array if I can not use string?

Yes this is reasonable. Code needs to 1) not store char past array size 2) Keep track of the used elements in the array.

I can obtain all the characters of the expression in this way?

If you cannot use stings, perhaps you cannot use "%c". Use fgetc(),fputc()

#define N 50
int counter=0;
char test[N];
int input;  // use int to distinguish EOF from a character.

while (counter < N && (input = fgetc(stdin)) != '\n' && input != EOF) {
  test[counter] = input;
  counter++;
}

for (i = 0; i < counter; i++){
  fputc(test[i], stdout);
}

Upvotes: 0

Clifford
Clifford

Reputation: 93556

You are testing scanf() for EOF which is a test for error or end of file, otherwise scanf() returns the number of fields matching the format strings successfully converted. In this case it cannot fail when the input is from the console since %c will match any character, and scanf() will wait indefinitely on the console if there is no character present - You can inject an EOF into the console input, but it seems unlikely that this is intended in this case.

scanf() is not necessary here, the simpler getchar() will suffice:

do
{
    input = getchar() ;
    test[counter] = input;
    counter++;

} while( counter < sizeof(test) && input != '\n' ) ;

Note that like your original code, this does not add a nul terminator (so in that sense it is not a "string").


Due to somewhat irrational restrictions on what parts of stdio may apparently be used:

do
{
    scanf( "%c", &input ) ;
    test[counter] = input;
    counter++;

} while( counter < sizeof(test) && input != '\n' ) ;

Upvotes: 1

P.P
P.P

Reputation: 121427

But the code didn't exit of the loop when the user does enter.

If you want the loop to break after ENTER key, you have to check that in your condition:

while (counter < 50 && scanf("%c", &input) != EOF && input != '\n' ) {
...
}

My second question is if it is a good idea to enter the expression into char array if I can not use string?

Yes. It's fine. There's little difference between a C-string and a char array (such as the terminating NUL byte). So if you can't use string/line reading functions such as fgets(str, sizeof str, stdin); or scanf("%s", buf);, then you don't have too many choices.

Upvotes: 1

Related Questions