Need help finishing C program calculator with command line arguments - c

This program just needs to be able to identify the invalid arguments such as having a letter in the command line or a double operator, except 5--5 that would give you 10. Order of operations does not matter it just reads left to right. The code below only give a 0005 if the first argument is a 5, I cannot figure out how to get the code to do the operations. Thank you for any input as this will definitely help me.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int op = 0;
int num1 = 0;
int num2 = 0;
double result = 0;
for (int x = 1; x < argc; x++) {
int num = atof(argv[x]);
if (num ==! argv[x]) {
printf("Invalid Input");
}
switch (atoi(argv[x])) {
case'+':
op = 43; /* ASCII value of '+' */
break;
case'-':
op = 45; /* ASCII value of '-' */
break;
case'*':
op = 42; /* ASCII value of '*' */
break;
case'/':
op = 47; /* ASCII value of '/' */
break;
case'^':
op = 94; /* ASCII value of '^' */
break;
default:
if (op == 0) {
num1 = atof(argv[x]);
} else {
switch(op){
case 43:
printf("%.1d + %.1d = %.1d",num1, num2, num1+num2);
break;
case 45:
printf("%.1d - %.1d = %.1d",num1, num2, num1-num2);
break;
case 42:
printf("%.1d * %.1d = %.1d",num1, num2, num1*num2);
break;
case 47:
printf("%.1d / %.1d = %.1d",num1, num2, num1/num2);
break;
case 94:
printf("%.4d ^ %.4d = %.4d",num1, num2, num1/num2);
break;
default:
break;
}
}
}
}
return 0;
}

Related

Calculator with user defined variables in C language

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)

Do while can do this but I want to know why this is wrong

#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;
}
}
}

Expression Tree - Operations with Characters

The user enters a string with an operation such as 4*5+2/3 and the code is supposed to make an expression tree out of it and the calculate said expression tree. I am having a problem where the program is making the expression tree with the decimal values of the ascii table instead of the actual numbers.
For example instead of 4*5+2/3, the program is storing and using 52 42 53 43 50 47 51 for the calculations. My desired run screen would be:
1 //this is the number of strings
4*5+2/3 //this is the string itself
20 //this is the result
However what I am getting is:
1 //this is the number of strings
4*5+2/3 //this is the string itself
2756 //this is the result
That is because the code is doing 52*53+50/51(because it is using the ascii values) and not 4*5+2/3.
I believe the reason for this is because I am storing 4*5+2/3 in a string of char and not in an array of int. I do not know if this is the case and would like some help.
You will not be able to run the following code as it is not complete but the whole program is five files and I do not know if I should put all of it here. I am new to both trees and StackOverflow.
This is my Make Expression Tree function and my Calculate Expression Tree function:
BTreeNode* MakeExpTree(char* exp, int len)
{
Stack stack;
BTreeNode * node, *right_node, *left_node;
InitStack(&stack);
for(int i = 0; i < len; i++){
if('0' <= exp[i] && exp[i] <= '9'){
node = CreateNode(exp[i]);
}
else{
right_node = PeekNode(&stack), Pop(&stack);
left_node = PeekNode(&stack), Pop(&stack);
node = CreateNode(exp[i]);
CreateRightSubtree(node, right_node);
CreateLeftSubtree(node, left_node);
}
PushNode(&stack, node);
}
return PeekNode(&stack);
}
int CalculateExpTree(BTreeNode* root)
{
int ret, op1, op2;
if(root == NULL){
return 0;
}
if(root->left_child == NULL && root->right_child == NULL){
return root->item;
}
op1 = CalculateExpTree(root->left_child);
op2 = CalculateExpTree(root->right_child);
switch(root->item){
case '+':
ret = op1 + op2;
break;
case '-':
ret = op1 - op2;
break;
case '*':
ret = op1 * op2;
break;
case '/':
ret = op1 / op2;
break;
case '#':
ret = op1 * pow( 2, op2);
break;
case '#':
ret = op1 / pow( 2, op2);
break;
}
return ret;
}
This is how I store the string from stdin in main function:
int main()
{
int num_exp, result, len = 0;
char input[10];
char IDK[129];
fgets(input, 9, stdin); //user enters number of strings
int m = sscanf(input, "%d", &num_exp);
char string[100][129] = { 0 };
char postfix[100][129] = { 0 };
for(int i = 0; i < num_exp; i++){
fgets(IDK, 129, stdin); //user enters string
int mm = sscanf(IDK, "%s", string[i]); //is this where the problem lies?
} //should I not be storing it in a char string?
for(int x = 0; x < num_exp; x++){
InfixToPostfix(string[x], postfix[x]); //converts strings from infix to postfix
}
BTreeNode* tree;
for(int k = 0; k < 129; k++){ //calculates length of string
if(postfix[0][k] == '\0'){
break;
}
len++;
}
tree = MakeExpTree(postfix[0], len); //makes expression tree
result = CalculateExpTree(tree); //calculates expression tree
//or is the problem in this function?
printf("%d \n", result);
return 0;
}
I am not understanding clearly what you are doing and it would help my learning too if you shared from what source are you learning these (we can chat in chat room) but I also tried to do similar thing and in my style it works partially (that is, sometimes when I insert larger number the answer is wrong but for small numbers generally correct).So you might get some help form my style of this code that calculates given string (A little help for me also would be appreciated commenters!!). My code:
#include <stdio.h>
#include <string.h>
#include "stackforcalc.h"
int isOperand(char b){
if(b>='0' && b<='9'){
return 1;
}else{
return 0;
}
}
int isOperator(char b){
if(b=='+' || b=='-' || b=='*' || b=='/'){
return 1;
}
return 0;
}
int getwt(char b){
int g=-1;
switch (b)
{
case '+':
case '-':
g=1;
break;
case '/':
case '*':
g=28787868;
break;
}
return g;
}
int higherprecedence(char a,char b){
int c=getwt(a);
int d=getwt(b);
return (c>=d)?1:0;
}
int infToPost(char *b,char *str){
int j=0;
for(int i=0;i<strlen(b);i++){
if(b[i]== ' ' || b[i]== ',' ){
continue;
}
else if(isOperator(b[i])){
str[j]=' ';
j++;
while(!empty() && gettop() != '(' && higherprecedence(gettop(),b[i])){
str[j]=gettop();
j++;
pop();
}
push(b[i]);
}
else if(isOperand(b[i])){
str[j]=b[i];
j++;
}
else if(b[i]=='('){
push(b[i]);
}
else if(b[i] ==')'){
while(!empty() && gettop() != '('){
str[i]=gettop();
j++;
pop();
}
pop();
}
}
while(!empty()){
str[j]=gettop();
j++;
pop();
}
}
int Evaluate(int t,char y,int r){
int ty;
switch(y){
case '+':
ty=t+r;
break;
case '-':
ty=r-t; //I inverted these.
break;
case '*':
ty=r*t;
break;
case '/': //I inverted these because
ty=r/t; //even though I did t/r it performed r/t.
break; //may be somewhere before the numbers were swapped
default:
ty=-1;
break;
}
return ty;
}
int calculatepostfix(char *c){
for(int i=0;i<strlen(c);i++){
if(c[i]==' ' || c[i]==','){
continue;
}
else if(isOperator(c[i])){
int op1=gettop2();
pop2();
int op2=gettop2();
pop2();
int oper=Evaluate(op1,c[i],op2);
push2(oper);
}
else if(isOperand(c[i])){
int res=0;
while(i<strlen(c) && isOperand(c[i])){
res=(res*10)+(c[i]-'0');
i++;
}
i--;
push2(res);
}
}
return gettop2();
}
int main(){
char b[65];
printf("\n \n**-- Calculator --**\n");
printf("Enter expression: ");
fgets(b,sizeof(b),stdin);
char str[50];
infToPost(b,str);
int tt =calculatepostfix(str);
printf("Your answer is: %d",tt);
}
The code in "stackforcalc.h" is
#ifndef stacycalc
#define stacycalc
#define maxsize 50
char a[maxsize];
int top=-1;
int abc[maxsize];
int to=-1;
void push2(int re){ abc[++to]=re; }
void push(char b){ a[++top]=b; }
void pop2(){ to--; }
void pop(){ top--;}
int gettop2(){ return (to==-1)?-1:abc[to]; }
char gettop(){ return (top==-1)?0:a[top]; }
int empty(){ return (top==-1)?1:0; }
#endif
That is because the code is doing 52*53+50/51 (because it is using the ascii values) and not 4*5+2/3.
Yes.
I believe the reason for this is because I am storing 4*5+2/3 in a string of char and not in an array of int.
No.
In C, int is just a bigger char. There's nothing magical about them; they both hold numbers.
There are a variety of ways to derive the integer value from an ASCII character. If you have exactly one character and don't want to use a library, you can "mask off" the bits: since the ASCII range for digits is 0x30 - 0x39,
static char string[] = "4";
int value = string[0] & 0x0F;
does the trick. For more complex operations, my favorite is sscanf(3), but many use atoi(3) or various flavors of strtol(3).

Calculator with Decimal, Octal and Hexadecimal Numbers

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.

Convert hex char[] to int[] in C 2 chars in 1 byte

I am trying to convert a char[] in hexadecimal format to int[] in hexadecimal.
Something like this:
hello --> 68656C6C6F --> [68, 65, 6C, 6C, 6F]
This is my code:
#include <stdio.h>
#include <string.h>
uint8_t* hex_decode(unsigned char *in, size_t len, uint8_t *out);
int main(void){
unsigned char word_in[17], word_out[33];//17:16+1, 33:16*2+1
int i, len = 0;
uint8_t* out;
while(len != 16){
printf("Set new word:");
fgets( word_in, sizeof( word_in), stdin);
len = strlen( word_in);
if( word_in[len-1]=='\n')
word_in[--len] = '\0';
for(i = 0; i<len; i++){
sprintf(word_out+i*2, "%02X", word_in[i]);
}
if(len != 16){
printf("Please, use a word of 16 chars long\n\n");
}
}
printf("%s", word_in);
printf("\n");
hex_decode(word_out, sizeof(word_out), out);
return 0;
}
uint8_t* hex_decode(unsigned char *in, size_t len, uint8_t *out)
{
unsigned int i, t, hn, ln;
for (t = 0,i = 0; i < len; i+=2,++t) {
hn = in[i] > '9' ? (in[i]|32) - 'a' + 10 : in[i] - '0';
ln = in[i+1] > '9' ? (in[i+1]|32) - 'a' + 10 : in[i+1] - '0';
out[t] = (hn << 4 ) | ln;
printf("%s",out[t]);
}
return out;
}
But after printing the word, I got a segmentation fault.
That function works perfect in arduino so I think it should works fine at my computer... Where is the problem?
See #dasblinkenlight answer for seg fault. To decode 2 bytes:
My 50 Cent... (a short version)
char hex[3];
char * phex;
int result;
for(int i = 0; i < 256; i++)
{
sprintf(hex, "%02X", i);
phex = hex;
result = ((*phex > 64 ? (*phex & 0x7) + 9 : *phex - 48) << 4) | (*(phex+1) > 64 ? (*(phex+1) & 0x7) + 9 : *(phex+1) - 48);
if(result != i)
{
printf("err %s %02X\n", hex, result);
}
}
Code above does no validation. This procedure returns -1 when input was invalid.
int h2i(char * ph)
{
int result;
if(*ph > 96 && *ph < 103) result = *ph - 87;
else if(*ph > 64 && *ph < 71) result = *ph - 55;
else if(*ph > 47 && *ph < 59) result = *ph - 48;
else return -1;
result <<= 4;
ph++;
if(*ph > 96 && *ph < 103) result |= *ph - 87;
else if(*ph > 64 && *ph < 71) result |= *ph - 55;
else if(*ph > 47 && *ph < 59) result |= *ph - 48;
else return -1;
return result;
}
But wait? A char can also be -1. Yes, after casting.
char * x = "FF";
char y;
int result;
result = h2i(x);
// if (result == -1) ...error...
y = (char)result;
You get a segmentation fault because you are passing the pointer out before making any assignments to it. Either the hex_decode need to take uint8_t **out_ptr and assign it a dynamically allocated array, or the caller needs to provide an array sufficient to hold the output of the conversion.
The reason why it "works" on another platform is that it exhibits undefined behavior: in arduino, the arbitrary value placed in the uninitialized pointer out happens to point to an unused location in memory. Writing to that location does not trigger segmentation fault, creating an illusion of working code.
i will just share my own code for this:
it converts any 8 hexadecimal char string into a integer number from [-2147483648. 2147483647]
input(argument) is 1 string(8+'\0'), output(returns) is a long int, MODIFY AS NECESSARY
#define N 8
long int hex2dec(char* hex){ /*conversor HEX 2 DEC*/
int i,j,n[N],l,neg;
long int dec=0;
for(i=0;i<N;i++){
n[i]=0;
}
l=strlen(hex);
neg=0;
if(hex[0]>='8'){
neg=1;
for(i=0;i<N;i++){
if(hex[i]=='0'){
hex[i]='F';
continue;
}
if(hex[i]=='1'){
hex[i]='E';
continue;
}
if(hex[i]=='2'){
hex[i]='D';
continue;
}
if(hex[i]=='3'){
hex[i]='C';
continue;
}
if(hex[i]=='4'){
hex[i]='B';
continue;
}
if(hex[i]=='5'){
hex[i]='A';
continue;
}
if(hex[i]=='6'){
hex[i]='9';
continue;
}
if(hex[i]=='7'){
hex[i]='8';
continue;
}
if(hex[i]=='8'){
hex[i]='7';
continue;
}
if(hex[i]=='9'){
hex[i]='6';
continue;
}
if(hex[i]=='A'){
hex[i]='5';
continue;
}
if(hex[i]=='B'){
hex[i]='4';
continue;
}
if(hex[i]=='C'){
hex[i]='3';
continue;
}
if(hex[i]=='D'){
hex[i]='2';
continue;
}
if(hex[i]=='E'){
hex[i]='1';
continue;
}
if(hex[i]=='F'){
hex[i]='0';
continue;
}
}
}
for(i=0;i<N;i++){
switch(hex[i]){
case '0':
n[i]=hex[i]-48; /* Ascii '0'=48 48-48=0*/
break;
case '1':
n[i]=hex[i]-48; /* Ascii '1'=49 49-48=1*/
break;
case '2':
n[i]=hex[i]-48;
break;
case '3':
n[i]=hex[i]-48;
break;
case '4':
n[i]=hex[i]-48;
break;
case '5':
n[i]=hex[i]-48;
break;
case '6':
n[i]=hex[i]-48;
break;
case '7':
n[i]=hex[i]-48;
break;
case '8':
n[i]=hex[i]-48;
break;
case '9':
n[i]=hex[i]-48;
break;
case 'A':
n[i]=hex[i]-55; /* Ascii 'A'=65 65-55=10*/
break;
case 'B':
n[i]=hex[i]-55; /* Ascii 'B'=66 66-55=11*/
break;
case 'C':
n[i]=hex[i]-55;
break;
case 'D':
n[i]=hex[i]-55;
break;
case 'E':
n[i]=hex[i]-55;
break;
case 'F':
n[i]=hex[i]-55;
break;
}
}
for(i=0,j=l;i<l;i++,j--){
dec=dec+(n[j-1]*pow(16,i));
}
if(neg==1){
dec=0-dec;
dec=dec-1;
}
return dec;
}
change
uint8_t *out;//region is not ensured
to
uint8_t out[sizeof(word_out)/2];
change
hex_decode(word_out, sizeof(word_out), out);//sizeof(word_out) is 33, must to 32
to
hex_decode(word_out, strlen(word_out), out);//strlen(word_out) or len * 2 or sizeof(word_out) -1
change
printf("%s",out[t]);//out is not string
to
printf("%02X ",out[t]);
The program looks complicated comparing what you want to do.
if you want to print the hexadecimal ascii code of a charachter, you can simply use
printf("%02X",'K'); // this will display the code ascii of 'K' in hexadecimal
If you want to print your word in code ascii in another char array. you can use sprintf():
int main() {
char word_in[17]="hello", word_out[33];
char *pi = word_in, *po = word_out;
word_out[0]=0;
for (;*pi;po+=2,pi++)
sprintf(po,"%02X",*pi);
printf("%s\n", word_out);
}
A charachetr is saved in binary format in the memory. this binary format represent the code ascii of the charachter. And when you want to print its content:
when using "%d": this will print the code ascii as integer
when using "%x": this will print the code ascii as hexadecimal
when using "%c": this will print the charachter

Resources