質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

346閲覧

C言語課題 一対の括弧を書き足す

kycfc2009

総合スコア13

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2017/06/19 06:23

プログラミング考え方

以下の問題をc言語でどう解いたらいいかわかりません。

問題 一対のかっこを書き足すことにより、次式正しく一対のかっこを書き足すことにより、次の式正しくするプログラムを作成しなさい。
18-7×3-1+2=6

申し訳ありませんが、私はプログラミングの初心者(繰り返し文、配列が理解できている程度)ですので時間がかかるプログラミングでも構いませんので、できるだけ理解しやすいものであると助かります。
プログラムがあれば本当に感謝です。

どなたか力を貸していただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2017/06/19 06:46

問題文で検索するとhttp://www.kis.e.kaiyodai.ac.jp/file/mse/2016.pdfが引っかかるんですが、他の問題のレベルとのバランスを考えると、本当に式の解析をしろという問題だったりしますかね...?出題者の方にどの程度のレベルの回答が求められるかおたずねできるでしょうか?
kycfc2009

2017/06/19 06:48

大学名ばれてしまいましたね笑 解析まで求められております。
otn

2017/06/19 06:58

CとC#は別の言語です。タグを修正しましょう
guest

回答3

0

ベストアンサー

ネタとしては面白いですね。ぱっと思いつく方法なら

  1. 頭から順に数字とオペレータに分解して配列に入れていく
  2. =が出たら後ろの数字を解として記憶
  3. 適当な数字の前に(があるものとして、それ以降にある数字の後ろに)を置いて式を計算し、2と一致するか調べる
  4. 3を総当たりで行う

といった感じでしょうか?

3が難しかったらとりあえず式を文字列として見て、数字の前に(、それ以降の数字の後ろに)を挿入した文字列を順次作成していけば、あとは一般的な式の評価を行えばいいと思います。

追記1
enumと構造体を使ってオペレータか数字の配列を作る

C

1enum { 2 OP_ADD, 3 OP_SUB, 4 OP_MUL, 5 OP_DIV, 6 NUMEBR, 7}KIND; 8 9struct { 10 KIND kind; 11 int value; 12}ELEMENT; 13 14ELEMENT elements[30];

追記2
()を総当たりで挿入する(オペレータは1文字、スペースは含まない前提)

C

1 2static int evaluateExpression(const char* exp) 3{ 4 printf("eval: %s\n", exp); 5 return 0; // none 6} 7static const char* passNumber(const char* s) 8{ 9 while (*s && isdigit(*s)) s++; 10 return s; 11} 12 13int main() 14{ 15 const char* exp = "18-7*3-1+2=6"; 16 17 const char* openPara = exp; 18 const char* closePara; 19 20 char exp2[100]; 21 22 while (1) { 23 closePara = passNumber(openPara); 24 25 while (*closePara != '=') { 26 closePara = passNumber(closePara + 1); // +1 : pass operator 27 28 char* d = exp2; 29 30 for (const char* s = exp; *s; s++) { 31 if (s == openPara) *d++ = '('; 32 if (s == closePara) *d++ = ')'; 33 *d++ = *s; 34 } 35 *d = '\0'; 36 37 if (evaluateExpression(exp2)) { 38 printf("anser is : %s\n", exp2); 39 goto EXIT: 40 } 41 } 42 43 openPara = passNumber(openPara); 44 if (*openPara == '=') { 45 break; 46 } 47 openPara++; // pass operator 48 } 49EXIT: 50 51 return 0; 52}

あとはこのへんを参考に式を評価してみる

投稿2017/06/19 07:11

編集2017/06/19 07:54
toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kycfc2009

2017/06/19 07:28

ご回答ありがとうございます。 なるほど、配列にオペレータをいれてしまう方法は考えておりませんでした。 初歩的な質問で申し訳ないですが、今までやったことがないのですがオペレータを配列に入れることは可能なのでしょうか。
toki_td

2017/06/19 07:56

前者の例だと追記1のように構造体の配列にする感じですかね。 文字列を完全に分解してやります。 後者は雑ですが追記2のようにして式を総当たりで作ってあとは文字列を式として評価すればいいです。 こちらのほうが簡単そうです。
kycfc2009

2017/06/19 08:04

すみません、プログラムまで組んでいただきありがとうございます。 これを解読して問題に再チャレンジしてみます! 本当にありがとうございました。
guest

0

逆ポーランドを使ってみました。

c

1#include <string.h> 2#include <stdlib.h> 3#include <math.h> 4#include <stdio.h> 5#include <string.h> 6 7double CalcString(char str[100]) 8{ 9 char vstak[100]; //演算子用のスタック 10 char porstr[100][20]; //逆ポーランド記法配列(数値は文字列、他は1文字) 11 char numstr[20]; //数値 12 13 int i; 14 int k=0;//stacksize 15 int vstaksize=0; 16 int numstrsize=0; 17 18 int strLen=strlen(str); 19 if(strLen==0){ 20 printf("文字列が空です。\n"); 21 return 0.0; 22 } 23 if(strLen>=98){ 24 printf("文字列が長すぎます。\n"); 25 return 0.0; 26 } 27 28 //前後に '(', ')' を追加 29 for(i=strLen;i>0;i--) 30 str[i]=str[i-1]; 31 str[0]='('; 32 strLen+=2; 33 str[strLen-1]=')'; 34 str[strLen]='\0'; 35 36 for(i=0;i<strLen;i++){ 37 switch(str[i]){//入力文字列の先頭文字 38 case '0':case '1':case '2':case '3':case '4': //数値の場合 39 case '5':case '6':case '7':case '8':case '9':case '.': 40 numstr[numstrsize]=str[i];//数値文字列に追加 41 numstrsize++; 42 break; 43 case '+': //+,-の場合は演算子スタックを掃き出す 44 case '-': 45 if(numstrsize>0){ 46 numstr[numstrsize]='\0'; 47 strcpy(porstr[k],numstr); 48 k++; 49 numstrsize=0; 50 } 51 while(vstaksize>0){//演算子スタックが空でない場合 52 if(vstak[vstaksize-1] == '('){//stack の top 53 break;//トップが開き括弧のときはブレイク 54 } 55 //演算子スタックからポーランド記法へ 56 porstr[k][0]=vstak[vstaksize-1]; 57 porstr[k][1]='\0'; 58 k++; 59 vstaksize--;//演算子スタックから1文字削除 60 } 61 vstak[vstaksize]=str[i]; 62 vstaksize++; 63 break; 64 case 'x': 65 case '/': //x,/の場合は演算子スタックに追加 66 if(numstrsize>0){ 67 //数値文字列があればポーランド記法に加える 68 numstr[numstrsize]='\0'; 69 strcpy(porstr[k],numstr); 70 k++; 71 } 72 numstrsize=0;//数値文字列の初期化(空にする) 73 if(vstaksize>0 && (vstak[vstaksize-1]=='x' || vstak[vstaksize-1]=='/')){ 74 //演算子スタックからポーランド記法へ 75 porstr[k][0]=vstak[vstaksize-1]; 76 porstr[k][1]='\0'; 77 k++; 78 vstaksize--;//演算子スタックから1文字削除 79 } 80 vstak[vstaksize]=str[i]; 81 vstaksize++; 82 break; 83 case '(': 84 vstak[vstaksize]=str[i];//演算子スタックへ 85 vstaksize++; 86 break; 87 case ')': 88 if(numstrsize>0){ 89 //数値文字列があればポーランド記法に加える 90 numstr[numstrsize]='\0'; 91 strcpy(porstr[k],numstr); 92 k++; 93 } 94 numstrsize=0;//数値文字列の初期化(空にする) 95 while(vstaksize>0){//演算子スタックが空でない間 96 if(vstak[vstaksize-1] == '('){ 97 vstaksize--;//開き括弧の時はスタックから消してブレイク 98 break; 99 } 100 porstr[k][0]=vstak[vstaksize-1];//ポーランド記法文字列へ 101 porstr[k][1]='\0'; 102 k++; 103 vstaksize--;//演算子スタックから1文字削除 104 } 105 break; 106 } 107 } 108 109// 逆ポーランド記法の計算 110 double numstack[100]; 111 int numstacksize=0; 112 113 for(i=0;i<k;i++){ 114 if(porstr[i][0]>='0'&&porstr[i][0]<='9'){ 115 numstack[numstacksize]=atof(porstr[i]); 116 numstacksize++; 117 }else{ 118 if(numstacksize<2){ 119 printf("エラーです。\n"); 120 return 0.0; 121 } 122 double ope1,ope2; 123 ope1 = numstack[numstacksize-2]; 124 ope2 = numstack[numstacksize-1]; 125 switch(porstr[i][0]){ 126 case '-':numstack[numstacksize-2]=(ope1-ope2);break; 127 case '+':numstack[numstacksize-2]=(ope1+ope2);break; 128 case '/':numstack[numstacksize-2]=(ope1/ope2);break; 129 case 'x':numstack[numstacksize-2]=(ope1*ope2);break; 130 } 131 numstacksize--; 132 } 133 } 134 if(numstacksize!=1){ 135 printf("エラーです。\n"); 136 return 0.0; 137 } 138 139 return numstack[0]; 140} 141 142//括弧のパターン式の作成 143int mk_patern(char str0[100], char strx[40][100]) 144{ 145 char str1[100]={0}; 146 char str[40][100]; 147 int i,j,k,l; 148 int lf, rt; 149 int tl=0; 150 for (i=0;i<strlen(str0);i++){ 151 lf=rt=-1; 152 for(j=i+1;j<=strlen(str0);j++){ 153 if (i==0){ 154 lf=0; 155 }else if(str0[i]-'0' <0 || str0[i]-'0' >9){ 156 lf=i+1; 157 } 158 if (lf>=0){ 159 if (str0[j]-'0' <0 || str0[j]-'0' >9){ 160 rt=j+1; 161 }else if(str0[j] == '\0'){ 162 rt=j+1; 163 } 164 } 165 if (lf>=0 && rt>=0){ 166 for (k=l=0;k<=strlen(str0);k++,l++){ 167 if (l==lf){ 168 str1[l]='('; 169 l++; 170 } 171 if (l==rt){ 172 str1[l]=')'; 173 l++; 174 } 175 str1[l]=str0[k]; 176 } 177 strcpy(strx[tl],str1); 178 tl++; 179 } 180 rt=-1; 181 } 182 } 183 return tl; 184} 185 186 187void main() 188{ 189 190 char str2[100]; 191 char str0[100]="18-7x3-1+2"; 192 char str[40][100]={0}; 193 int i,cn; 194 195 cn=mk_patern(str0, str); 196 197 for( i=0; i<cn; i++){ 198 strcpy(str2,str[i]); 199 //逆ポーランド法計算 200 if ( 6 == CalcString(str2) ){ 201 printf("%s = 6 \n",str2); 202 } 203 } 204 205} 206

投稿2017/06/19 10:23

A.Ichi

総合スコア4070

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

C言語初心者向けの問題とすると例えば下記で如何でしょうか?
ちょっと手を抜きすぎですが。

C

1#include <stdio.h> 2 3int main() 4{ 5 printf("18-7x(3-1)+2=6\n"); 6 7 return 0; 8}

問題を素直に読むと、式の意味を理解した上で()を書き足すプログラムですが、その難易度は非常に高く、熟練者でもかなりの手間がかかります。情報工学系の大学の演習としても難易度は高い方と思います。

初心者向けということであれば、どこに()を挿入するのかはプログラマが判断し、文字列のその位置に()を挿入するプログラムを作るのが妥当な気がします。

十分なサイズのバッファを用意し、そこに元の文字列の先頭から5文字をstrncpy()、そして、"("をstrcat()、次に元の文字列の続きから3文字をstrncat()のような感じで次々と追加していくと良いと思います。

投稿2017/06/19 06:35

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kycfc2009

2017/06/19 06:46

ご回答ありがとうございます。 今回の問題は大学の最終課題で式を理解したうえで解けとのことです。プログラミング作成以外に問題の定式化やアルゴリズム、フローチャート等も求められています。 最終課題は3つあって、今のところニュートンラフソン法を用いた計算と整数の内部表現を固定小数点表示で表す問題を解き、これが最後の課題となっております。 ただ、理解力が低くせっかく書いていただいた以下の文章がよく理解できておりません。 >十分なサイズのバッファを用意し、そこに元の文字列の先頭から5文字をstrncpy()、そして、"("をstrcat()、次に元の文字列の続きから3文字をstrncat()のような感じで次々と追加していくと良いと思います。 なにか付け加えていただけることがあれば幸いです。
Chironian

2017/06/19 07:24 編集

マジで大学の演習問題でしたか!! Bongoさんが見つけた資料を見ると、「情報工学系の大学の演習としても難易度は高い方」にもろ該当しますね。それを、strncpy()を知らない人に解かせるのか。なんてハードな。 ごめんなさい。このギャップを埋めることは、私の手に余りすぎます。 ところで、「ニュートンラフソン法」は数値計算の話ですので、この問題には使わないと思います。 この問題は「総当り」を使って解くような問題です。 また、strncpy()等の話は忘れて下さい。これはどこに()を挿入するのか「人」が判断して解くための方法の提案です。それも必要にはなりますが、どこに()を挿入するのかを判定するプログラムを開発するのは感覚的には300倍くらい難しいです。前者を6分くらいで解ける人でも後者は30時間くらいかかっても可笑しくないと思います。
kycfc2009

2017/06/19 07:33

理解度が低くて申し訳ございません。 正直、私もこの問題は難しすぎるとは感じております。 本当に完成しなければ、少しプログラミングっぽいことをして全て数え上げて計算することも検討しております。 丁寧なご回答ありがとうございました。 少しでも回答できるように頑張ります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問