###前提・実現したいこと
16進数の電卓を作っている。
基本的な機能は計算式を入力して、結果を表す。(括弧付き計算式はOK)
入力した不正な数式の不正箇所を「^」で指摘したいが、やり方が分からない。
例:5+((6/2)--1
| ^ ^
一応、ソース全体を張り付けておく。
###該当のソースコード
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MaxSize 32 char str[MaxSize]; int sign; void translate(char str[],char exp[]) {//逆ポーランド記法に直す struct{ char data[MaxSize]; int top; }op; char ch; int i=0; int t=0; op.top=-1; ch = str[i]; i++; while(ch!='\0'){ switch(ch){ case '(': op.top++; op.data[op.top]=ch; break; case ')': while(op.data[op.top] != '('){ exp[t]=op.data[op.top]; op.top--; t++; } op.top--; break; case '+': case '-': while(op.top != -1&&op.data[op.top] != '('){ exp[t] = op.data[op.top]; op.top--; t++; } op.top++; op.data[op.top] = ch; break; case '*': case '/': while(op.data[op.top] == '/'||op.data[op.top] == '*'){ exp[t] = op.data[op.top]; op.top--; t++; } op.top++; op.data[op.top] = ch; break; case ' ': break; default: while((ch >= '0'&&ch <= '9')||(ch >= 'a'&&ch <= 'f')){ exp[t] = ch; t++; ch = str[i]; i++; } i--; exp[t] = '#'; t++; } ch = str[i]; i++; } while(op.top != -1){ exp[t] = op.data[op.top]; t++; op.top--; } exp[t] = '\0'; } int cal_value(char exp[],int* flag){ struct{ signed int data[MaxSize]; int top; }st; signed int d; char ch; int t = 0; st.top = -1; ch = exp[t]; t++; while(ch != '\0'){ switch(ch){//四則演算 case '+': st.data[st.top-1] = st.data[st.top-1]+st.data[st.top]; st.top--; break; case '-': if(st.top<=0){ st.data[st.top]=-st.data[st.top]; return st.data[st.top]; break; }else{ st.data[st.top-1] = st.data[st.top-1]-st.data[st.top]; } st.top--; break; case '*': st.data[st.top-1] = st.data[st.top-1]*st.data[st.top]; st.top--; break; case '/': if(st.data[st.top] != 0) st.data[st.top-1]=st.data[st.top-1]/st.data[st.top]; else{ printf("除数を正しく入力してください\n\n"); *flag=1; } st.top--; break; default: d=0; while(ch !='#'){//文字列を数値に if(ch>='0'&&ch<='9'){ d = 16*d+ch-'0'; ch = exp[t]; t++; }else if(ch>='a'&&ch<='f'){ d = 16*d+ch-0x57; ch = exp[t]; t++; } } st.top++; st.data[st.top] = d; if(sign==1){ st.data[0]=-st.data[0]; sign=0; } } ch = exp[t]; t++; } return st.data[st.top]; } int CheckLen(char data[]){ int i=0; for(i=0;data[i]!='\n';i++){ if(i>32){ printf("最大入力文字数を超過しました。\n30文字以内でもう一度入力しください。\n\n"); return 1; } } if(data[0]==10&&data[1]==0){ printf("計算式が入力していません。\nEnterキーを押して、もう一度計算式を入力してください。\n\n"); return 1; } return 0; } int DeleteSpaeceTab(char *data){ int i=0; int speace_tab_cnt=0; while(data[i]!='\0'){//タブ・スペースの削除 if(data[i]==' '||data[i]=='\t'){ while(data[i]!='\0'){ data[i]=data[i+1]; i++; } i=0; } i++; } data[i-1]='\0'; return *data; } int MaxMinCheck(char *data){ int operator_flag=0; int i=0; int j=0; char w[31]={' '}; long long w2=0; char *extra; while(data[i]!='\0'&&i<=32){ if(data[i]=='+'||data[i]=='-'||data[i]=='*'||data[i]=='/'){ operator_flag=1; } i++; } i=0; if(operator_flag==1){ while(data[i]!='\0'){//最大値チェック(演算子がある場合) if(data[i] >= '0'&& data[i] <= 'f'){ w[j]=data[i]; i++; j++; }else{ w2=strtol(w,&extra,16); if(w2<INT_MIN||w2>INT_MAX){ printf("入力可能な桁数は8桁で、範囲は80000000~ffffffffです。\n\n"); return 1; break; } i++; j=0; } if(j>8){ printf("入力可能な桁数は8桁で、範囲は80000000~ffffffffです。\n\n"); return 1; break; } } }else{ i=0; while(data[i]!='\0'){//最大値チェック(演算子がない場合) w[i]=data[i]; i++; } w2=strtol(w,&extra,16); if(i>8){ printf("入力可能な桁数は8桁で、範囲は80000000~ffffffffです。\n\n"); return 1; }else if(w2<INT_MIN||w2>INT_MAX){ printf("入力可能な桁数は8桁で、範囲は80000000~ffffffffです。\n\n"); return 1; } } return 0; } int IncrrectFormulaCheck(char *data){ int i=0; while(data[i]!='\0'){//不正数式の例外処理 if(data[i]=='/'&&data[i+1]=='0'){ printf("除数を正しく入力してください。\n\n"); return 1; break; }else if(data[i]=='+'||data[i]=='-'||data[i]=='*'||data[i]=='/'){ if(data[i+1]=='+'||data[i+1]=='-'||data[i+1]=='*'||data[i+1]=='/'){ printf("エラー!演算子を正しく入力してください。\n\n"); return 1; break; }else{ i++; } }else if(data[0]=='*'||data[0]=='/'){ printf("エラー!計算式を正しく入力してください。\n\n"); return 1; break; }else if(data[i]=='('||data[i]==')'){ i++; }else if(data[i]>= '0'&&data[i] <= '9'){ i++; }else if(data[i]>='a'&&data[i]<='f'){ i++; }else if(data[i]>='A'&&data[i]<='F'){ printf("英字は小文字で入力してください。\n\n"); return 1; break; }else{ printf("エラー!計算式を正しく入力してください。\n\n"); return 1; break; } } i=0; while(data[i+1]!='\0'){//末尾文字の要素番号を計算 i++; } if(data[i]>='0'&&data[i]<='9'){//末尾の不正数式指摘 }else if(data[i]>='a'&&data[i]<='f'){ }else if(data[i]=='('||data[i]==')'){ }else{ printf("不正な数式が入力されました。\n\n"); return 1; } return 0; } int main(void){ char str[MaxSize],exp[MaxSize]; int i=0; int j=0; int k=0; int err_flag=0; int err_flag2=0; printf("*******************************************\n"); printf("\t\t十六進数電卓\n"); printf("*******************************************\n\n"); while(1){ memset(str,-2,sizeof(str)); memset(stdin,0,sizeof(stdin)); err_flag=0; err_flag2=0; i=0; printf("計算式を入力してください。\n"); //gets_s(str,32); fgets(str, 32, stdin); if(str[0]=='z'&&str[1]==10&&str[2]==0){ exit(1); }else if(str[0]=='z'){ printf("終了したい場合はzを入力し、Enterキーを押してください。\n\n"); err_flag=1; }else{ err_flag=CheckLen(str); if(err_flag!=1){ DeleteSpaeceTab(str); err_flag=MaxMinCheck(str); if(err_flag!=1){ err_flag=IncrrectFormulaCheck(str); } } if(str[0]=='-'){//負数対応 while(str[i]!='\0'){ str[i]=str[i+1]; i++; } sign=1; }else if(str[0]=='+'){ while(str[i]!='\0'){ str[i]=str[i+1]; i++; } sign=0; } } if(err_flag!=1){ translate(str,exp); k=cal_value(exp,&err_flag2); if(err_flag2==0){ printf("=%x\n",k); printf("\n"); } } if ( str[strlen(str)-1] != '\n' ){ while( getchar() != '\n' ); } } system("pause"); return 0; }
###試したこと
まだ何も試していない
###補足情報(言語/FW/ツール等のバージョンなど)
C言語/Microsoft Visual C++ 2010/.NET 4.0
パッと見ですが str を大域変数にしたなら(大域変数にするにしてももう少し大域変数らしい変数名にした方が良いです。ハンガリアン記法にしろとは言わないけど)いちいち関数に渡すのはやめましょう。
回答3件
あなたの回答
tips
プレビュー