Exercise 7-3. Revise minprintf() to handle more of the other facilities of printf().
#include <stdio.h> // for printf(), putchar()
#include <string.h> // for strcat()
#include <ctype.h> // for isdigit()
#include <stdarg.h> // for va_arg, va_list, va_start, va_end
#define MAXLEN 100 // max length of print format
// minimal printf() with variable argument list
void minprintf(char *fmt, ...);
int main()
{
char msg[] = "hello";
short sh = 0;
unsigned u = 1;
float f = -.2f;
double d = 1234567890;
double dd = d*d;
long double ld = dd*dd;
minprintf("msg: \"%s\"\n", msg);
minprintf("msg: \"%8s\"\n", msg);
minprintf("msg: \"%-8s\"\n", msg);
minprintf("msg: \"%8.4s\"\n", msg);
minprintf("msg: \"%8.*s\"\n", 4, msg);
minprintf("msg: \"%-8.4s\"\n", msg);
minprintf("msg: \"%-8.*s\"\n", 4, msg);
minprintf("pointer address: %p\n", msg);
minprintf("msg[0]: \'%c\'\n", msg[0]);
minprintf("%hd, %u, %f\n", sh, u, f);
minprintf("%4hd, %-4u, %8.2f\n", sh, u, f);
minprintf("%4hd, %-4u, %8.*f\n", sh, u, 2, f);
minprintf("%e, %f, %g\n", d, d, d);
minprintf("%12.4e, %-14.2f, %10.2g\n", d, d, d);
minprintf("%12.*e, %-14.*f, %10.*g\n", 4, d, 2, d, 2, d);
minprintf("%lE, %lf, %lG\n", dd, dd, dd);
minprintf("%Lg, %LG\n", ld, ld);
minprintf("%LE, %Lf\n", ld, ld);
return 0;
}
// minimal printf() with variable argument list
void minprintf(char *fmt, ...)
{ // argument pointer: will point to each
va_list ap; // unnamed argument in turn
char format[MAXLEN]; // print format
char cval; // char value
char *p, *sval; // string value
void *vp; // pointer to void
short shval; // short value
short unsigned shuval; // short unsigned value
int i, ival; // integer value
int max; // maximum field width
unsigned uval;
long lval;
long unsigned luval;
long long llval;
long long unsigned lluval;
double dval; // double value
long double ldval;
max = 0;
format[0] = '%'; // initialize
format[1] = '\0'; // end string
va_start(ap, fmt); // make ap point to first unnamed arg
for (p = fmt; *p; p++)
{
if (*p != '%' && format[1] == '\0')
{ // haven't got to the formatting part yet
putchar(*p); // write the string as it is
continue; // go to next for() iteration
} // here *p == '%' or format[1] != '\0'
switch(*++p) // after ++p, p points to print format
{
case '-': case '.': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8': case '9':
i = 1;
format[i++] = *p;
p++;
while (isdigit(*p) || *p == '.')
{
format[i++] = *p;
p++;
}
if (*p == '*')
{
format[i++] = *p; // '*'
max = va_arg(ap, int); // next unnamed arg (max field width)
p++;
}
format[i] = '\0';
p--; // p is incremented at the end of for()
p--; // and at the beginning of switch()
break;
case 'c':
cval = va_arg(ap, int); // next unnamed arg (char as int)
printf("%c", cval);
max = 0, format[1] = '\0'; // reset
break;
case 'h':
strcat(format, "h");
p++;
i = strlen(format);
format[i++] = *p; // char after 'h'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{ // take next unnamed argument as int
shval = va_arg(ap, int); // next unnamed arg (short as int)
if (max) // max > 0
{printf(format, max, shval);}
else {printf(format, shval);} // short integer
max = 0, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{ // take next unnamed argument as unsigned int
shuval = va_arg(ap, unsigned); // unsigned int
if (max) // max > 0
{printf(format, max, shuval);}
else {printf(format, shuval);} // short unsigned int
max = 0, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'd': case 'i': case 'o': case 'x': case 'X':
ival = va_arg(ap, int); // next unnamed arg (int)
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (max) // max > 0
{printf(format, max, ival);}
else {printf(format, ival);}
max = 0, format[1] = '\0'; // reset
break;
case 'u':
uval = va_arg(ap, unsigned);
strcat(format, "u");
if (max) // max > 0
{printf(format, max, uval);}
else {printf(format, uval);}
max = 0, format[1] = '\0'; // reset
break;
case 'l':
strcat(format, "l");
p++;
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
lval = va_arg(ap, long);
if (max) // max > 0
{printf(format, max, lval);}
else {printf(format, lval);}
max = 0, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
luval = va_arg(ap, long unsigned);
if (max) // max > 0
{printf(format, max, luval);}
else {printf(format, luval);}
max = 0, format[1] = '\0'; // reset
break;
}
else if(*p == 'l')
{
p++;
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long);
if (max) // max > 0
{printf(format, max, llval);}
else {printf(format, llval);}
max = 0, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned);
if (max) // max > 0
{printf(format, max, lluval);}
else {printf(format, lluval);}
max = 0, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
dval = va_arg(ap, double);
if (max) // max > 0
{printf(format, max, dval);}
else {printf(format, dval);}
max = 0, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
dval = va_arg(ap, double);
if (max) // max > 0
{printf(format, max, dval);}
else {printf(format, dval);}
max = 0, format[1] = '\0'; // reset
break;
case 'L':
strcat(format, "L");
p++;
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long);
if (max) // max > 0
{printf(format, max, llval);}
else {printf(format, llval);}
max = 0, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned);
if (max) // max > 0
{printf(format, max, lluval);}
else {printf(format, lluval);}
max = 0, format[1] = '\0'; // reset
break;
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
ldval = va_arg(ap, long double);
if (max) // max > 0
{printf(format, max, ldval);}
else {printf(format, ldval);}
max = 0, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 's':
strcat(format, "s");
sval = va_arg(ap, char *);
if (max) // max > 0
{printf(format, max, sval);}
else {printf(format, sval);}
max = 0, format[1] = '\0'; // reset
break;
case 'p':
vp = va_arg(ap, void *);
printf("%p", vp);
max = 0, format[1] = '\0'; // reset
break;
default:
putchar(*p);
max = 0, format[1] = '\0'; // reset
break;
} // end of switch()
} // end of for()
va_end(ap); // clean up when done
}
/*
gcc minprintf.c -o minprintf
./minprintf
msg: "hello"
msg: " hello"
msg: "hello "
msg: " hell"
msg: " hell"
msg: "hell "
msg: "hell "
pointer address: 0x7fffa0ab56f2
msg[0]: 'h'
0, 1, -0.200000
0, 1 , -0.20
0, 1 , -0.20
1.234568e+09, 1234567890.000000, 1.23457e+09
1.2346e+09, 1234567890.00 , 1.2e+09
1.2346e+09, 1234567890.00 , 1.2e+09
1.524158E+18, 1524157875019052032.000000, 1.52416E+18
2.32306e+36, 2.32306E+36
2.323057E+36, 2323057227982592286636176640212729856.000000
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 7-4. Write a private version of scanf() analogous to minprintf() from the previous section (Exercise_7-3).
#include <stdio.h> // for putchar(), printf(), scanf()
#include <string.h> // for strcat()
#include <ctype.h> // for isdigit()
#include <stdarg.h> // for va_arg, va_list, va_start, va_end
#define FALSE 0
#define TRUE 1
#define MAXWORD 100 // max word length
#define MAXLEN 100 // max length of scan format
// minimal scanf() with variable argument list
void minscanf(char *fmt, ...);
int main() // one scan at a time
{
char msg[MAXWORD] = "hola";
short sh;
int i;
unsigned u;
float f;
double d;
double dd;
long double ld1, ld2;
printf("greeting: ");
minscanf("* %s", msg); // Enter
printf("msg: \"%s\"\n", msg); // hola
printf("greeting: ");
minscanf("%s", msg); // halo
printf("msg: \"%s\"\n", msg); // halo
printf("greeting: ");
minscanf("%4s", msg); // hello
printf("msg: \"%s\"\n", msg); // hell
printf("char: ");
minscanf("%c", msg); // for 'o' in "hello" after "hell"
minscanf("%c", msg); // for '\n' after "hello"
minscanf("%c", msg); // d
printf("msg[0]: \'%c\'\n", msg[0]); // d
printf("msg: \"%s\"\n", msg); // dell
printf("short: ");
minscanf("%hd", &sh); // -1
printf("unsigned: ");
minscanf("%u", &u); // +1
printf("float: ");
minscanf("%f", &f); // -.2f
printf("%hd, %u, %f\n", sh, u, f);
printf("day: ");
minscanf("%hi", &sh); // 03
printf("month: ");
minscanf("%d", &i); // 08
printf("year: ");
minscanf("%u", &u); // 2023
printf("day/month/year: %hi/%d/%u\n", sh, i, u); // 3/8/2023
printf("float: ");
minscanf("%e", &f);
printf("double: ");
minscanf("%lf", &d);
printf("double: ");
minscanf("%lg", &dd);
printf("%e, %f, %g\n", f, d, dd);
printf("%E, %F, %G\n", f, d, dd);
printf("long double: ");
minscanf("%Lf", &ld1);
printf("long double: ");
minscanf("%Lg",&ld2);
printf("%Lf, %Lg\n", ld1, ld2);
printf("%LF, %LG\n", ld1, ld2);
return 0;
}
// minimal scanf() with variable argument list
void minscanf(char *fmt, ...)
{ // argument pointer: will point to each
va_list ap; // unnamed argument in turn
char format[MAXLEN]; // scan format
char *cval; // char value
char *p, *sval; // string value
void *vp;
short *shval; // short value
short unsigned *shuval; // short unsigned value
int i, *ival; // integer value
int field; // field width specified?
unsigned *uval;
long *lval;
long unsigned *luval;
long long *llval;
long long unsigned *lluval;
float *fval; // float value
double *dval; // double value
long double *ldval;
field = FALSE; // initialize
format[0] = '%'; // initialize
format[1] = '\0'; // end string
va_start(ap, fmt); // make ap point to first unnamed arg
for (p = fmt; *p; p++)
{
if (*p != '%' && !field)
{ // haven't got to the formatting part yet
if (*p == '*')
{
scanf("*"); // this is what scanf() does, ignoring
return; // both the format and the input
}
if (*p == '%')
{
scanf("%%"); // this is what scanf() does, ignoring
return; // both the format and the input
}
i = strlen(format);
format[i++] = *p; // add the string as it is
format[i] = '\0';
continue; // go to next for() iteration
} // here *p == '%' or format[1] != '\0'
switch(*++p) // after ++p, p points to print format
{
case '*':
scanf("*"); // this is what scanf() does, ignoring
return; // both the format and the input
case '%':
scanf("%%"); // this is what scanf() does, ignoring
return; // both the format and the input
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
field = TRUE;
i = strlen(format);
format[i++] = *p;
p++;
while (isdigit(*p))
{
format[i++] = *p;
p++;
}
format[i] = '\0';
p--; // p is incremented at the end of for()
p--; // and at the beginning of switch()
break;
case 'c':
cval = va_arg(ap, char*); // next unnamed arg (char *)
scanf("%c", cval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'h':
strcat(format, "h");
p++;
i = strlen(format);
format[i++] = *p; // char after 'h'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
shval = va_arg(ap, short*); // next unnamed arg
scanf(format, shval); // short integer
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{ // take next unnamed argument as short unsigned int *
shuval = va_arg(ap, short unsigned*); // short unsigned int *
scanf(format, shuval); // short unsigned int *
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'd': case 'i': case 'o': case 'x': case 'X':
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
ival = va_arg(ap, int*); // next unnamed arg (int*)
scanf(format, ival);
field = FALSE, format[1] = '\0'; // reset
break;
case 'u':
strcat(format, "u");
uval = va_arg(ap, unsigned*);
scanf(format, uval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'l':
strcat(format, "l");
p++;
i = strlen(format);
format[i++] = *p; // char after 'l'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
lval = va_arg(ap, long*);
scanf(format, lval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
luval = va_arg(ap, long unsigned*);
scanf(format, luval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if(*p == 'l')
{
p++;
i = strlen(format);
format[i++] = *p; // char after 'll'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long*);
scanf(format, llval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned*);
scanf(format, lluval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
dval = va_arg(ap, double*);
scanf(format, dval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
fval = va_arg(ap, float*);
scanf(format, fval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'L':
strcat(format, "L");
p++;
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long*);
scanf(format, llval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned*);
scanf(format, lluval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
ldval = va_arg(ap, long double*);
scanf(format, ldval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 's':
strcat(format, "s");
sval = va_arg(ap, char *);
scanf(format, sval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'p':
strcat(format, "p");
vp = va_arg(ap, void *);
scanf(format, vp);
field = FALSE, format[1] = '\0'; // reset
break;
default:
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
printf("Unknown format: \"%s\"\n", format);
return;
} // end of switch()
} // end of for()
va_end(ap); // clean up when done
}
/*
gcc minscanf.c -o minscanf
./minscanf
greeting: // Enter
msg: "hola"
greeting: halo
msg: "halo"
greeting: hello
msg: "hell"
char: d
msg[0]: 'd'
msg: "dell"
short: -1
unsigned: +1
float: -.2
-1, 1, -0.200000
day: 03
month: 08
year: 2023
day/month/year: 3/8/2023
float: 123456.123456
double: -123456789.123456789
double: +1234567890.123456789
1.234561e+05, -123456789.123457, 1.23457e+09
1.234561E+05, -123456789.123457, 1.23457E+09
long double: -1234567890123456789.123456789
long double: +12345678901234567890.123456789
-1234567890123456789.125000, 1.23457e+19
-1234567890123456789.125000, 1.23457E+19
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 7-5. Rewrite the postfix_calculator of Chapter_4 to use scanf() and/or sscanf() to do the input and number conversion.
1 2 +
1 2 * 3 + 5 -
-1 2 +
-1 -2 -
4 3 %
2 0 %
1 3 /
1 0 /
#include <stdio.h> // for getchar(), ungetc(), printf(), stdin,
// scanf(), sscanf(), EOF
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getop(char *); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2;
double op1, op2; // operands
char s[MAXOP]; // operand or operator
while((type = getop(s)) != EOF)
{ // nonempty line ending with EOF will not be executed
switch(type)
{
case NUMBER :
sscanf(s, "%lf", &op1);
push(op1);
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conv from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
case '\n' :
printf("\t%.8g\n", pop()); // top of stack
break;
default :
printf("Unknown command: %s\n", s);
break;
}
}
return 0;
}
#define MAXVAL 100 // stack size
double val[MAXVAL]; // value stack
double *sp = val; // stack pointer (*val is top of stack)
void push(double f) // push f on (top of) stack
{
if (sp < val+MAXVAL) {*sp++ = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > val) {return *--sp;}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getop(char *s) // get next operator or numeric operand
{
int c;
// skip beginning whitespace (' ', '\t')
while ((*s = c = getchar()) == ' ' || c == '\t')
{} // *s is not ' ' or '\t', but could be '\n' or EOF
*(s+1) = '\0'; // end string
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
{return c;} // not a number, probably an operator (or '\n' or EOF)
// here c is digit or '.' or '+' or '-'
if (c == '+' || c == '-') // unary or binary sign
{
c = getchar();
if (!isdigit(c) && c != '.')
{
ungetc(c, stdin); // push c back on standard input
return *s; // binary '+' or '-'
}
else // c is digit or '.'
{
ungetc(c, stdin); // digit or '.'
if (*s == '-') {ungetc(*s, stdin);} // s[0] == '-'
// if (*s == '+') {} // ignore '+' sign
}
}
else{ungetc(*s, stdin);} // digit or '.'
scanf("%s", s);
return NUMBER;
}
/*
gcc calc1.c -o calc1
./calc1
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./calc1 < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), printf(), sscanf(), EOF
#define MAXLINE 1000 // max line length
#define MAXOP 100 // max size of operand or operator
#define NUMBER '0' // signal that a number has been found
int getLine(char *, int); // getline() is declared in stdio.h
char line[MAXLINE];
int n; // no of chars read by sscanf()
char *lp; // line pointer (current position on line)
int getop(char *); // get the next operand or operator
void push(double); // push operand on stack
double pop(void); // pop operand from stack
int main()
{
int type, i1, i2, len;
double op1, op2; // operands
char s[MAXOP]; // operand or operator
while((len = getLine(line, MAXLINE)) > 0)
{ // nonempty line ending with EOF will not be executed
lp = line;
while(sscanf(lp, "%s%n", s, &n) == 1) // until end of line
{ // %n - number of chars read
lp += n;
type = getop(s);
switch(type)
{
case NUMBER :
sscanf(s, "%lf", &op1);
push(op1);
break;
case '+' :
push(pop() + pop());
break;
case '-' :
op2 = pop();
push(pop() - op2);
break;
case '*' :
push(pop() * pop());
break;
case '/' :
op2 = pop();
if (op2 != 0.0)
{push(pop() / op2);}
else {printf("Error: zero divisor\n");}
break;
case '%' :
i2 = pop(); // automatic conversions
i1 = pop(); // from double to int
if (i2 != 0.0)
{push(i1 % i2);} // auto conv from int to double, arg of push()
else {printf("Error: zero divisor\n");}
break;
default :
printf("Unknown command: %s\n", s);
break;
} // end of switch()
} // end of inner while()
printf("\t%.8g\n", pop()); // top of stack
} // end of outer while()
return 0;
} // end of main()
// getLine(): read a line into s, return length
int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if --lim > 0:
for (p = s; (--lim > 0) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n' or not, s[lim-1]='\0'
*p = c;
}
if (c == '\n') // i < (lim-1), getchar() executed
{
*p++ = c; // '\n'
}
*p = '\0'; // the null character ends a string
return p-s; // max(p-s) == (lim-1), assuming (lim-1) > 0
}
#define MAXVAL 100 // stack size
double val[MAXVAL]; // value stack
double *sp = val; // stack pointer (*val is top of stack):
void push(double f) // push f on (top of) stack
{
if (sp < val+MAXVAL) {*sp++ = f;}
else {printf("Error: stack full, can't push %g\n", f);}
}
double pop(void) // pop and return top value from stack
{
if (sp > val) {return *--sp;}
else
{
printf("Error: stack empty\n");
return 0.0;
}
}
#include <ctype.h> // for isdigit()
int getop(char *s) // get next operator or numeric operand
{
if (!isdigit(*s) && *s != '.' && *s != '+' && *s != '-')
{return *s;} // not a number, probably an operator (or '\n')
// here *s is digit or '.' or '+' or '-'
if (*s == '+' || *s == '-') // unary or binary sign
{
s++;
if (!isdigit(*s) && *s != '.')
{
s--;
return *s; // binary '+' or '-'
}
else // *s is digit or '.'
{
return NUMBER;
}
}
else{return NUMBER;} // *s is digit or '.'
}
/*
gcc getcalc.c -o getcalc
./getcalc
1 2 +
3
1 2 + 3 * 4 /
2.25
-1 2 +
1
-1 -2 +
-3
-1 2 + 3 *
3
2 0 /
Error: zero divisor
2 // pop() called by '\n' returns first operand, still on stack
1 2 /
0.5
2 3 %
2
4 2 %
0
4 1 %
0
4 3 %
1
4 0 %
Error: zero divisor
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
a b +
Unknown command: a
Unknown command: b
Error: stack empty // nothing pushed, pop() called by +
Error: stack empty // pop() called by '\n'
0 // value returned by pop() for an empty stack
1 2 9
9 // pop() called by '\n'
+
3 // 1 + 2
1 2 c
Unknown command: c
2 // pop() called by '\n'
3 +
4 // 1 + 3
CTRL^D (EOF) or CTRL^C in Linux, CTRL^Z + Enter in Windows
./getcalc < compute.txt
3 // 1 2 +
0 // 1 2 * 3 + 5 -
1 // -1 2 +
1 // -1 -2 -
1 // 4 3 %
Error: zero divisor // 2 0 %
Error: stack empty // nothing pushed, '\n' calls pop():
0 // value returned by pop() for an empty stack
0.33333333 // 1 3 /
Error: zero divisor // 1 0 /
1 // pop() called by '\n' returns first operand, still on stack
*/