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

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

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)

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.

Verifying integer input in a union in C

I'm trying to verify that what a user inputs in to one section of a union is actually an integer. I have been trying to use the isdigit function (see below) but I am having no success. All I need to do is make sure the user enters ONLY numbers for the date, but I am having a lot of trouble with it.
My code:
#define STRSIZE 30
#define PROFSIZE 30
#define NBRASSI 2
#define TRUE 1
#define FALSE 0
struct assignment
{
char name[STRSIZE];
char prof[PROFSIZE];
int duedate;
float value;
};
.
.
.
struct assignment populate_structure(struct assignment assi[], int assi_nbr)
{
int count;
int date_check = FALSE;
for (count = 0; count < assi_nbr; count++)
{
flushall();
printf("Enter Assignment #%d name (max %d chars):\n", count + 1,
STRSIZE);
gets(assi[count].name);
while (date_check == FALSE)
{
printf("Enter due date for Assignment #%d (YYYYMMDD):\n",
count + 1);
scanf("%d", &assi[count].duedate);
if (isdigit(assi[count].duedate))
{
date_check = TRUE;
}
else
{
printf("Invalid");
date_check = FALSE;
}
}
printf("Enter %% of final grade for Assignment #%d:\n", count + 1);
scanf("%f", &assi[count].value);
flushall();
printf("Enter Professor's name for Assignment #%d (max %d chars):\n",
count + 1, PROFSIZE);
gets(assi[count].prof);
printf("\n\n");
}
return assi[count];
}
It gives me no errors in Visual Studio, but when I run the program I get an Abort error whenever ANY value is input for assi[].duedate
If I remove if (isdigit(assi[count].duedate)), the program runs fine (so long as they only input an integer for duedate). Any help is greatly appreciated.
As the commenters already noted: isdigit() is for single characters only. Also: the way you use scanf() already assures the result to be a number.
But you should read a string instead, it is easier to test. For example
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int c;
int position = 0;
int res;
char date[9] = {'\0'};
char input[20] = {'\0'};
puts("try if date is in the format \"YYYYMMDD\"");
res = scanf("%19s",input);
if(res != 1){
fprintf(stderr,"input was a mess, aborting\n");
goto __FAILURE;
}
c = input[position];
while(c != '\0'){
switch(position){
case 0:
if( c == '2' || c == '1' ){
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 1:
if( c == '9' || c == '0' ){
// check valid digit by looking back here
// (not implemented)
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 2:
if( isdigit(c) ){
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 3:
if( isdigit(c) ){
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 4: // month
if( c == '0' || c == '1' ){
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 5: // month
if( isdigit(c) ){
// check valid digit by looking back here
// (not implemented)
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 6: // day
if( c == '0' || c == '1' || c == '2' || c == '3'){
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
case 7: // day
if( isdigit(c)){
// check valid digit by looking back here
// (not implemented)
date[position] = (char) c;
} else {
goto __FAILURE;
}
break;
default:
break;
}
c = input[++position];
}
printf("Date was correct and is %s\n",date);
exit(EXIT_SUCCESS);
__FAILURE:
printf("Date was wrong at position %d with character %c or just too short/long\n",position,c);
exit(EXIT_FAILURE);
}
Fill out the rest (check if date is valid and in the correct range). You could also part the date into individual year/month/day sections instead of putting the string into another string and convert them into numbers via atoi ( you can use atoi `because you already made sure to have a valid number) or by converting manually inside the switch without extra variables and functions. Checking ranges arithmetically is simpler than comparing strings/characters.
Here is my offering - any invalid entry calls exit(1) though a better error handler would be preferred. The data is entered as a string, and then extracted and validated.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct {
int year;
int month;
int day;
} mydate_t;
int main(void){
int i;
mydate_t dat = {0};
int dayspermon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char str[12];
printf("Enter a date (YYYYMMDD): ");
fflush(stdout);
if(fgets(str, sizeof str, stdin) == NULL) {
exit(1);
}
for(i=0; i<8; i++) {
if(!isdigit(str[i])) {
exit(1); // also fails when the string is too short
}
}
// extract
for(i=0; i<4; i++) {
dat.year = dat.year * 10 + str[i] - '0';
}
for(i=4; i<6; i++) {
dat.month = dat.month * 10 + str[i] - '0';
}
for(i=6; i<8; i++) {
dat.day = dat.day * 10 + str[i] - '0';
}
// validate
if(dat.year < 2000 || dat.year > 3000) // arbitrary range
exit(1);
if(dat.year % 4 == 0 && (dat.year % 100 != 0 || dat.year % 400 == 0)) {
dayspermon[1]++; // leap year adjustment
}
if(dat.month < 1 || dat.month > 12)
exit(1);
if(dat.day < 1 || dat.day > dayspermon[dat.month - 1])
exit(1);
printf("Date: %04d %02d %02d\n", dat.year, dat.month, dat.day);
}

Why does my C program print out the same output no matter what I put for the input?

I'm new to C and I've been working on this homework problem for about 2 hours to no avail. I'm attempting to create a program that takes an alphabetic phone number (ie; CALLATT or 1-800-COL-LECT) and turns it into the number form (2255288 or 1-800-265-5328). No matter what I put for input, though, I always get -4197680 for my output.
int main(void){
int c=0, len, a[len];
char n[len];
printf("Enter phone number: \n");
scanf("%c", n);
len = sizeof(n) / sizeof(n[0]);
while (len > c){
if (n[c] == 'A' || n[c] == 'B' || n[c] == 'C'){
a[c] = 2;
c++;
}
else if (n[c] == 'D' || n[c] == 'E' || n[c] == 'F'){
a[c] = 3;
c++;
}
else if (n[c] == 'G' || n[c] == 'H' || n[c] == 'I'){
a[c] = 4;
c++;
}
else if (n[c] == 'J' || n[c] == 'L' || n[c] == 'L'){
a[c] = 5;
c++;
}
else if (n[c] == 'M' || n[c] == 'N' || n[c] == 'O'){
a[c] = 6;
c++;
}
else if (n[c] == 'P' || n[c] == 'Q' || n[c] == 'R' || n[c] == 'S'){
a[c] = 7;
c++;
}
else if (n[c] == 'T' || n[c] == 'U' || n[c] == 'V'){
a[c] = 8;
c++;
}
else if (n[c] == 'W' || n[c] == 'X' || n[c] == 'Y' || n[c] == 'Z'){
a[c] = 9;
c++;
}
else {
a[c] = n[c];
c++;
}
}
printf("%d\n", a);
return 0;
}
EDIT: Revised. There were many comments pointing out problems, here is my answer which works with a reasonable length phone number. It skips any non-dialing characters, such as '-' which is not part of a phone number.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void){
int k, d, e, len;
char dial[20], entry[20] = {0};
printf("Enter phone number: ");
fgets(entry, 19, stdin);
len = strlen(entry);
d = 0; // dial string index of output
for (e=0; e<len; e++) { // entry string index of input
k = entry[e];
switch (toupper(k)) {
case 'A': case 'B': case 'C': dial[d++] = '2'; break;
case 'D': case 'E': case 'F': dial[d++] = '3'; break;
case 'G': case 'H': case 'I': dial[d++] = '4'; break;
case 'J': case 'K': case 'L': dial[d++] = '5'; break;
case 'M': case 'N': case 'O': dial[d++] = '6'; break;
case 'P': case 'Q': case 'R': case 'S': dial[d++] = '7'; break;
case 'T': case 'U': case 'V': dial[d++] = '8'; break;
case 'W': case 'X': case 'Y': case 'Z': dial[d++] = '9'; break;
default:
if (isdigit(k) || k=='*' || k=='#') dial[d++] = k;
}
}
dial[d] = 0; // terminate string
printf("Dial %s\n", dial);
return 0;
}
Here is some code:
char buf[32];
sscanf("%31s", buf);
size_t i;
for (i = 0; i < sizeof(buf) && buf[i]; ++i)
{
switch (buf[i])
{
case 'A': case 'B': case 'C':
buf[i] = '2'; break; // Note: character literal, not integer
case 'D': case 'E': case 'F':
buf[i] = '3'; break;
....
}
}
printf("%s", buf);
If you have a Posix-compliant library, you can use dynamic allocation:
char *buf;
scanf("%ms", &buf); //scanf would allocate memory
for (i = 0; buf[i]; ++i)
{
.....
}
printf("%s", buf);
free(buf);
There are so many problems in your code, it will almost need a re-write to make it work. I think you should start something small. Make sure it works before adding more functionality. I would suggest dividing the code in main into three sections -- reading the phone number, converting phone number and printing the converted phone number.
Here's a skeletal program that captures those three steps.
#define SIZE 50
void readPhoneNumber(char phoneNumber[])
{
}
void convertTextToNumber(char phoneNumber[], char dialedNumber[])
{
}
void printPhoneNumber(char phoneNumber[])
{
}
int main(void)
{
char phoneNumber[SIZE];
char dialedNumber[SIZE];
readPhoneNumber(phoneNumber);
convertTextToNumber(phoneNumber, dialedNumber);
printPhoneNumber(dialedNumber);
}
Now, you can start fleshing out the functions. For example, readPhoneNumber can be implemented as:
void readPhoneNumber(char phoneNumber[])
{
printf("Enter phone number: \n");
fgets(phoneNumber, SIZE, stdin);
}
printPhoneNumber can be implemented as:
void printPhoneNumber(char phoneNumber[])
{
printf("%s\n", phoneNumber);
}
I'll leave you to work out the implementation of convertTextToNumber.
Here you have undefined behavior, len is not initialized.
int c=0, len, a[len];
char n[len];
Use instead a constant value instead, i bet the phone number in your country has some kind of maximum length.
This way to read from the keyboard is not recommended, scanf does not check for length of string so you can do a faceroll on the keyboard and your program will crash. Instead use fgets( ) to read from stdin then go through the string char by char skipping the included \n
printf("Enter phone number: \n");
scanf("%c", n);
This makes no sense, you calculate the sizeof n i.e. of the integer that holds n. If you want the length of the string use strlen( n ); btw try to use more descriptive variable names.
len = sizeof(n) / sizeof(n[0]);
Instead of
while (len > c){
why not use a normal for-loop ? you seem to increment c++ everywhere.
this here will not do what you expect it to do
printf("%d\n", a);
but you assign 'a' integers e.g.
a[c] = 2;
printf can not magically print a number of your array, instead you want to print out is a string with the numbers. the ascii value of a digit is 48 + digit. e.g. '0' is 48, by knowing this have a character buffer and add the ascii values to it. make sure it ends with \0 which is end of string. then print out the string
buf[c++] = 48 + digit;
...
buf[c] = '\0';
puts( buf );

Resources