Reputation: 103
I've written a simple calculator app in C and it works pretty well so far but I'm missing one thing: how to ensure the user has entered an input in the correct form e.g. "6 + 7". Is there any way I can test for that?
Here is my code so far:
/*A simple calculator that can add, subtract and multiple. TODO: Division
and add error handling i.e. if not an expected input!*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char input[10];
int result;
printf("Welcome to the calculator! The available operations are +, - and *.\n");
while (1) {
printf("What would you like to calculate?\n");
fgets(input, 10, stdin); /*Getting user input in form e.g. 4 + 7*/
/*Ideally test for input should go here*/
/*Separating user input into the numbers and operators, using strtok and
space as a delimiter*/
char *firstNumber = strtok(input, " ");
char *operator = strtok(NULL, " ");
char *secondNumber = strtok(NULL, " ");
/*Converting the separated numbers to integers*/
int firstInt = atoi(firstNumber);
int secondInt = atoi(secondNumber);
if (strcmp(operator, "+") == 0) {
result = firstInt + secondInt;
} else if (strcmp(operator, "-") == 0) {
result = firstInt - secondInt;
} else if (strcmp(operator, "*") == 0) {
result = firstInt * secondInt;
} else {
printf("That ain't a valid operator sonny jim. Try again:\n");
continue;
}
printf("Your result is %d.\n", result);
int flag = 0;
while (flag == 0) {
printf("Would you like to do another calculation? (yes or no)\n");
fgets(input, 10, stdin);
if (strcmp(input, "yes\n") == 0) {
flag = 1;
} else if (strcmp(input, "no\n") == 0) {
flag = 2;
} else {
printf("That isn't a valid response. Please respond yes or no.\n");
}
}
if (flag == 2) {
break;
}
}
return 0;
}
Upvotes: 8
Views: 2047
Reputation: 4288
Not necessarily the best way, but I would use sscanf
this way:
int firstInt;
int secondInt;
char operator;
if (3 != sscanf(input, "%d %c %d %1[^\n]", &firstInt, &operator, &secondInt, &temp)) {
printf("Invalid input Billy!\n");
continue;
}
sscanf
should return 3 if it successfully read in the values from the input string. If it would return 4 that would mean it read some trailing non whitespace characters which is invalid. The added benefit of this approach is that you don't need to parse the operands elsewhere with atoi
.
Whole code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char input[10];
char temp[2];
int result;
printf("Welcome to the calculator! The available operations are +, - and *.\n");
while (1) {
printf("What would you like to calculate?\n");
fgets(input, 10, stdin); /*Getting user input in form e.g. 4 + 7*/
/*Ideally test for input should go here*/
int firstInt;
int secondInt;
char operator;
if (3 != sscanf(input, "%d %c %d %1[^\n]", &firstInt, &operator, &secondInt, temp)) {
printf("Invalid input Billy!\n");
continue;
}
if ('+'== operator) {
result = firstInt + secondInt;
} else if ('-' == operator) {
result = firstInt - secondInt;
} else if ('*' == operator) {
result = firstInt * secondInt;
} else {
printf("That ain't a valid operator sonny jim. Try again:\n");
continue;
}
printf("Your result is %d.\n", result);
int flag = 0;
while (flag == 0) {
printf("Would you like to do another calculation? (yes or no)\n");
fgets(input, 10, stdin);
if (strcmp(input, "yes\n") == 0) {
flag = 1;
} else if (strcmp(input, "no\n") == 0) {
flag = 2;
} else {
printf("That isn't a valid response. Please respond yes or no.\n");
}
}
if (flag == 2) {
break;
}
}
return 0;
}
Upvotes: 3
Reputation: 305
The first test you should do is for length. You only allow input of ten characters. That's one for the operator, two for spaces, one for the \n
, and one for the NUL
terminator. That leaves only 5 characters to be split amongst the two operands. So, if the user inputs 543 * 65
, you've already truncated the \n
. An input of 5432 * 65
, and you start losing important data. The way I would implement a length check is to search for the \n
:
if (input[0] && input[strlen(input) - 1] != '\n')
, you know the input has been truncated.† Next, you need to check for the validity of the characters. If you keep your strtok()
method, you can do input checking when you convert the string to an integer if you use the preferred function strtol()
†† with far better error checking. As for the operator, you already have checks on that. For formatting of input: check for NULL pointers. If strtok()
doesn't find a space delimiter, it will return a NULL pointer, which you would then try to read from later in your program.
†: I personally would make my input character limit larger: at least 25
††: man strtol
for more information
Upvotes: 2
Reputation: 153368
string in C is of the correct 'format'?
A simpler approach uses " %n"
at the end to record the offset of the scan - if it made it that far. Akin to @Chris Dodd comment.
int firstNumber;
char operator[2];
int secondNumber;
int n = 0;
sscanf(input, "%d %1[+-] %d %n", &firstNumber, operator, &secondNumber, &n);
// v---v-------------------- Scan complete?
if (n > 0 && input[n] == '\0') Success();
// ^--------------^ No extra junk at the end?
else Fail();
Detecting if a space exists is tricky. This answer and "%d %c %d"
would pass `"5-7". If spaces are required about the operator, use
"%d%*[ ]%1[+-]*[ ]%d %n"
Notice the " "
in " %n"
allows scanning to be tolerant of a trailing '\n'
. Use as desired.
Upvotes: 2