Right now I am learning to program in c by reading the book "Programming in C, 3rd edition" by Stephen Kockan.
Exercise6-4 in the book is really giving me a headache. In the book it says:
Write a program that acts as a simple "printing" calculator.
The program should allow the user to type in expressions of the form
number operator
The following operatros should be recognized by the program:
'+' '-' '*' '/' 'S' 'E'
The S operator tells the program to set the "accumulator" to the
typed-in number. The E operator tells the program that execution is to
end. The arithmetic operations are performed on the content of the
accumulator with the number that was keyed in acting as the seconcd
operand.
Here is a link,to how i figured it out too.
Unfortunately it's in Objective-C(but is still the same exercise!), and I don't understand
Objective-C syntax.
UPDATE
This is what I have made so far:
// "Printing" Calculator
#include <stdio.h>
int main(void)
{
char operator;
float value, result, accumulator;
printf("Begin Calculations...\n\n");
operator = '0';
while ( operator != 'E')
{
scanf("%f %c", &value, &operator);
switch(operator)
{
case 'S':
accumulator = value;
printf("The accumulator = %f", accumulator);
break;
case '+':
result = accumulator + value;
printf("%f + %f = %f", accumulator, value, result);
break;
case '-':
break;
case '*':
break;
case '/':
break;
default:
printf("Unknown operator");
break;
}
}
printf("Calculations terminated");
return 0;
}
I can't figure out how to use the scanf() function, and read both a value for an operation and a value for the accumulator. Because those two thing may not be the same.
Here is your C code.
#include <stdio.h>
#include <conio.h>
int main (void)
{
int loop;
float value,
acc = 0;
char o;
printf ("Simple Printing Calculator Program\n\n");
printf ("\nKEY: \n+ Add \n- Subtract \n* Multiply \n/ Divide\n");
printf ("S Set Accumulator \nE End Program\n\n");
printf ("Enter a number and an operator, then press enter\n\n");
printf ("Type in your expression: ");
for ( loop=0 ; loop>-1; ++loop)
{
{
scanf ("%f %c", &value, &o);
if ( o == '+' )
{
acc = acc + value; printf ("\n%.2f\n",acc);
}
else if ( o == '-' )
{
acc = acc - value; printf ("\n%.2f\n",acc);
}
else if ( o == '*' )
{
acc = acc * value; printf ("\n%.2f\n",acc);
}
else if ( o == 'S' )
{
acc = value; printf ("\n%.2f\n",acc);
}
else if ( o == 'E' )
{
printf ("\nFinal Value: %.2f\n\nGoodbye!",acc); loop = loop + 1000;
}
else if ( o == '/' )
if ( value == 0 )
{
loop = loop - loop -100;
printf ("\nDivision by zero.\n");
}
else
{
acc = acc / value; printf ("\n%.2f\n", acc);
}
else
{
loop = loop -loop-100;
printf ("\nUnknown operator.\n");
}
}
getch ();
return 0;
}
Related
I am trying to learn c Language, and I have to create a calculator, the thing is, if I don't type anything and press the enter key it should print out an error, I have tried to do it with scanf but it is not working.
#include <stdio.h>
#include <stdlib.h>
int main()
{
float a,b,c;
char op;
int q=1;
while(q=1){
scanf("%f%c%f",&a,&op,&b);
if (scanf("%f%c%f",&a,&op,&b)=='\n')
{
printf("error");
}
switch (op)
{
case '+':c=a+b;
break;
case '-':c=a-b;
break;
case'*':c=a*b;
break;
case'/':c=a/b;
break;
default:printf("error");
q=2;
break;
}
{printf("%f\n",c);}
}}
Try to scan for a newline using a scanset %1[\n].
Another scanset %*[^\n] will scan and discard everything that is not a newline.
Another approach would be to use fgets to read a line and then parse the line with sscanf.
#include <stdio.h>
#include <stdlib.h>
int main ( void) {
char newline[2] = "";
char op = 0;
int scanned = 0;
double a = 0.0;
double b = 0.0;
double c = 0.0;
while ( 1) {
printf ( "input a number, an operator and a number\n");
printf ( " or just enter to quit\n");
if ( 1 == scanf ( "%1[\n]", newline)) { // try to scan a newline
printf ( "done\n");
break;
}
if ( 3 != ( scanned = scanf("%lf %c%lf", &a, &op, &b))) {
printf ( "bad input error\n");
printf ( "try again\n");
}
if ( EOF == scanned) {
printf ( "EOF error\n");
break;
}
scanf ( "%*[^\n]"); // scan and discard up to newline
scanf ( "%1[\n]", newline); // scan a newline
if ( 3 == scanned) {
switch (op) {
case '+':
c = a + b;
break;
case '-':
c = a - b;
break;
case '*':
c = a * b;
break;
case '/':
c = a / b;
break;
default:
printf ( "bad op error\n");
printf ( "try again\n");
op = 0;
break;
}
if ( op) {
printf ( "%f\n", c);
}
}
}
return 0;
}
I hope you are having a nice day. Thank you for taking the time to read my question.
I am still a beginner in the C language. My professor has asked me to program a scientific calculator. The calculator should be able to read and store user-defined variables and work with them. for example, I should be able to enter a=5 b=9 etc. after that the program should calculate, for instance, a+1= 6, or a+b=14 and show it to the user. Of course, the user decides if the operation is addition, subtraction, division or multiplication.
The user should also be able to enter such input: e.g. c=5+9.
I have started working on the calculator, unfortunately, I have just been able to only allow the user to define one variable at a time and work with it.
For example:
a=7
7+a=14
That's all I could do. I asked my professor for help and he keeps telling me that I have to to teach the program how to separate between what is before the "=" and what's after it.
Thank you in advance for every help or piece of advice you give
This is the code I came up with
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main() {
char situation;
float operand1, operand2;
char i = 0;
char ch;
char op;
int operand = 0;
int j, digit, number[10] = {};
int j2 = 0;
char str[100] = { 0 };
while (1) {
printf("\n\na) To calculate choose me :)");
printf("\n\nb) If you want to calculate with variables, choose me:");
printf("\n\nc) To Exit choose me :(\n\n");
scanf_s("%c", &situation, 1);
while ((getchar()) != '\n');
switch (situation) {
case 'a':
printf("type in some arithmetic terms : \n");
scanf_s("%f", &operand1);
scanf_s("%c", &op, 1);
scanf_s("%f", &operand2);
while ((getchar()) != '\n');
switch (op) {
case '+':
printf("\n\n%.2f + %.2f = %.2f\n\n", operand1, operand2, operand1 + operand2);
break;
case '-':
printf("\n\n%.2f - %.2f = %.2f\n\n", operand1, operand2, operand1 - operand2);
break;
case '*':
printf("\n\n%.2f * %.2f = %.2f\n\n", operand1, operand2, operand1 * operand2);
break;
case '/':
printf("\n\n%.2f / %.2f = %.2f\n\n", operand1, operand2, operand1 / operand2);
break;
default:
printf("\n\nERROR!\n\n");
}
break;
case 'b':
printf("\n\nTo return to the main menu please enter any capital letter of your choosing\n\n");
printf("\n\nWhen calculating with a variable, please always write the variable on the right side, Thank you. You may start:\n\n");
do {
scanf_s("%s", &str, 99);
for (i = 0; i < 100; i++) {
if (str[i] == '=') {
for (j = 0; j < strlen(str); j++) {
ch = str[j];
if (ch >= '0' && ch <= '9') {
digit = ch - '0';
number[j2] = j2 * 10 + digit;
//printf("%d", number);
}
}
scanf_s("%d", &operand);
scanf_s("%c", &op, 1);
scanf_s("%d", &number[j2]);
while ((getchar()) != '\n');
switch (op) {
case '+':
printf("\n\n%d + %c = %d\n\n", operand, str[0], operand + number[j2]);
break;
case '-':
printf("\n\n % d - % c = % d\n\n", operand, str[0], operand - number[j2]);
break;
case '*':
printf("\n\n % d * % c = % d\n\n", operand, str[0], operand * number[j2]);
break;
case '/':
printf("\n\n % d / % c = % d\n\n", operand, str[0], operand / number[j2]);
break;
default:
printf("\n\nERROR!\n\n");
}
break;
}
}
} while (islower(str[0]));
while ((getchar()) != '\n');
break;
case 'c':
printf("\n\goodbye\n\n");
exit(0);
break;
default:
printf("\n\nThis is not an acceptable input. Please Try again!");
}
}
}
There are multiple problems in your code:
int number[10] = {}; is an invalid initializer in C. You should write:
int j, digit, number[10] = { 0 };
you should use double instead of float
scanf_s("%c", &situation, 1); is not portable: the Microsoft version of this function expects the size argument 1 as an UNSIGNED whereas the Standard C function defined as optional in Annex K specifies that the size argument 1 must be passed as a size_t, hence as (size_t)1. Avoid using this function and read user input as a line with fgets() and use the standard function sscanf() instead and do test the return value to detect and report invalid and/or missing input.
Add these lines before including <stdio.h> at the top of your source file to prevent compiler warnings:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
scanf_s("%c", &op, 1); does not skip white space, such as spaces and newlines. You should write
scanf(" %c", &op);
while ((getchar()) != '\n'); is risky: this loop will run forever if the end of file occurs before a newline can be read.
instead of j < strlen(str), which may rescan the string at every iteration, you should write:
for (j = 0; str[j] != '\0'; j++)
i is used as an index, it should have type int or size_t, not char.
the format string in printf("\n\n % d - % c = % d\n\n", ...); is incorrect: the space between the % and the c is not supported. You probably meant to write this anyway:
printf("\n\n%d - %c = %d\n\n", operand, str[0], operand - number[j2]);
printf("\n\goodbye\n\n"); is incorrect: \g is an invalid escape sequence. You should write:
printf("\n\nGoodbye\n\n");
Here is a modified version using functions to parse the line and handle variable assignment separately from evaluating expressions:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 26 global variables */
double variables['z' - 'a' + 1];
/* the function skip_spaces() updates `*pos`, skipping any white
* space in `str` at the corresponding index
*/
void skip_spaces(const char *str, int *pos) {
while (isspace((unsigned char)str[*pos]))
*pos += 1;
}
/* the function trim_spaces() updates `*pos`, skipping any white
* space in `str` at the corresponding index. In addition, it
* removes trailing white space from the string, ie: newlines,
* spaces, TABs and other white space characters
*/
void trim_spaces(char *str, int *pos) {
int len = strlen(str);
while (len > *pos && isspace((unsigned char)str[len - 1]))
str[--len] = '\0';
skip_spaces(str, pos);
}
/* the function parse_operand() reads the next operand from `str`
* at index `*pos`. It recognises floating point numbers and
* variable names, which are replaced with their value. The value is
* stored into `*value`. `*pos` is updated past the operand and any
* white space after it.
*/
int parse_operand(char *str, int *pos, double *value) {
char *endp;
skip_spaces(str, pos);
char ch = str[*pos];
if (ch >= 'a' && ch <= 'z') {
*value = variables[ch - 'a'];
*pos += 1;
skip_spaces(str, pos);
return 1; // variable
}
*value = strtod(str + *pos, &endp);
if (endp > str + *pos) {
*pos = endp - str;
skip_spaces(str, pos);
return 2; // number
}
return 0;
}
/* parse_expression: parse an expression with basic operators,
* no precedence: the function expects at least one operand and
* keeps parsing and evaluating as long as there is a supported
* operator that follows. The result is stored into `*result`.
*/
int parse_expression(char *str, int *pos, double *result) {
double operand2;
char op;
if (!parse_operand(str, pos, result)) {
printf("missing operand: %s\n", str + *pos);
return 0;
}
while ((op = str[*pos]) == '+' || op == '-' || op == '*' || op == '/' || op == '%') {
*pos += 1;
if (!parse_operand(str, pos, &operand2)) {
printf("missing operand: %s\n", str + *pos);
return 0;
}
switch (op) {
case '+':
*result += operand2;
break;
case '-':
*result -= operand2;
break;
case '*':
*result *= operand2;
break;
case '/':
*result /= operand2;
break;
case '%':
*result = fmod(*result, operand2);
break;
}
}
return 1;
}
int main() {
char str[100];
printf("type some expressions:\n");
while (fgets(str, sizeof str, stdin)) {
double result, result2;
int pos = 0;
/* strip trailing whitespace, skip initial whitespace */
trim_spaces(str, &pos);
if (!str[pos]) {
/* stop on empty line */
break;
}
/* test for a variable assignment */
if (str[pos] >= 'a' && str[pos] <= 'z' && str[pos + 1] == '=') {
/* variable assignment */
int v = str[pos] - 'a';
pos += 2;
if (parse_expression(str, &pos, &result) && !str[pos]) {
variables[v] = result;
printf("%s -> %.2f\n", str, result);
} else {
printf("invalid expression: %s\n", str);
}
} else {
/* other expression */
if (parse_expression(str, &pos, &result)) {
skip_spaces(str, &pos);
if (str[pos] == '\0') {
printf("%s -> %.2f\n", str, result);
} else
if (str[pos] == '=') {
/* comparison of expressions */
pos += 1;
if (parse_expression(str, &pos, &result2) && !str[pos]) {
if (result == result2) {
printf("%s -> true (%.2f == %.2f)\n", str, result, result2);
} else {
printf("%s -> false (%f != %f, delta: %e)\n",
str, result, result2, result2 - result);
}
} else {
printf("invalid expression: %s\n", str);
}
} else {
printf("invalid syntax: %s\n", str);
}
}
}
}
return 0;
}
Output:
b=2/3
b=2/3 -> 0.67
2/3=b
2/3=b -> true (0.67 == 0.67)
20/3=10*b
20/3=10*b -> false (6.666667 != 6.666667, delta: -8.881784e-16)
#include <stdio.h>
#include <rpcndr.h>
int main() {
boolean playAgain=1;
char playInput;
float num1,num2,answer;
char operator;
while (playAgain){
printf("Enter First Number, operator, second number:");
scanf("%f%c%f",&num1,&operator,&num2);
switch (operator) {
case '*':
answer=(num1*num2);
break;
case '/':
answer=(num1/num2);
break;
case '+':
answer=num1+num2;
break;
case '-':
answer=num1-num2;
break;
default:break;
}
printf("%f\n",answer);
printf("Do You Want To Try It Again(y/n)?");
scanf("%c",&playInput);
if(playInput=='n'){
playAgain=0;
}
}
}
Do while can do this code. But I want to why this method gets an error. And there is a problem with Scanf() function.
Error says :
Clang-Tidy: 'scanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtof' instead
There are some issues.
The first scanf won't check for syntax errors in the numbers and may leave a newline in the stream and confuse the second scanf
The second scanf may not strip the newline from the stream, so on the second loop iteration, the first scanf may have a problem.
While it might be possible to fix/contort scanf into doing what you want, I'd follow clang's warning and use strtof.
Here's the code refactored to use fgets and strtof. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>
// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
char *cp;
// output prompt to user
puts(prompt);
fflush(stdout);
do {
// get an input line
cp = fgets(buf,len,stdin);
// got EOF
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
} while (0);
return cp;
}
int
main(void)
{
float num1, num2, answer;
char *cp;
char buf[1000];
int err;
char operator;
while (1) {
cp = lineget(buf,sizeof(buf),
"Enter First Number, operator, second number:");
if (cp == NULL)
break;
// get the first number
num1 = strtof(cp,&cp);
// get the operator
// NOTE: this could be a syntax error for the first number -- we'll
// check that below in the switch
operator = *cp;
if (operator != 0)
++cp;
// get second number and check for syntax error
num2 = strtof(cp,&cp);
if (*cp != 0) {
printf("ERROR trailing '%s'\n",cp);
continue;
}
err = 0;
switch (operator) {
case '*':
answer = (num1 * num2);
break;
case '/':
answer = (num1 / num2);
break;
case '+':
answer = num1 + num2;
break;
case '-':
answer = num1 - num2;
break;
default:
err = 1;
break;
}
// we got a bad operator (or syntax error in first number)
if (err) {
printf("ERROR unknown operator '%c'\n",operator);
continue;
}
printf("%f\n", answer);
cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
if (cp == NULL)
break;
if (buf[0] == 'n')
break;
}
return 0;
}
UPDATE:
The above code will detect most errors. Here's an enhanced version that does even more explicit checking:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>
// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
char *cp;
// output prompt to user
puts(prompt);
fflush(stdout);
do {
// get an input line
cp = fgets(buf,len,stdin);
// got EOF
if (cp == NULL)
break;
// strip newline
buf[strcspn(buf,"\n")] = 0;
} while (0);
return cp;
}
int
main(void)
{
float num1, num2, answer;
char *cp;
char *bp;
char buf[1000];
int err;
char operator;
while (1) {
bp = lineget(buf,sizeof(buf),
"Enter First Number, operator, second number:");
if (bp == NULL)
break;
// get the first number
num1 = strtof(bp,&cp);
// ensure we got at least a digit
// NOTE: this will detect:
// ""
// "j"
if (cp == bp) {
printf("ERROR no first number specified\n");
continue;
}
// get the operator
// NOTE: this could be a syntax error for the first number -- we'll
// check that below in the switch
operator = *cp;
// no operator specified
if (operator == 0) {
printf("ERROR no operator specified\n");
continue;
}
// skip over the operator
bp = ++cp;
// get second number and check for syntax error
num2 = strtof(bp,&cp);
if (*cp != 0) {
printf("ERROR trailing '%s'\n",cp);
continue;
}
// we need at least one digit (e.g.):
// we want to reject: 23+ and ensure we have [at least] 23+0
// this will detect 23+k
if (cp == bp) {
printf("ERROR no second number specified\n");
continue;
}
err = 0;
switch (operator) {
case '*':
answer = (num1 * num2);
break;
case '/':
answer = (num1 / num2);
break;
case '+':
answer = num1 + num2;
break;
case '-':
answer = num1 - num2;
break;
default:
err = 1;
break;
}
// we got a bad operator (or syntax error in first number)
if (err) {
printf("ERROR unknown operator '%c'\n",operator);
continue;
}
printf("%f\n", answer);
cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
if (cp == NULL)
break;
if (buf[0] == 'n')
break;
}
return 0;
}
EDIT:
fflush is undefined behavior, you can use getchar() to clear the buffer
#include <stdio.h>
void clear_input_buffer()
{
char tmp;
do
{
tmp = getchar();
} while (tmp != '\n' && tmp != EOF);
}
int main()
{
_Bool playAgain = 1;
char playInput;
float num1, num2, answer;
char operator;
while (playAgain)
{
printf("Enter First Number, operator, second number:");
scanf("%f%c%f", &num1, &operator, & num2);
clear_input_buffer();
switch (operator)
{
case '*':
answer = (num1 * num2);
break;
case '/':
answer = (num1 / num2);
break;
case '+':
answer = num1 + num2;
break;
case '-':
answer = num1 - num2;
break;
default:
break;
}
printf("%f\n", answer);
printf("Do You Want To Try It Again(y/n)?");
scanf("%c", &playInput);
clear_input_buffer();
if (playInput == 'n')
{
playAgain = 0;
}
}
}
OLD:
You should use fflush(stdin) (if your compiler supports it, it is undefinded by c stanard) or a diffrent method to clear the input buffer, otherwise scanf will read an extra \n at the end causing it to skip the rest of the data in the buffer
#include <stdio.h>
int main() {
_Bool playAgain=1;
char playInput;
float num1,num2,answer;
char operator;
while (playAgain){
printf("Enter First Number, operator, second number:");
scanf("%f%c%f",&num1,&operator,&num2);
fflush(stdin);
switch (operator) {
case '*':
answer=(num1*num2);
break;
case '/':
answer=(num1/num2);
break;
case '+':
answer=num1+num2;
break;
case '-':
answer=num1-num2;
break;
default:break;
}
printf("%f\n",answer);
printf("Do You Want To Try It Again(y/n)?");
scanf("%c",&playInput);
fflush(stdin);
if(playInput=='n'){
playAgain=0;
}
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
This is program exercise from The C Programming Language by Kernighan and Ritchie (Chap 5).
In this program, when I use '*' as multiplication operator the the pointer **argv points to argv[0] i.e. 1st(Zeroth) argument and reads 1st character 'P' instead of '*'.
Upon execution, with arguments:
./ProgE5-10 +124 -3 * =
it returns incorrect answer instead of -372.
But if replace '*' with 'x' the program works fine.
All other operations (viz. +, -, /, =) are also working fine.
Please tell me why * makes argv to point to Program Name.
//Exercise 5-10. 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 x C+4).
//For multiplication character '*' is not working
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAXLINE 1000
#define NUMBER 0
int sign = 1;
char s[MAXLINE];
void calc (int type);
int main(int argc, char *argv[])
{
if (argc < 4)
printf("Usage: ./<programName> op1 op2 operator\n");
else
{
int i, d;
int c;
while (--argc > 0 && (c = **++argv) != '\n')
{
i = 0;
printf("\nargc = %d\tc = %c:%d", argc, c, c);
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '\n')
{
printf("\nNon-Digit: %c : ", c);
if ((c == '+' || c == '-') && isdigit(d = *++(argv[0])))
{
printf("\tSign");
sign = (c == '-') ? -1 : 1;
c = d;
goto DOWN1;
}
else
{
printf("Operator");
printf("\nRead Operator: %c\n", c);
calc(c);
goto DOWN2; //To avoid re-executing calc(Number) which
//is outside any loop in main when operator
//is read and operation is performed.
}
}
DOWN1: while (isdigit(c = *argv[0]))
{
s[i++] = c;
c = *++(argv[0]);
if (**argv == '.')
{
s[i++] = **argv;
while (isdigit(*++(argv[0])))
s[i++] = **argv;
}
s[i] = '\0';
printf("\ns[] = %s", s);
}
calc(NUMBER); //Outside while to get single push of s[]
//after reading the complete number
DOWN2: ;
}
}
return 0;
}
void push (double f);
double pop(void);
void calc (int type)
{
double op2, res;
switch(type)
{
case NUMBER:
push(sign*atof(s));
sign = 1;
break;
case '+':
push(pop() + pop());
break;
case '-':
op2 = pop();
push(pop() - op2);
break;
case '*':
push(pop() * pop());
break;
case '/':
op2 = pop();
push(pop() / op2);
break;
case '=':
res = pop();
push(res);
printf("\t\t\t||Result = %lg||\n", res);
break;
case '\n':
break;
default:
printf("\nError: Invalid Operator!\n");
break;
}
}
#define STACKSIZE 1000
double val[STACKSIZE];
int sp = 0;
void push(double f)
{
if (sp >= STACKSIZE)
printf("\nError: Stack Overflow!\n");
else
val[sp++] = f, printf("\nNum %lg Pushed to Stack\n", f);
}
double pop(void)
{
if (sp != 0)
{
double ret = val[--sp];
printf("\nNum %lg Popped from the Stack\n", ret);
return ret;
}
else
{
printf("\nError: Stack Empty!\n");
return 0.0;
}
}
Your shell (e.g. bash) is treating the * character as a glob pattern, which gets replaced with a list of files in the current directory.
$ ls
file1
file2
$ echo *
file1 file2
This is why the * in your case gets replaced with ProgE5-10, which is a file in the current directory.
If you escape the * with a backslash when running your program, or surround it in single or double quotes, this will solve the issue
$ ./ProgE5-10 +124 -3 \* =
I want to make a calculator that is capable of calculation with decimal numbers and is able to return the decimal values in their respective binary, octal or hexadecimal representation.
So far in the main method the program reads the command line and I can invoke the program by two ways.
The first way would be with 3 values:
"number1" "operator" "number2".
And the second way would be with 4 values:
"wished numeral system for the output" "number1" "operator" "number2".
Where for the wished numeral system output b would stand for for binary, o for octal and h for hexadecimal. In both ways the user should be able to input decimal, octal and hexadecimal numbers for the inputs number1 and number2.
#include "zahlen.h"
#include <stdio.h>
#include "stringTOint.h"
int main(int argc, char *argv[]) {
char o,op,sx[DIGITS+1],sy[DIGITS+1],sz[DIGITS+1];
int x,y,z;
char flag_x,flag_y;
/* 1) Read Commandline */
if (argc != 4 && argc != 5) {
printf("Aufruf: %s -o <x> <op> <y> \n",argv[0]);
return 1;
} else if(argc == 4) {
x = stringTOint(argv[1]);
op = argv[2][0];
y = stringTOint(argv[3]);
} else if(argc == 5) {
o = argv[1][0];
x = stringTOint(argv[2]);
op = argv[3][0];
y = stringTOint(argv[4]);
if(o != 'b' && o != 'o' && o != 'h') {
printf("Wrong Operation\n");
return 1;
}
}
/* 2) Solve the equation */
if(argc==4) {
printf("solve: %s %c %s \n", argv[1], op, argv[3]);
z = solve(x, op, y);
} else if(argc==5) {
printf("solve: %s %c %s \n", argv[2], op, argv[4]);
z = solve(x, op, y);
}
/* 3) Calculate the Representation of the wished Numeral System */
switch(o) {
case 'b':
intTObinaer(x, sx);
intTObinaer(y, sy);
intTObinaer(z, sz);
break;
case 'o':
intTOoctal(x,sx);
intTOoctal(y,sy);
intTOoctal(z,sz);
break;
case 'h':
intTOhexal(x,sx);
intTOhexal(y,sy);
intTOhexal(z,sz);
break;
default:
intTObinaer(x, sx);
intTObinaer(y, sy);
intTObinaer(z, sz);
break;
}
/* 4) Return the results */
printf("\n %s %d\n%c %s %d\n= %s %d\n", sx,x,op,sy,y,sz,z);
return 0;
}
The methods intTObinaer, intTOoctal and intTOhexal only differ by the base with which the decimal number gets divided.
intTObinaer(int i, char str[]) {
unsigned int zahl = i;
int j;
/* Fill Array with zeros */
int x = 0;
for (x; x < DIGITS+1; x++) {
str[x] = '0';
}
/*Calculate the Binary representation of the given Decimal integer */
for (j = DIGITS-1; j > 0; j--) {
/* This base gets changed to 8 or 16 for octal and hexal representation */
str[j] = (char) (zahl % 2) + '0';
zahl = zahl / 2;
if (zahl == 0) {
break;
}
}
/* Set the end of the Array */
str[DIGITS] = '\0';
}
The actual equation gets solved in the solve method, where the right operation for number1 and number2 gets chosen by an switchcase where the different cases can be selected by the char op that the user had input between the two numbers.
#include <stdio.h>
int solve(int x, char op, int y) {
int ergebnis = 0;
switch(op) {
case '+':
ergebnis = x + y;
break;
case '-':
ergebnis = x - y;
break;
case '*':
ergebnis = x * y;
break;
case '/':
ergebnis = x / y;
break;
case '&':
ergebnis = x & y;
break;
case '|':
ergebnis = x | y;
break;
default:
printf("Wrong input\n");
}
return ergebnis;
}
My question now is due to the fact the the user should be able to input different numeral systems(e.g. decimal, octal or hexadecimal) how can I identify the different numeral systems and then transfer them into decimal so that I can calculate the result. After that these decimal Numbers have to be converted back into the desired numeral system that the user wanted.
Looks like you only need to add two lines to do that:
#include "stdlib.h"
#define stringTOint(arg) ((int)strtol(arg,NULL,0))
Or better yet, replace those invocations of stringTOint() with corresponding strtol() invocations (and add the #include, of course).
strtol() uses the same prefixes as for C literals: 0 for octal, 0x for hex, no prefix is decimal.
I would like to suggest another approach to this problem.
Many of the parsing you perform can be performed directly by the sscanf function, the only case is the binary case that needs to be implemented differently.
The implementation follows 3 main step:
Parse the input using the sscanf function (or the ConvCharToBinfor binary values) and store the values in the variables a and b;
Perform the operation and store the result in the res variable;
Print the output result by using the printf parsing (or loop for the binary case).
An implementation would be the following:
#include<stdio.h>
#include<string.h>
typedef struct stack {
unsigned char data[32];
int size;
} stack_t;
int ConvCharToBin(char* input);
int main(int argc, char *argv[]) {
char numSys = 'd', op;
char** param = argv;
int a, b, res;
param++;
//error case
if(argc != 4 && argc != 5) {
//not a valid input
printf("Not a valid input");
return -1;
}
if(argc == 5) {
numSys = param[0][0];
param++;
}
op = param[1][0];
switch(numSys) {
case 'b':
a = ConvCharToBin(param[0]);
b = ConvCharToBin(param[2]);
break;
case 'd':
sscanf(param[0], "%d", &a);
sscanf(param[2], "%d", &b);
break;
case 'h':
sscanf(param[0], "%x", &a);
sscanf(param[2], "%x", &b);
break;
case 'o':
sscanf(param[0], "%o", &a);
sscanf(param[2], "%o", &b);
break;
default:
//no viable number system
return -1;
}
switch(op) {
case '+':
res = a + b;
break;
case '-':
res = a - b;
break;
case '/':
res = a / b;
break;
case '*':
res = a * b;
break;
case '&':
res = a & b;
break;
case '|':
res = a | b;
break;
default:
//no valid operand
printf("invalid operation\n");
return -1;
}
stack_t tmp;
tmp.size = 0;
int i;
switch(numSys) {
case 'b':
while (res) {
if (res & 1) {
tmp.data[tmp.size] = '1';
tmp.size++;
} else {
tmp.data[tmp.size] = '0';
tmp.size++;
}
res >>= 1;
}
for(i = tmp.size - 1; i >= 0; i--) {
printf("%c", tmp.data[i]);
}
printf("\n");
break;
case 'd':
printf("%d\n", res);
break;
case 'h':
printf("%x\n", res);
break;
case 'o':
printf("%o\n", res);
break;
}
return 0;
}
int ConvCharToBin(char* input) {
char* idx;
int res = 0x00000000;
for(idx = input; idx < input + strlen(input); idx++) {
res <<= 1;
if(*idx == '1') {
res |= 0x00000001;
}
}
return res;
}
The sscanf reads formatted data from a string (in you case the argv strings)
This can be parsed using the following:
%d for decimal;
%x for hexadecimal;
%o for octal.
Unfortunately there is no C standard for parsing binary using sscanf, so this is done apart using the stdout.
I would also point out that this implementation has two limitation
Input/output limited to 32 bit unsigned (so from 0 to 4294967295), but with some slight modifications it can be extended;
No error checking for the input values, this can also be easily implemented.