I've encountered an issue with heap deallocation using free() in my tokenizer. The tokenizer is part of a recursive descent parsing calculator, which works flawlessly otherwise. But upon incorporation of a call to the deallocation function, it behaves erratically. While realistically, the calculator will likely never come close to exhausting its heap, writing a program with a memory leak is just poor practice.
tokenize.h
#define OPERAND 0
#define OPERATOR 1
#define PARENTHESIS 2
#define TERMINAL 3
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
typedef struct {
int id;
char *value;
} token;
int token_count();
token *tokenize();
void deallocate();
tokenize.c
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(char string[]) {
int i = 0;
int count = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
while (1) {
i++;
if (string[i] >= '0' && string[i] <= '9') {
continue;
} else {
break;
}
}
count++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
i++;
continue;
default:
return 0;
break;
}
}
return count;
}
token *tokenize(char string[]) {
int i = 0;
token *ret;
int count = token_count(string);
if (!count) {
return ret;
}
ret = malloc((count + 1) * sizeof(token));
ret[count].id = TERMINAL;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
ret[ret_ind].id = OPERAND;
int size = 0;
int j = i;
while (1) {
size++;
j++;
if (string[j] >= '0' && string[j] <= '9') {
continue;
} else {
break;
}
}
ret[ret_ind].value = malloc(size * sizeof(char) + 1);
ret[ret_ind].value[size + 1] = '\0';
for(int k = 0; k < size; k++) {
ret[ret_ind].value[k] = string[i + k];
}
i = j;
ret_ind++;
continue;
}
switch (string[i]) {
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = L_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2 * sizeof(char));
ret[ret_ind].value[0] = R_PARENTHESIS;
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
return ret;
}
void deallocate(token *in) {
int i = 0;
while (1) {
free(in[i].value);
i++;
if (in[i].id == TERMINAL) {
break;
}
}
free(in);
return;
}
There are multiple problems in your code:
in case the input line has no tokens or a syntax error, you return ret uninitialized from tokenize. You should return NULL instead.
ret[ret_ind].value[size + 1] = '\0'; stores the null terminator one step too far in the allocated array. It should be ret[ret_ind].value[size] = '\0';
malloc(size * sizeof(char) + 1) is inconsistent: if you insist on using sizeof(char), which is 1 by definition, you should write malloc((size + 1) * sizeof(char)), but it is idiomatic to use malloc(size + 1) in C and you could also replace multiple lines of code with a simple ret[ret_ind].value = strndup(string + i, k);
the cases for L_PARENTHESIS and R_PARENTHESIS could be merged into a single block.
the deallocation loop should stop when you reach the TERMINAL token. As currently coded, you cannot handle an empty list, which you should not produce, but it is better to make utility functions more resilient to later changes.
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
the prototypes in token.h should include the typed argument lists.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
#include "tokenize.h"
int token_count(const char *string) {
int count = 0;
int i = 0;
while (string[i] != '\0') {
switch (string[i++]) {
case ' ':
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i += strspn(string + i, "0123456789");
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
count++;
continue;
default:
return -1;
}
}
return count;
}
token *tokenize(const char *string) {
int count = token_count(string);
if (count <= 0)
return NULL;
token *ret = malloc((count + 1) * sizeof(token));
int i = 0;
int ret_ind = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
int size = strspn(string + i, "0123456789");
ret[ret_ind].id = OPERAND;
ret[ret_ind].value = strndup(string + i, size);
ret_ind++;
i += size;
continue;
}
switch (string[i]) {
case ' ':
i++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
ret[ret_ind].id = OPERATOR;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
case L_PARENTHESIS:
case R_PARENTHESIS:
ret[ret_ind].id = PARENTHESIS;
ret[ret_ind].value = malloc(2);
ret[ret_ind].value[0] = string[i];
ret[ret_ind].value[1] = '\0';
ret_ind++;
i++;
continue;
default:
break;
}
break;
}
ret[ret_ind].id = TERMINAL;
return ret;
}
void deallocate(token *in) {
if (in) {
for (int i = 0; in[i] != TERMINAL; i++)
free(in[i].value);
free(in);
}
}
Here are additional remarks for the rest of the code:
why clear the screen on entry and exit?
you should test for end of file in the main loop:
if (!fgets(user_in, 1024, stdin))
break;
you should strip the newline efficiently:
#include <string.h>
user_in[strcspn(user_in, "\n")] = '\0';
then you can simplify the test for exit:
if (!strcmp(user_in, "exit"))
break;
no need to clear user_in after solve()
you could simplify testing by solving the command line arguments:
for (int i = 1; i < argc; i++)
solve(argv[i]);
you should ignore white space and accept empty lines
you should use "%.17g instead of %lf. Note that the l is mandatory
for scanf() for a double type, but ignored for printf, because
float arguments are converted to double when passed to vararg
functions like printf.
you should use a context structure and pass a pointer to it
to parse and its helper functions to avoid global variables
as you can see in try_add_sub and try_mul_div, it would simplify
the switch to unify token types and avoid the OPERATOR classification.
the parser is too complicated: you should use recursive descent more
directly: try_add_sub should first call try_mul_div and iterate on
additive operators, calling try_mul_div for each subsequent operand.
Similarly, try_mul_div should first call try_exp and try_exp would
call try_primitive which would handle parentheses and constants.
this approach consumes one token at a time, which can be read from
the expression source on the fly, bypassing the need for tokenizing the whole string.
you should accept the full number syntax for constants, which is easy with strtod().
Here is a simplified version along these directions:
//---- tokenize.h ----
#define TERMINAL 0
#define OPERAND 1
#define ERROR 2
#define ADD '+'
#define SUBTRACT '-'
#define MULTIPLY '*'
#define DIVIDE '/'
#define EXPONENT '^'
#define L_PARENTHESIS '('
#define R_PARENTHESIS ')'
#define SYNTAX_ERROR 1
#define PAREN_ERROR 2
typedef struct context {
char *p;
char *nextp;
int parenthesis_balance;
int error_code;
double value;
} context;
int this_token(context *cp);
void skip_token(context *cp);
//---- tokenize.c ----
#include <stdlib.h>
//#include "tokenize.h"
int this_token(context *cp) {
char *p = cp->p;
for (;;) {
switch (*p) {
case '\0':
cp->nextp = p;
return TERMINAL;
case ' ':
case '\t':
case '\n':
/* ignore white space */
p++;
continue;
case ADD:
case SUBTRACT:
case MULTIPLY:
case DIVIDE:
case EXPONENT:
case L_PARENTHESIS:
case R_PARENTHESIS:
/* single character operators */
cp->nextp = p + 1;
return *p;
default:
/* try and parse as a number constant */
cp->value = strtod(p, &cp->nextp);
if (cp->nextp > p)
return OPERAND;
return ERROR;
}
}
}
void skip_token(context *cp) {
cp->p = cp->nextp;
}
//---- parse.h ----
int parse(char expression[], double *result);
void solve(char expression[]);
//---- parse.c ----
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//#include "tokenize.h"
//#include "parse.h"
/* expression parsers return non zero upon error */
int try_add_sub(context *cp, double *result);
int try_mul_div(context *cp, double *result);
int try_exp(context *cp, double *result);
int try_primary(context *cp, double *result);
int try_add_sub(context *cp, double *result) {
if (try_mul_div(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case ADD:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result += operand;
continue;
case SUBTRACT:
skip_token(cp);
if (try_mul_div(cp, &operand))
return 1;
*result -= operand;
continue;
}
return 0;
}
}
int try_mul_div(context *cp, double *result) {
if (try_exp(cp, result))
return 1;
for (;;) {
double operand;
switch (this_token(cp)) {
case MULTIPLY:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result *= operand;
continue;
case DIVIDE:
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result /= operand;
continue;
}
return 0;
}
}
int try_exp(context *cp, double *result) {
if (try_primary(cp, result))
return 1;
if (this_token(cp) == EXPONENT) {
double operand;
skip_token(cp);
if (try_exp(cp, &operand))
return 1;
*result = pow(*result, operand);
}
return 0;
}
int try_primary(context *cp, double *result) {
switch (this_token(cp)) {
case OPERAND:
skip_token(cp);
*result = cp->value;
return 0;
case L_PARENTHESIS:
skip_token(cp);
cp->parenthesis_balance++;
if (try_add_sub(cp, result))
return 1;
cp->parenthesis_balance--;
if (this_token(cp) != R_PARENTHESIS) {
cp->error_code = PAREN_ERROR;
return 1;
}
skip_token(cp);
return 0;
}
cp->error_code = SYNTAX_ERROR;
return 1;
}
/* parse and evaluate an expression, return error code, update result */
int parse(char expression[], double *result) {
context cc;
cc.nextp = cc.p = expression;
cc.parenthesis_balance = 0;
cc.error_code = 0;
cc.value = 0;
if (try_add_sub(&cc, result))
return cc.error_code;
if (this_token(&cc) != TERMINAL)
return SYNTAX_ERROR;
return 0;
}
void solve(char expression[]) {
double result = 0;
switch (parse(expression, &result)) {
case 0:
printf(" %.17g\n", result);
break;
case SYNTAX_ERROR:
printf("ERROR: Syntax\n");
break;
case PAREN_ERROR:
printf("ERROR: Unbalanced parenthesis\n");
break;
}
}
//---- calculator.c ----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include "parse.h"
int main(int argc, char **argv) {
for (int i = 1; i < argc; i++)
solve(argv[i]);
if (argc == 1) {
char user_in[1024];
char *p;
printf("Terminal Calculator\n");
printf("Type 'exit' to terminate\n\n");
for (;;) {
printf("=> ");
if (!fgets(user_in, sizeof user_in, stdin)) {
printf("\n");
break;
}
/* strip trailing newline */
user_in[strcspn(user_in, "\n")] = '\0';
/* skip initial white space */
p = user_in + strspn(user_in, " \t");
/* ignore empty and comment lines */
if (*p == '\0' || *p == '#')
continue;
/* trap exit command */
if (!strcmp(p, "exit"))
break;
solve(p);
}
}
return 0;
}
Related
I'm reading "TCPL" recently.There exist a classic case "postfix calculator" in section 4.3. I have a question on the case:
See the case code(copy from the book):
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define MAXOP 100
#define NUMBER '0'
#define MAXVAL 100 /* maxmium depth of val stack */
#define BUFFSIZE 100
int sp = 0;
double val[MAXVAL];
int bufp = 0; /* next free size in buf*/
char buf[BUFFSIZE]; /* buffer in ungetch */
int getch(void);
void ungetch(int);
int getop(char []);
void push(double);
double pop(void);
int main()
{
int type;
double op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '/':
op2 = pop();
if (op2 != 0.0) {
push(pop() / op2);
}
else
{
printf("error: zero divisor. \n");
}
break;
default:
printf("\t%.8g\n", pop());
break;
}
}
return 0;
}
/* push: push value f onto value stack */
void push(double f)
{
if (sp < MAXVAL) {
val[sp++] = f;
}
else {
printf("error: stack full, can't push.\n");
}
}
/* pop: pop and return value on the top of the stack */
double pop(void)
{
if (sp > 0) {
return val[--sp];
}
else {
printf("error: stack empty.\n");
return 0.0;
}
}
/* getop: get next character or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t') {
;
}
s[1] = '\0';
if (!isdigit(c) && c != '.' ) { /* operator */
return c;
}
i = 0;
if (isdigit(c)) { /* collect integer part */
while (isdigit(s[++i] = c = getch())) {
;
}
}
if (c == '.') { /* collect fraction part */
while (isdigit(s[++i] = c = getch())) {
;
}
}
s[i] = '\0';
if (c != EOF) {
ungetch(c);
}
return NUMBER;
}
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
return (bufp > 0)? buf[--bufp] : getchar();
}
/* ungetch: push character back on input */
void ungetch(int c)
{
if (bufp >= BUFFSIZE) {
printf("ungetch: too many characters in buufer.\n");
}
else {
buf[bufp++] = c;
}
}
There is a global char array buf, It is like a stack and the last two function are to 'pop' and 'push' on buf.
My question is in which case does the stack buf contains more than one element?
The only chance can the ungetch() be called is in function getop(), however in getop() the function getch() is called at least once.
My question is in which case does the stack buf contains more than one element?
never, buf can be just a char, it is only used to memorize the char placed just after a number to not lost it
The code can be modified to not use it :
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
return getchar();
}
/* ungetch: push character back on input */
void ungetch(int c)
{
ungetc(c, stdin);
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc pf.c
pi#raspberrypi:/tmp $ ./a.out
1 2 3 4 + + +
10
Or using the fact only one char can be saved :
int SavedChar = EOF;
/* getch: get a (possibly pushed-back) character */
int getch(void)
{
if (SavedChar == EOF)
return getchar();
int r = SavedChar;
SavedChar = EOF;
return r;
}
/* ungetch: push character back on input */
void ungetch(int c)
{
SavedChar = c;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc pf.c
pi#raspberrypi:/tmp $ ./a.out
1 2 3 4 + + +
10
I am trying to solve one problem from spoj http://www.spoj.com/problems/ARITH2/
But every time i am getting 'WA' Wrong Answer.I've tried every possible Test Case and it's giving me expected results.I've written the code mentioned below:
#include <stdio.h>
int main() {
int t,s=0;char operator;
scanf("%d",&t);
while(t--)
{
signed long long int s=0,c=0;
scanf("%lld",&s);
while(1)
{
operator=0;
operator=getc(stdin);
if(operator=='=')
break;
scanf("%lld",&c);
switch(operator)
{
case '+' : s=s+c;
break;
case '-' : s=s-c;
break;
case '*' : s=s*c;
break;
case '/' : s=s/c;
break;
}
}
printf("%lld\n",s);
}
return 0;
}
Please check the requirement, you should not use scanf instead, using sscanf cos the input is whole expression such 50 * 40 * 250 + 791 =. You can create a simple parser as below code to walkthrough whole expression.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char ch = 0;
int state = 0;
char buff[128];
char ops = 0;
unsigned int result = 0;
int i = 0, idx = 0;
char expr[1024];
int cnt = 0;
if (scanf("%[^=]=%n", expr, &cnt) <= 0)
return 0;
while(idx < cnt) {
ch = expr[idx++];
printf("state %d ch %c\n", state, ch);
switch(state) {
case 0:
if ((ch <= '9') && (ch >= '0')) {
state++;
buff[i++] = ch;
}
break;
case 1:
if ((ch <= '9') && (ch >= '0')) {
buff[i++] = ch;
} else {
buff[i] = '\0';
if (i > 0) {
unsigned int num = atoi(buff);
switch (ops) {
case '-':
result -= num;
break;
case '+':
result += num;
break;
case '*':
result *= num;
break;
case '/':
result /= num;
break;
default:
result = num;
break;
}
printf("> found fact %d, result %u\n", num, result);
}
i = 0;
if ((ch == '-') || (ch == '+') || (ch == '*') || (ch == '/')) {
state = 0;
ops = ch;
printf("> found ops %c\n", ch);
} else if ((ch == ' ') || (ch == '\t')) {
continue;
} else if (ch == '=') {
break;
} else {
// expression end
break;
}
}
break;
default:
break;
}
}
printf("> result '%u' ", result);
return 0;
}
Quick glance, it doesn't look like you are respecting the spacing outlined in the spec. For example, 1 + 1 * 2 = is going to read the wrong character for operator. 1+1*2= looks like it'll work, but that's not what was asked for.
Also, you're reading in unsigned integers and will instantly fail any test cases with signed numbers.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "stack.h"
#define MAX_EQU_LEN 100
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
char* infix_to_postfix(char* infix)
{
char* postfix = malloc(MAX_EQU_LEN);
stack* s = create_stack();
s->size = strlen(infix);
node* tempPtr = s->stack;
unsigned int i;
char symbol,next;
for(i = 0; i < s->size ; i++)
{
symbol = *((infix + i));
tempPtr = s->stack;
if(isNumeric(&symbol) != 1)
{
strcat(postfix, &symbol);
}
else if(symbol == '(')
{
push(s, symbol);
}
else if(symbol == ')')
{
while(s->size != 0 && top(s) != '(')
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
tempPtr = s->stack;
if(tempPtr->data == '(')
{
pop(s);
}
}
}
else
{
while(s->size != 0 && prec(top(s)) > prec(symbol))
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
push(s,next);
}
}
while(s->size != 0)
{
next = tempPtr->data;
pop(s);
strcat(postfix, &next);
}
}
return postfix;
}
int evaluate_postfix(char* postfix) {
//For each token in the string
int i,result;
int right, left;
char ch;
stack* s = create_stack();
node* tempPtr = s->stack;
for(i=0;postfix[i] < strlen(postfix); i++){
//if the token is numeric
ch = postfix[i];
if(isNumeric(&ch)){
//convert it to an integer and push it onto the stack
atoi(&ch);
push(s, ch);
}
else
{
pop(&s[i]);
pop(&s[i+1]);
//apply the operation:
//result = left op right
switch(ch)
{
case '+': push(&s[i],right + left);
break;
case '-': push(&s[i],right - left);
break;
case '*': push(&s[i],right * left);
break;
case '/': push(&s[i],right / left);
break;
}
}
}
tempPtr = s->stack;
//return the result from the stack
return(tempPtr->data);
}
This file is part of a program that uses a stack struct to perform an infix to postfix on an input file. The other functions have been tested and work fine but when I try to add this part and actually perform the operations the program segmentation faults. A debugger says it occurs in the infix_to_postfix function however it doesn't say which line and I can't figure out where. Does anyone know why this would seg fault?
You've done a few things wrong:
if(isNumeric(&symbol) != 1)
The function isNumeric() expects a null terminated string as input, not a pointer to a single character.
strcat(postfix, &symbol);
Here the same thing applies.
strcat(postfix, &next);
I'm guessing this is wrong too. If you want to turn a single character into a string, you can do this:
char temp[2] = {0};
temp[0] = symbol;
strcat(postfix, temp);
static int isNumeric(char* num)
{
if(atoi(num) == 0)
{
return 0;
}
return 1;
}
What if the string is "0"? Consider using strtol instead because it offers a more powerful means of testing the success of the outcome.
An unrelated stylistic note: your first function looks overcomplicated to me. Although it's perfectly possible that the way I'd do it is also overcomplicated.
static int prec(char operator)
{
switch (operator)
{
case '*':
return 5;
case '/':
return 4;
case '%':
return 3;
case '+':
return 2;
case '-':
return 1;
default:
break;
}
return 0;
}
If a function performs a simple mapping from one set to another, It could usually be performed more simply (and faster) as an array lookup. So I'd start with a string of the input characters.
char *operators = "*" "/" "%" "+" "-";
Note that the compiler will concatenate these to a single string value with a null-terminator.
int precedence[] = { 5, 4, 3, 2, 1, 0 };
Then testing whether a char is an operator is:
#include <string.h>
if (strchr(operators, chr))
...;
And getting the precedence becomes:
p = precedence[strchr(operators, chr) - operators];
If there are more values to associate with the operator, I'd consider using an X-Macro to generate a table and a set of associated enum values to use as symbolic indices.
I'm solve an exercise in which one of the functions has to translate infix notation to postfix notation. Here follows my whole code
#include<stdio.h>
#define MAX 100
char stack[MAX];
int top;
void compact(char Descomp[], char Compac[]);
void init_stack();
int push(char Elem);
int desempilha(char *Elem);
int priority(char Operator);
int arity(char Exp[], int position);
int translate_pos(char exp[], char exp_pos[]);
int main()
{
char Exp[MAX]; /* stores the expression read from stdin */
char Exp_compact[MAX]; /* stores expression without spaces */
char Exp_pos[MAX]; /* stores the expression after the translation for postfix*/
int indicator; /* indicate if an error occurred, 0 for NO ERROR and -1 for ERROR*/
indicator = 0;
printf("\nType the expression: ");
gets(Exp);
compact(Exp, Exp_compact);
indicator = translate_pos(Exp_compact, Exp_pos);
puts(Exp_pos);
return indicator;
}
/* compact function delete spaces within the expression read from stdin */
void compact(char Descomp[], char Compac[])
{
int i;
int j;
i = 0;
j = 0;
while(Descomp[j] != '\0')
{
if(Descomp[j] != ' ')
{
Compac[i] = Descomp[j];
i++;
}
j++;
}
}
/* initiate the stack by setting top = -1 */
void init_stack()
{
top = -1;
}
/* puts the element Elem in the stack */
int push(char Elem)
{
if(top == MAX - 1) /* Stack is full */
return -1;
top++;
stack[top] = Elem;
return 0;
}
/* remove the element in stack[top] and puts it in &Elem*/
int pop(char *Elem)
{
if(top == -1) /* stack is empty */
return -1;
*Elem = stack[top];
top--;
return 0;
}
/* Return the priority of an operator */
int priority(char Operator)
{
switch(Operator)
{
case '+': return 1;
case '-': return 1;
case '*': return 2;
case '/': return 2;
case '^': return 3;
case '(': return 4;
case ')': return 5;
default : return 0;
}
}
/* returns the arity of CONSTANTS + - * / and ^, for ( an ) is merely symbolic */
int arity(char Exp[], int position)
{
if(priority(Exp[position]) == 1)
{
if( (position == 0) || ( (priority(Exp[position - 1]) >= 1) && (priority(Exp[position - 1]) <= 3) ))
return 1;
else
return 2;
}
else if( (priority(Exp[position]) > 1) && (priority(Exp[position]) <= 4))
return 2;
else
return priority(Exp[position]);
}
/* reads an infix expression and returns postfix expression */
int translate_pos(char exp[], char exp_pos[])
{
int i;
int j;
int ind;
char trash;
i = 0;
j = 0;
ind = 0;
trash = ' ';
init_stack();
while(exp[i]!= '\0')
{
if(arity(exp, i) == 0)
{
exp_pos[j] = exp[i];
j++;
}
if(arity(exp, i) == 1)
{
switch(exp[i])
{
case '-':
{
exp_pos[j] = exp_pos[i];
j++;
}
case '+': trash = exp_pos[i];
}
}
if(arity(exp, i) == 2)
{
while((top != -1) && (priority(stack[top]) <= priority(exp[i])))
{
ind = pop(&exp_pos[j]);
j++;
}
ind = push(exp[i]);
}
if(priority(exp[i]) == 4)
{
ind = push(exp[i]);
}
if(priority(exp[i]) == 5)
{
while( (top != -1) && (stack[top] != '('))
{
ind = pop(&exp_pos[j]);
j++;
}
if(stack[top] == '(')
ind = pop(&trash);
}
i++;
}
while(top != -1)
{
ind = pop(&exp_pos[j]);
j++;
}
return ind;
}
The algorithm I used to translate the expression is
while there is token to be read;
read the token;
if token is a constant
push it to Exp_Postfix;
if token is '('
push it to stack
if token is ')'
pop from the stack all symbols until '(' be find and remove '(' from the stack
if token is an operator and its arity is 2
pop all operators with less or equal priority than the token and store then in the Exp_Postfix;
push token to the stack;
if token is an operator and its arity is 1
if token is '-'
push it to Exp_postfix;
if token is '+'
pass to the next token;
pop all remaining symbols in the stack and push then, in order, to the Exp_Postfix;
I compiled the .c archive using
gcc -Wall archive.c -o archive
and executed it. I give the expression
5+(6*9^14)
It the returned expression was
5
I do not now if the error is in my code or in solution to the problem.
There are an awful lot of problems, here, for instance:
compact() and translate_pos() leave Exp_compact and Exp_pos, respectively, without a terminating \0, so you're getting garbage printed out.
your arity() function is returning 2 for an opening parenthesis.
in the first switch statement of translate_pos(), you're missing break statements.
Your priority comparison in translate_pos() when arity is 2 is back to front.
When you're comparing operator precedence, you should treat an opening parenthesis specially, since it should have the lowest precedence when on the top of the stack.
You should have a lot more else keywords in translate_pos().
You're using gets(), which was always bad, and now has actually been removed from C.
I haven't exhaustively tested it, but here's a correct version that seems to work for all the test inputs I tried:
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
/* Function prototypes */
void compact(char Descomp[], char Compac[]);
void init_stack();
int push(char Elem);
int desempilha(char *Elem);
int priority(char Operator);
int arity(char Exp[], int position);
int translate_pos(char exp[], char exp_pos[]);
/* Stack variables */
#define MAX 100
char stack[MAX];
int top;
int main(void) {
char Exp[MAX];
char Exp_compact[MAX] = {0};
char Exp_pos[MAX] = {0};
int indicator = 0;
printf("\nType the expression: ");
fgets(Exp, MAX, stdin);
compact(Exp, Exp_compact);
indicator = translate_pos(Exp_compact, Exp_pos);
puts(Exp_pos);
return indicator;
}
/* compact function delete spaces within the expression read from stdin */
void compact(char Descomp[], char Compac[]) {
int i = 0;
int j = 0;
while ( Descomp[j] ) {
if ( !isspace(Descomp[j]) ) {
Compac[i++] = Descomp[j];
}
j++;
}
}
/* initiate the stack by setting top = -1 */
void init_stack() {
top = -1;
}
/* puts the element Elem in the stack */
int push(char Elem) {
if (top == MAX - 1) /* Stack is full */
return -1;
stack[++top] = Elem;
return 0;
}
/* remove the element in stack[top] and puts it in &Elem*/
int pop(char *Elem) {
if (top == -1) /* stack is empty */
return -1;
*Elem = stack[top--];
return 0;
}
/* Return the priority of an operator */
int priority(char Operator) {
switch (Operator) {
case '+':
return 1;
case '-':
return 1;
case '*':
return 2;
case '/':
return 2;
case '^':
return 3;
case '(':
return 4;
case ')':
return 5;
default:
return 0;
}
}
/* returns the arity of OPERATORS + - * / and ^,
* for ( an ) is merely symbolic */
int arity(char Exp[], int position) {
if ( priority(Exp[position]) == 1 ) {
if ( (position == 0) ||
((priority(Exp[position - 1]) >= 1) &&
(priority(Exp[position - 1]) <= 3)) ) {
return 1;
} else {
return 2;
}
} else if ( (priority(Exp[position]) > 1) &&
(priority(Exp[position]) <= 3) ) {
return 2;
} else {
return priority(Exp[position]);
}
}
/* reads an infix expression and returns postfix expression */
int translate_pos(char exp[], char exp_pos[]) {
int i = 0, j = 0, ind = 0;
char trash = ' ';
init_stack();
while ( exp[i] ) {
if ( arity(exp, i) == 0 ) {
exp_pos[j++] = exp[i];
} else if ( arity(exp, i) == 1 ) {
switch (exp[i]) {
case '-':
exp_pos[j++] = exp[i];
break;
case '+':
trash = exp_pos[i];
break;
default:
assert(0);
}
} else if (arity(exp, i) == 2) {
while ( (top != -1) &&
(priority(stack[top]) >= priority(exp[i])) &&
stack[top] != '(' ) {
ind = pop(&exp_pos[j++]);
}
ind = push(exp[i]);
} else if ( priority(exp[i]) == 4 ) {
ind = push(exp[i]);
} else if ( priority(exp[i]) == 5 ) {
while ( (top != -1) && (stack[top] != '(') ) {
ind = pop(&exp_pos[j++]);
}
if ( (top != - 1) && stack[top] == '(') {
ind = pop(&trash);
}
}
i++;
}
while (top != -1) {
ind = pop(&exp_pos[j++]);
}
return ind;
}
Gives the following output for various test cases:
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 1+2
12+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (1+2)
12+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 1+2*3
123*+
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (1+2)*3
12+3*
paul#local:~/src/c/postfix$ ./postfix
Type the expression: (3+4)*4/2
34+4*2/
paul#local:~/src/c/postfix$ ./postfix
Type the expression: 5+(6*9^14)
56914^*+
paul#local:~/src/c/postfix$
I'd suggest comparing my code to yours and trying to understand the individual differences to see where you were going wrong.
In the main function of C:
void main(int argc, char **argv)
{
// do something here
}
In the command line, we will type any number for example 1 or 2 as input, but it will be treated as char array for the parameter of argv, but how to make sure the input is a number, in case people typed hello or c?
Another way of doing it is by using isdigit function. Below is the code for it:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXINPUT 100
int main()
{
char input[MAXINPUT] = "";
int length,i;
scanf ("%s", input);
length = strlen (input);
for (i=0;i<length; i++)
if (!isdigit(input[i]))
{
printf ("Entered input is not a number\n");
exit(1);
}
printf ("Given input is a number\n");
}
You can use a function like strtol() which will convert a character array to a long.
It has a parameter which is a way to detect the first character that didn't convert properly. If this is anything other than the end of the string, then you have a problem.
See the following program for an example:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[]) {
int i;
long val;
char *next;
// Process each argument given.
for (i = 1; i < argc; i++) {
// Get value with failure detection.
val = strtol (argv[i], &next, 10);
// Check for empty string and characters left after conversion.
if ((next == argv[i]) || (*next != '\0')) {
printf ("'%s' is not valid\n", argv[i]);
} else {
printf ("'%s' gives %ld\n", argv[i], val);
}
}
return 0;
}
Running this, you can see it in operation:
pax> testprog hello "" 42 12.2 77x
'hello' is not valid
'' is not valid
'42' gives 42
'12.2' is not valid
'77x' is not valid
Using scanf is very easy, this is an example :
if (scanf("%d", &val_a_tester) == 1) {
... // it's an integer
}
A self-made solution:
bool isNumeric(const char *str)
{
while(*str != '\0')
{
if(*str < '0' || *str > '9')
return false;
str++;
}
return true;
}
Note that this solution should not be used in production-code, because it has severe limitations. But I like it for understanding C-Strings and ASCII.
Using fairly simple code:
int i;
int value;
int n;
char ch;
/* Skip i==0 because that will be the program name */
for (i=1; i<argc; i++) {
n = sscanf(argv[i], "%d%c", &value, &ch);
if (n != 1) {
/* sscanf didn't find a number to convert, so it wasn't a number */
}
else {
/* It was */
}
}
I was struggling with this for awhile, so I thought I'd just add my two cents:
1) Create a separate function to check if an fgets input consists entirely of numbers:
int integerCheck(){
char myInput[4];
fgets(myInput, sizeof(myInput), stdin);
int counter = 0;
int i;
for (i=0; myInput[i]!= '\0'; i++){
if (isalpha(myInput[i]) != 0){
counter++;
if(counter > 0){
printf("Input error: Please try again. \n ");
return main();
}
}
}
return atoi(myInput);
}
The above starts a loop through every unit of an fgets input until the ending NULL value. If it comes across a letter or an operator, it adds "1" to the int "counter" which is initially set to 0. Once the counter becomes greater than 0, the nested if statement instructs the loop to print an error message & then restart the program. When the loops completes, if int 'counter' is still the value of 0, it returns the initially inputted integer to be used in the main function ...
2) the main function would be:
int main(void){
unsigned int numberOne;
unsigned int numberTwo;
numberOne = integerCheck();
numberTwo = integerCheck();
return numberOne*numberTwo;
}
Assuming both integers are inputted correctly, the example provided will yield the result of int "numberOne" multiplied by int "numberTwo". The program will repeat for however long it takes to get two properly inputted integers.
if (sscanf(command_level[2], "%f%c", &check_f, &check_c)!=1)
{
is_num=false;
}
else
{
is_num=true;
}
if(sscanf(command_level[2],"%f",&check_f) != 1)
{
is_num=false;
}
how about this?
This works for me
#include <string.h>
int isNumber(char *n) {
int i = strlen(n);
int isnum = (i>0);
while (i-- && isnum) {
if (!(n[i] >= '0' && n[i] <= '9')) {
isnum = 0;
}
}
return isnum;
}
e.g.:
printf("%i\n", isNumber("12")); // 1
printf("%i\n", isNumber("033")); // 1
printf("%i\n", isNumber("0")); // 1
printf("%i\n", isNumber("")); // 0
printf("%i\n", isNumber("aaa")); // 0
printf("%i\n", isNumber("\n")); // 0
printf("%i\n", isNumber("a0\n")); // 0
The C library function int isdigit(int c) checks if the passed character is a decimal digit character.
#include <stdio.h>
#include <ctype.h>
int main () {
int var1 = 'h';
int var2 = '2';
if( isdigit(var1) ) {
printf("var1 = |%c| is a digit\n", var1 );
} else {
printf("var1 = |%c| is not a digit\n", var1 );
}
if( isdigit(var2) ) {
printf("var2 = |%c| is a digit\n", var2 );
} else {
printf("var2 = |%c| is not a digit\n", var2 );
}
return(0);
}
the result is :
var1 = |h| is not a digit
var2 = |2| is a digit
The sscanf() solution is better in terms of code lines. My answer here is a user-build function that does almost the same as sscanf(). Stores the converted number in a pointer and returns a value called "val". If val comes out as zero, then the input is in unsupported format, hence conversion failed. Hence, use the pointer value only when val is non-zero.
It works only if the input is in base-10 form.
#include <stdio.h>
#include <string.h>
int CONVERT_3(double* Amt){
char number[100];
// Input the Data
printf("\nPlease enter the amount (integer only)...");
fgets(number,sizeof(number),stdin);
// Detection-Conversion begins
int iters = strlen(number)-2;
int val = 1;
int pos;
double Amount = 0;
*Amt = 0;
for(int i = 0 ; i <= iters ; i++ ){
switch(i){
case 0:
if(number[i]=='+'){break;}
if(number[i]=='-'){val = 2; break;}
if(number[i]=='.'){val = val + 10; pos = 0; break;}
if(number[i]=='0'){Amount = 0; break;}
if(number[i]=='1'){Amount = 1; break;}
if(number[i]=='2'){Amount = 2; break;}
if(number[i]=='3'){Amount = 3; break;}
if(number[i]=='4'){Amount = 4; break;}
if(number[i]=='5'){Amount = 5; break;}
if(number[i]=='6'){Amount = 6; break;}
if(number[i]=='7'){Amount = 7; break;}
if(number[i]=='8'){Amount = 8; break;}
if(number[i]=='9'){Amount = 9; break;}
default:
switch(number[i]){
case '.':
val = val + 10;
pos = i;
break;
case '0':
Amount = (Amount)*10;
break;
case '1':
Amount = (Amount)*10 + 1;
break;
case '2':
Amount = (Amount)*10 + 2;
break;
case '3':
Amount = (Amount)*10 + 3;
break;
case '4':
Amount = (Amount)*10 + 4;
break;
case '5':
Amount = (Amount)*10 + 5;
break;
case '6':
Amount = (Amount)*10 + 6;
break;
case '7':
Amount = (Amount)*10 + 7;
break;
case '8':
Amount = (Amount)*10 + 8;
break;
case '9':
Amount = (Amount)*10 + 9;
break;
default:
val = 0;
}
}
if( (!val) | (val>20) ){val = 0; break;}// val == 0
}
if(val==1){*Amt = Amount;}
if(val==2){*Amt = 0 - Amount;}
if(val==11){
int exp = iters - pos;
long den = 1;
for( ; exp-- ; ){
den = den*10;
}
*Amt = Amount/den;
}
if(val==12){
int exp = iters - pos;
long den = 1;
for( ; exp-- ; ){
den = den*10;
}
*Amt = 0 - (Amount/den);
}
return val;
}
int main(void) {
double AM = 0;
int c = CONVERT_3(&AM);
printf("\n\n%d %lf\n",c,AM);
return(0);
}