Storing arithmetic operators in an array in C? - c

I am just wondering if it is possible to store the basic arithmetic operators (+, -, *, /) inside variables in C. The reason that I need to do this is because I am trying to build a basic calculator program that accepts up to 5 numbers and can do any of these operations on them. Right now the only way that I have been able to come up with to do this is to store the operators inside a char array and then iterate through it using for loops and switch statements to decide what operator to use for each step. It's pretty clunky and doesn't actually work right now and I am not sure why. Also even if it did work, it wouldn't follow order of operations which I need it to do as well.
This is an example of the output of my program:
Enter a number: 4
Enter an operator (+, -, *, /, or =): +
Enter a number: 8
Enter an operator (+, -, *, /, or =): -
Enter a number: 7
Enter an operator (+, -, *, /, or =): *
Enter a number: 9
Enter an operator (+, -, *, /, or =): /
Enter a number: 2
4.00 + 8.00 - 7.00 * 9.00 / 2.00
0.500000
-6.500000
-6.500000
-3.250000
-3.250000
Result: -3.25
[Finished in 24.13s]
The first 9 lines are just taking the input for the numbers and operators, the 10th line prints out the numbers and operators entered in order, the 11th - 15th lines are supposed to print out the result after each operation which you can see are all incorrect, and the final line prints out the result. What do you think might be causing the math to be incorrect?
Here is my code at the moment:
#include <stdio.h>
#include <stdlib.h>
int main() {
double nums[5];
char operators[5];
double result;
int i = 0;
while ((i <= 4) && (operators[i - 1] != '=')) {
/* Getting the user's input */
printf("Enter a number: ");
scanf("%lf", &nums[i]);
if (i == 4) {
operators[4] = '=';
} else {
printf("Enter an operator (+, -, *, /, or =): ");
scanf(" %c", &operators[i]);
}
i++;
}
printf("%.2f %c %.2f %c %.2f %c %.2f %c %.2f\n", nums[0], operators[0], nums[1], operators[1], nums[2], operators[2], nums[3], operators[3], nums[4]);
for (i = 0; i <= 4; i++) {
/* Doing the math */
if (i == 0) {
/* Getting the value of the first two numbers */
switch(operators[i]) {
case '+' :
result = nums[0] + nums[1];
case '-' :
result = nums[0] - nums[1];
case '*' :
result = nums[0] * nums[1];
case '/' :
result = nums[0] / nums[1];
}
printf("%f\n", result);
} else {
/* Iterating through the rest of both arrays and
continuing to perform operations on the result */
switch(operators[i]) {
case '+' :
result = result + nums[i + 1];
case '-' :
result = result - nums[i + 1];
case '*' :
result = result * nums[i + 1];
case '/' :
result = result / nums[i + 1];
}
printf("%f\n", result);
}
}
// Printing out the answer rounded to 2 decimal points
printf("Result: %.2f", result);
return 0;
}
So just to re-iterate my question, is there a way that I could store the operators in a variable as operators instead of chars, which would remove the need for all of the loops, if statements, and switch statements, and if not, what changes should be made to make my code work properly?
P.S. I am only just learning C right now so suggestions for how I should be formatting my code are welcome too.

First the bugs:
while ((i <= 4) && (operators[i - 1] != '=')) {
On the first iteration of this loop i is 0 so operators[i - 1] attempts to read before the start of the array. Reading outside of array bounds is undefined behavior.
The incorrect values you're getting is because there's no break statement between each of your switch cases. Without that, the code "falls through" to the next case. So if the operation is subtraction you do that, then multiplication, then division.
Regarding the operators, you can create functions to encapulate each operator, each with the same signature (i.e. return type and number/type of parameters) along with a matching typedef. Then you can have an array of pointers to these functions, and set them to point to the proper function.
Also, you don't need to have a special case for the first set of operators. Just start from index 1 instead of 0 and initialize the result to the first value.
#include <stdio.h>
#include <stdlib.h>
double op_add(double x, double y)
{
return x + y;
}
double op_sub(double x, double y)
{
return x - y;
}
double op_mul(double x, double y)
{
return x * y;
}
double op_div(double x, double y)
{
return x / y;
}
typedef double (*op_type)(double, double);
int main() {
double nums[5];
char operator;
op_type operators[5];
double result;
int i = 0;
while (i < 5) {
/* Getting the user's input */
printf("Enter a number: ");
scanf("%lf", &nums[i]);
if (i == 4) {
operators[i] = NULL;
} else {
printf("Enter an operator (+, -, *, /, or =): ");
scanf(" %c", &operator);
switch(operator) {
case '+' :
operators[i] = op_add;
break;
case '-' :
operators[i] = op_sub;
break;
case '*' :
operators[i] = op_mul;
break;
case '/' :
operators[i] = op_div;
break;
default :
operators[i] = NULL;
break;
}
}
if (!operators[i]) break;
i++;
}
result = nums[0];
for (i = 1; i < 5; i++) {
if (operators[i-1]) {
result = operators[i-1](result, nums[i]);
printf("%f\n", result);
} else {
break;
}
}
// Printing out the answer rounded to 2 decimal points
printf("Result: %.2f", result);
return 0;
}

Related

Am i doing a good job? I seem to have a lot of errors

int main() {
double num1, num2;
char f1;
printf("What to Count:");
scanf_s("%f", &num1);
scanf_s("%c", &f1);
scanf_s("%f=", &num2);
if (f1 = "+") {
printf("%lf\n", num1 + num2);
}
else if (f1 = "-") {
printf("%lf\n", num2 - num2);
}
else if (f1 = "*") {
printf("%lf\n", num1 * num2);
}
else if (f1 = "/") {
printf("%.2f\n", num1 / num2);
}
else if (f1 = "%") {
printf("%lf\n", num1 % num2);
}
else if (f1 = "#") {
printf("%lf\n", num1 ^ num2);
}
else {
printf("Invalid!\n");
}
system("pause");
return 0;
}
mvs said "a value of type "const char* " cannot be assigned to an entity of type "char"
"expression must have integral or unscoped enum type" etc.
You should get way more compiler warnings:
scanf_s("%f", &num1); here you have a parameter type mismatch. For double you need %lf. Fun fact: For printf("%lf\n", num1 + num2); you don't need the extra l as float parameters are passed as double anyway.
Same for scanf_s("%f=", &num2);. In this call you also require the user to enter = after the number.
scanf_s("%c", &f1); The scanf_s function requires an extra argument for %c format specifier: a value of type rsize_t indicating the size of the receiving array
if (f1 = "+") This is an assignment instead of a comparison. Use == instead.
That is also wrong type. "+" is a string while you only want to compare a character. That would be '+'.
As Jabberwocky pointed out, you are using all kind of functions without including the required headers. Don't do this.
printf("%lf\n", num1 ^ num2); What is this expression supposed to do? Bitwise XOR operator (^) is not allowed to be used with double values.
Same with printf("%lf\n", num1 % num2); The module operator mustn't be used with double values.
Additionally, you should always check return value of scanf and related function. Otherwise how would you know about errors?
From the operations that are not valid for double I assume you are supposed to use int instead.
As you do not use the lengh field of scanf_s you couls also use the standard functions instead.
A fixed version of your code could look like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main(void) {
int num1, num2;
char f1;
printf("What to Count:");
scanf("%d", &num1);
scanf("%c", &f1);
scanf("%d=", &num2);
int result = 0;
bool invalid = false;
if (f1 == '+') {
result = num1 + num2;
}
else if (f1 == '-') {
result = num1 - num2;
}
else if (f1 == '*') {
result = num1 * num2;
}
else if (f1 == '/') {
result = num1 / num2;
}
else if (f1 == '%') {
result = num1 % num2;
}
else if (f1 == '#') {
result = num1 ^ num2;
}
else {
invalid = true;
}
if (invalid)
{
printf("Invalid!\n");
}
else
{
printf("%d\n", result);
}
system("pause");
return 0;
}
I moved the printing into one place. That would make it easier to change type of calculations.
Output (in WSL):
What to Count:3+5=
8
sh: 1: pause: not found
Confusing assignment and equality operator:
Single '=' is used for assigning a value. For example char a = 5;
This assigns a value of 5 to the character variable a.
Double '==' is used for comparison, or checking equality. For example in this case, you have used single '=' in the conditions, which as you now know is an assignment operator. Replace it with a '=='.
Not including the header files:
The functions like printf and scanf are predefined in the header file <stdio.h>. Without including this, your compiler wouldn't recognize what print and scanf means.
Not checking input validity:
When prompting the user for input, always check the return value of scanf. Consider your users stupid, or even hostile who wants to find a way to crash your program. What if I were to enter 'asdf' when you asked for a character and vice versa? Scanf is a powerful function, but it was meant for parsing, not getting input as such.
Confusing '' and " ":
' ' is for a char variable, whereas " " is for a string variable. You've declared f1 as a character variable after main, not a string variable.
Indentation:
The curly braces are not in their right places. And you may as well omit them when the conditions only contain a single line of code.
Format specifier for double variable:
The format specifier for a double variable in the scanf statement is %lf, whereas a %f is used while printing.
You've also included a '=' operator in the third scanf statement. That could also render the program to work improperly.
int main(void)
{
double num1, num2;
char f1;
printf("What to Count:");
scanf_s("%lf", &num1);
scanf_s("%c", &f1);
scanf_s("%lf", &num2);
double resultdivide = num1 / num2;
double resultpow = pow(num1, num2);
double resultplus = num1 + num2;
double resultminus = num1 - num2;
double resultmult = num1 * num2;
if (f1 == '+') {
printf("%.0f\n",resultplus);
}
else if (f1 == '-') {
printf(".0f\n", resultminus);
}
else if (f1 == '*') {
printf("%.0f\n", resultmult);
}
else if (f1 == '/') {
printf("%.2f\n", resultdivide);
}
else if (f1 == '#') {
printf("%.0f\n", resultpow);
}
else {
printf("Invalid!\n");
}
system("pause");
return 0;
}
this is what i've come up with after brainstorming
looks messy but it actually works so im fine with it
but still can't figure out how to add the % function D:

Recall the char function

I'm very new to programming, and I'm doing a simple bot in C, that has a calculator function. I'm having some trouble in this piece of code:
char operation = get_char("Insert the mathematical operation: ");
float x = get_float("X: ");
float y = get_float("Y: ");
if (operation == 43)
{
float result = (x + y);
int rresult = round(result);
printf("X + Y = %i\n", rresult);
string confirmation = get_string("Need to do something more? ");
if (strcmp(confirmation, "Y") == 0)
{
return operation;
}
As you can see, this calculator ask the user for a char (*, /, + or - [its everything defined in the other parts of the code, I will not post it here just to be brief] that defines the math operation and then, after doing the calculation and printing the result, asks the user if he wants to do more calculations. If the answer is "Y" (yes), I want to restart this piece of code, asking for the char and the floats, and doing everything. I want to know the simplest way to do this, without making the code looks bad designed.
Also, I'm using CS50 IDE.
I don't have CS50, therefore, plain C. The construct you might want to use is a do-while loop.
#include <stdio.h>
#include <math.h>
char get_char(char * msg) {char c; printf("%s", msg); scanf(" %c", &c); return c;}
float get_float(char * msg) {float f; printf("%s", msg); scanf(" %f", &f); return f;}
int main() {
char confirmation = 'n';
do {
char operation = get_char("Insert the mathematical operation: ");
float x = get_float("X: ");
float y = get_float("Y: ");
if (operation == '+') {
float result = (x + y);
printf("Result in float: %f\n", result);
int rresult = round(result);
printf("X + Y = %i\n", rresult);
}
confirmation = get_char("Need to do something more [y/n]? ");
} while (confirmation == 'y');
return 0;
}
$ gcc -Wall dowhile.c
$ ./a.out
Insert the mathematical operation: +
X: 0.11
Y: 0.88
Result in float: 0.990000
X + Y = 1
Need to do something more [y/n]? y
Insert the mathematical operation: +
X: 0.1
Y: 0.1
Result in float: 0.200000
X + Y = 0
Need to do something more [y/n]? n
$

How to convert a String to a Float in C

I have written the following code
#include <stdio.h>
#include <stdlib.h>
int main()
{
// declaration of variables as strings
char astr;
char bstr;
char cstr;
/* Input three sides of a triangle */
printf("Enter first side of triangle: ");
scanf("%s",&astr);
printf("Enter second side of triangle: ");
scanf("%s",&bstr);
printf("Enter third side of triangle: ");
scanf("%s",&cstr);
// conversion of strings to float
float a = atof(&astr);
float b = atof(&bstr);
float c = atof(&cstr);
// checking if given triangle is valid
if((a + b > c) && (a + c > b) && (b + c > a))
{
// Checking for special cases of triangle
if(a==b && b==c)
{
/* If all sides are equal */
printf("Equilateral triangle.");
}
else if(a==b || a==c || b==c)
{
/* If any two sides are equal */
printf("Isosceles triangle.");
}
else
{
/* If none sides are equal */
printf("Scalene triangle.");
}
}
else
{
printf("Triangle is not valid. \n");
}
printf("%f \n", a);
printf("%f \n", b);
printf("%f \n" ,c);
return 0;
}
However when I run it, I get "Triangle is not valid" despite the fact that mathematically the triangle would be valid
When printing the Values stored in a b and c I discover that only the Value for c is stored correctly but a and b are always 0.000000
what have I done wrong?
Thanks in advance
instead of 3 wrong lines:
char astr;
scanf("%s",&astr);
float a = atof(&astr);
let me propose working lines:
char astr[20]; // should be enough
scanf("%19s",astr); // 19 protects from buffer overflow on astr
float a = atof(astr);
First, you cannot scan a string into a char: not enough room / undefined behaviour. Pass a char array instead (and in that case drop the &, it's already an address)
Second, pass the string to atof, not the pointer on the string.
Aside: atof doesn't check for errors, better use strtof which provides (optional) error checking.
int main () {
float val;
char str[10];
strcpy(str, "1234");
val = atof(str);
printf("%f", val);
return 0;
}
You can also use strtod() refer man page of atof()

C program: Simple math program

Want to print for example
Grade: 4/5
80 percent
Program ask a user how many math problems they want to solve and prints out the number of "wrongs/the number of rights" and their grade. I think I dont have my math right at the end of the code cause its printing out for example:
Grade: 4/5
-7446528 percent
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# include <stdio.h>
int main()
{
int NumberOfTimes, AddAns, SubAns, AddCorrect=0, SubCorrect=0, CorrectAnsAdd, CorrectAnsSub, TotalCorrect, TotalWrong, Add;
int i,a,b,c,d,e,f,g;
float percent;
printf("\n");
printf("-------------------MATH QUIZ------------------------\n");
printf("Enter the number of Math problems you want to solve:"); //enters the # of problems the program produces
scanf("%d", &NumberOfTimes);
printf("\n");
srand(time(NULL));
//Random number generator
for (i=0;i<NumberOfTimes;++i)
{
b = rand() %3 + 1;
c = rand() %3 + 1;
a = rand() %2 + 1;
//Random addition problems
if (a == 1)
{
printf("%d + %d = ", b,c);
scanf("%d", &AddAns);
d = b + c;
if (AddAns == d)
{
printf(" +Correct\n");
AddCorrect = AddCorrect + 1;
}
//Random subtraction problems
else
{
printf(" +Wrong, it was %d\n", d);
AddIncorrect = AddIncorrect + 1;
}
}
if (a == 2)
{
printf("%d - %d = ", b,c);
scanf("%d", &SubAns);
g = b - c;
//Produces right or wrong answers
if (SubAns == g)
{
printf(" +Correct\n");
SubCorrect = SubCorrect + 1;
}
else
{
printf(" +Wrong, it was %d\n", g);
SubIncorrect = SubIncorrect + 1;
}
}
}
//Producing the output to wrong/right numbers and grade percentage
TotalCorrect = AddCorrect + SubCorrect;
printf("\n");
printf("Grade: %d/%d\n",TotalCorrect,NumberOfTimes);
printf("\n");
percent=NumberOfTimes/TotalCorrect;
printf("%d percent \n", percent);
return 0;
}
There are a few things going on. First, to print a float with printf, use %f. %d is for ints.
Secondly, when you calculate percent, you're accidentally using integer division. Since NumberOfTimes and TotalCorrect are both integers, NumberOfTimes/TotalCorrect performs integer division and produces an int. It's only converted to a float after the whole initializing expression is evaluated. Use this instead:
percent = (float)TotalCorrect / NumberOfTimes;
// OR, if you want an actual percent:
percent = 100.0f*TotalCorrect/NumberOfTimes;
Then, using %f:
printf("%f percent\n", percent); // "80.000000 percent"
Note that this will display the percentage out to many decimal places; if you want a cleaner display without a decimal point, you could just calculate the percent as an int:
// multiply before dividing to avoid integer division problems
int percent = 100*TotalCorrect/NumberOfTimes;
printf("%d percent\n", percent); // "80 percent"
Hope this helps!
In C, dividing two integers won't get you a floating point number, even if the assignment is to a float. It's just how the language works. You'll have to cast NumberOfTimes and TotalCorrect as floats.
So replace
percent=NumberOfTimes/TotalCorrect; with
percent=(float)TotalCorrect/(float)NumberOfTimes * 100;
Furthermore, you're trying to print a float as an integer in the line
printf("%d percent \n", percent);
which is giving you a wonky result. Instead, try:
printf("%d percent \n", (int)percent);

Printf Problem with While Loop

I'm creating a temperature converter in C. Basically, you input a minimum and maximum value in degrees Celsius, along with a step, and it displays that information in a list, along with the Fahrenheit equivalent. On some occasions, I have noticed the last Fahrenheit entry not being displayed when it should. For example, when you input a lower limit of 10, a higher limit of 30, and a step of 4, it cuts off the last Fahrenheit temperature. I know it's something to do with the last while loop, but I just can't figure it out.
#include <stdio.h>
int main (int argc, const char * argv[]) {
double l, h, s;
double lf, hf, sf;
/* Number rows in tables */
int num1, num2;
num1 = 1;
num2 = 1;
/* Lower limit input */
printf("Please give a lower limit: ");
scanf("%4lf", &l);
while (l < 0) {
printf("Lower limit must be greater than 0: ");
scanf("%4lf", &l);
}
/* Stores value for Fahrenheit conversion */
lf = l;
/* Higher limit input */
printf("Please give a higher limit: ");
scanf("%4lf", &h);
while (h <= l) {
printf("Higher limit must be greater than lower limit: ");
scanf("%4lf", &h);
}
while (h >= 50000) {
printf("Higher limit must be less than 50000: ");
scanf("%4lf", &h);
}
hf = h;
/* Step input */
printf("Please input step: ");
scanf("%4lf", &s);
while (s <= 0) {
printf("Step must be greater than 0: ");
scanf("%4lf", &s);
}
while (s >= h - l) {
printf("Step must be less than the difference in temperatures: ");
scanf("%4lf", &s);
}
sf = s;
/* Celsius table */
printf("\nCelsius\n-------\n");
while (l <= h) {
printf("%i. %4lf\n", num1, l);
num1++;
l = l + s;
}
/* Fahrenheit table */
printf("\nFahrenheit\n----------\n");
/* Converts Celsius to Fahrenheit */
lf = (lf * 1.8) + 32;
hf = (hf * 1.8) + 32;
sf = sf * 1.8;
printf("Lower input: %4lf\n", lf);
printf("Higher input: %4lf\n", hf);
printf("Step: %4lf\n----------\n", sf);
/* This while loop sometimes cuts off the last entry */
while (lf <= hf) {
printf("%i. %4lf\n", num2, lf);
num2++;
lf = lf + sf;
}
return 0;
}
The problem is with comparing the doubles, you might get into a situation where something like 10 + 1.8 evaluates to 11.800000001 and thus missing the end value.
The solution to your problem would be to first calculate the number of steps:
int steps = (h - l) / s + 1; //Might want to apply rounding
And then use a for/while loop over the integer variable instead:
for (int i = 0; i < steps; ++i) {
double t = l + (h - l) * i / (steps - 1);
}
for (int i = 0; i < steps; ++i) {
double tf = lf + (hf - lf) * i / (steps - 1);
}
while (lf <= hf)
You are comparing Double values, You will face problems of Precison & Rounding Errors, Most likely that causes the last iteration to not execute at all.
This answer of mine, should be a good read.
Choose a precision and compare it with the difference between hf and lf(abs value).
Also keep in mind with a random fixed step you will not always reach the top value of the interval. it might work if step divides h-l but it won't work otherwise.
Directly after your last while loop, add the following code (and don't forget to #include assert.h):
printf("lf = %f, hf = %f\n", lf, hf);
assert(lf == hf);
you should get this output:
Celsius
-------
1. 10.000000
2. 14.000000
3. 18.000000
4. 22.000000
5. 26.000000
6. 30.000000
Fahrenheit
----------
Lower input: 50.000000
Higher input: 86.000000
Step: 7.200000
----------
1. 50.000000
2. 57.200000
3. 64.400000
4. 71.600000
5. 78.800000
lf = 86.000000, hf = 86.000000
Assertion failed: lf == hf, file randomdudescode.c, line 77
Which is incredibly confusing, because obviously lf == hf.
This illustrates one of the quirks of C and floating point tomfoolery in general. You have to deal with rounding errors and imprecision.

Resources