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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

2202閲覧

括弧が正しく使われているか

kun_monimoni

総合スコア26

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/06/28 07:43

編集2020/06/28 07:44

問、括弧ばかりからなる記号列が正しい形になっているかどうかを調べたい。括弧には、小括弧 ( )、中括弧 { }、大括弧 [ ] がある。それぞれの括弧は、その開き記号と閉じ記号とが対応していなければならない。正確にいうと、括弧ばかりからなる記号列が与えられとき、つぎの操作を可能な限り繰り返すことでその記号列が空となるならば、その記号列は正しいという。
( と ) がこの順に隣り合って並んでいるなら、共に取り除く。
{ と } がこの順に隣り合って並んでいるなら、共に取り除く。
[ と ] がこの順に隣り合って並んでいるなら、共に取り除く。
入力に与えられた括弧ばかりからなる記号列が正しいなら correct と1行に出力し、正しくなければ wrong と1行に出力するプログラムを作れ。
なお出力の末尾には改行を書き出すこと。

入力例1
({()[]}[{()()((()))}])({}[])
出力例1
correct
入力例2
({()[]][([{}[]])}{()())(())}({}[])
出力例2

です。

以外書いたコードなのですが、初心者でもありよくわからない部分やへんな部分が多いと思います。どなたかわかる方いらっしゃれば手直しなどしていただけるとありがたいです。よろしくお願いします。

 //#include <string.h>
//#include <stdio.h>
int main(void) {

char s[10000]; scanf("%s", s); int c1 = 0,c2 = 0,c3=0,c4=0,c5=0,c6=0; int i; for(i=0;i<10000;i++) { if(s[i]==')') { c1++; if(c1>c2) break; continue; }else if(s[i]=='(') { c2++; continue; }else if(s[i]=='}') { c3++; if(c3>c4) break; continue; }else if(s[i]=='{') { c4++; continue; }else if(s[i]==']') { c5++; continue; if(c5>c6) break; }else if(s[i]=='[') { c6++; continue; } } if((c1>c2 || c3>c4 || c5>c6) || (c1<c2 || c3<c4 || c5<c6)) printf("wrong\n"); if(c1==c2 && c3==c4 && c5==c6) printf("correct\n"); return 0;

}

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

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

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

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

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

thkana

2020/06/28 08:32

https://teratail.com/questions/271871 に全く同じ問題があるのはともかくとして、 問題にある、 つぎの操作を可能な限り繰り返すことでその記号列が空となるならば、その記号列は正しいという。 という定義を無視してオレサマ判別をしているという時点で「全然ダメ」と言わざるを得ないのではないでしょうか?
anndonut

2020/06/28 12:25

問題文を無視してLL(1)パーサを手書きしようとしてたww
Zuishin

2020/06/28 12:34

問題文は何が正しいかの定義を書いているだけで、このアルゴリズムに従ってプログラムを書けということではないんじゃないでしょうか。
thkana

2020/06/28 12:56

ん~、そうですねぇ。出題の書き方に強い誘導は感じますが、そうでなければNGかどうかは出題者の意思次第、ですか。まぁ、どういう解答を提出するかは質問者さんにお任せします。でも、結果が違うのはマズイでしょう。 (知恵袋でも同じ質問をしている人もいたし:即取り消ししてたけど)
Daregada

2020/06/28 13:36

まあこういう文を書くのは、「これに沿ってコードを書くと楽に解決できるぞー」という出題側の強い誘導なんですが、この段階で自由にやらせると解決にはほど遠い謎コードが量産され、それを出題側はひとつひとつ解読しないといけないから、なんですよね。こういうのが数十個送られてくるところを想像してくれ。
Zuishin

2020/06/28 13:58

私ならテストケースをいくつか用意しておいて、全部通れば OK 通らなければ NG と機械的に採点します。アルゴリズムを固定しても数十個全部読むのは大変なので。まあ実際どうするか知りませんが。
thkana

2020/06/28 22:04

プロなら結果さえ出せばOKですけど、学生の課題でしょうから過程も大事、みたいなところもあるでしょう。 大学の頃、なんかの問題をラブラス変換だったかz変換だったかを使ってちゃかちゃかと解いたら、真面目に解かせたかった教授の不興を買ったのがトラウマになって過剰反応してるかも知れないw
fana

2020/06/29 01:22

(大学なら,課題の採点とかは研修室の学生に丸投げだったりも)
guest

回答4

0

ベストアンサー

他の回答へのコメントでちょこちょこ書いちゃったのも半端なんで、一応こちらで書きましょうか。
まず。質問のプログラムは文字列の終端をチェックしていないので、10000字を必ずチェックしようとします。まぁ大抵wrongになりますね。例えば
for(i=0;i<10000 && s[i]!=0 ;i++) {
とでもして下さい。

次、

C

1for(;;){ 2 if(){ 3 continue; 4 }else if(){ 5 continue; 6 }else if(){ 7 continue; 8 } 9}

という構造になっていて、if文を抜けたら(else節には入らす)ループの最後に即到達するので、continueは無意味です。
もし、elseがなくて

C

1for(;;){ 2 if(){ 3 continue; 4 } 5 if(){ 6 continue; 7 } 8 if(){ 9 } 10}

だったらcontinueも仕事をするでしょうが。

もう一つ、

C

1if((c1>c2 || c3>c4 || c5>c6) || (c1<c2 || c3<c4 || c5<c6)) printf("wrong\n"); 2if(c1==c2 && c3==c4 && c5==c6) printf("correct\n");

なんかすごく一生懸命考えたのかな...と思いますが、c1>c2 || c1<c2ってのはつまりc1!=c2ってことですね。
つまり、これは

C

1if(c1!=c2 || c3!=c4 || c5!=c6) printf("wrong\n"); 2if(c1==c2 && c3==c4 && c5==c6) printf("correct\n");

と書き換えられて、さらにド・モルガンの法則を知っていればまさに
!(c1==c2 && c3==c4 && c5==c6)(c1!=c2 || c3!=c4 || c5!=c6)は等価なわけで、
結局なんのことはない

C

1if(c1==c2 && c3==c4 && c5==c6) printf("correct\n"); 2else printf("wrong\n");

をなんだか複雑に書いていただけ。

で、いろいろ苦労したけれど、テストデータに
[(])
というのを与えると、correctになっちゃうから明らかに間違い...結構根本から考え直さなきゃね、

ということになるわけです。

投稿2020/06/28 12:49

編集2020/06/28 12:58
thkana

総合スコア7639

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

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

yumetodo

2020/06/28 14:45

やっぱりド・モルガンの法則は大事ですよね・・・
kun_monimoni

2020/07/01 10:10

ご丁寧にありがとうございます! 参考にさせていただきます!
guest

0

変数の意味やプログラムの意図がよく分からない。

問題文を素直にそのままプログラムにすればいいのでは?

C

1#include <stdio.h> 2#include <string.h> 3 4int main(){ 5 char data[1000]; 6 int change; 7 int i; 8 char *p; 9 int x,y; 10 11 fgets(data,sizeof data,stdin); 12 data[strlen(data)-1]=0; /* 改行文字削除 */ 13 14 change=1; 15 while(change){ 16 change=0; 17 for(i=0; i<strlen(data); i++){ 18 x=data[i]; 19 y=data[i+1]; 20 if(x=='(' && y==')' 21 || x=='{' && y=='}' 22 || x=='[' && y==']'){ 23 for(p=data+i; *(p+1); p++) *p=*(p+2); /* 2字詰め */ 24 change=1; 25 break; 26 } 27 } 28 } 29 if(strlen(data)==0){ 30 printf("correct\n"); 31 }else{ 32 printf("wrong\n"); 33 } 34 return 0; 35}

投稿2020/06/28 08:30

otn

総合スコア84507

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

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

pepperleaf

2020/06/28 11:20

元の意図はなんとなく、、で、生かしたコードと思ったが、手直しレベルでは難しかった...。
thkana

2020/06/28 11:58

括弧の数を数えているだけで位置的な対応をチェックしてないから、[(]) をcorrect判定しちゃうことになるあたりが手当てしにくいですね>質問者プログラムの方針
otn

2020/06/28 12:02

> 位置的な対応をチェックしてないから、 そうだったんですね。解読を断念して良かった。
thkana

2020/06/28 12:20 編集

無駄なcontinueがいっぱい入っているとか、correct/wrongの判定条件が大変なことになっている(けど位置の件以外は間違ってもいない)というあたりがちょっと読みにくくはありましたが、それほど無茶なことはしてないですよ>質問者のプログラム。種類ごとに開き括弧と綴じ括弧をそれぞれ数えて、閉じ括弧の方が多くなったら即検査終了、最後に開きと閉じが同数かどうかチェックということで。 文字列の終わりを検査していないのは致命的でしたが。(あと、そもそも問題の指示に従っていないところ、か)
kun_monimoni

2020/07/01 10:11

ご丁寧にありがとうございます! 参考にさせていただきます!
guest

0

つぎの操作を可能な限り繰り返すことでその記号列が空となるならば、その記号列は正しいという。

これを無視したコードですが、いかがでしょうか?

C

1#include <stdio.h> // scanf, puts 2#include <string.h> // strchr 3 4int main(void) 5{ 6 const char *a = "({[", *b = ")}]"; 7 char s[1000], t[1000]; 8 int n = 0; 9 scanf("%999s", s); 10 for (int i = 0; s[i]; i++) { 11 char *p = strchr(b, s[i]); 12 if (!p) t[n++] = s[i]; 13 else if (n == 0 || strchr(a, t[--n])-a != p-b) { n = 1; break; } 14 } 15 puts(n ? "wrong" : "correct"); 16}

追記
最後に判定結果を表示するだけで、入力文字列は不要になるから、
char t[1000]; は不要です。char s[1000]; を使えばよくて、
コード中の t[n++] と t[--n] を s[n++] と s[--n] に変更するだけです。

投稿2020/06/28 15:13

編集2020/06/28 16:07
kazuma-s

総合スコア8224

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

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

kun_monimoni

2020/07/01 10:10

ご丁寧にありがとうございます! 参考にさせていただきます!
guest

0

元のコードを生かして、と考えたのは、ギブアップしたのですが、、
(理由は、thkanaさんの書かれたとおり)

なんとかならないか、とちょっと考えてみました。(パズル感覚)

C

1int check(char *s) 2{ 3 char *s0 = &s[1]; 4 char *s1 = s; 5 6 while (*s0 != '\0') { 7 switch (*s0) { 8 case '(': 9 case '{': 10 case '[': 11 s1++; 12 *s1 = *s0; 13 break; 14 case ')': 15 if (*s1 != '(') return 0; 16 s1--; 17 break; 18 case '}': 19 if (*s1 != '{') return 0; 20 s1--; 21 break; 22 case ']': 23 if (*s1 != '[') return 0; 24 s1--; 25 break; 26 } 27 s0++; 28 } 29 if (s1 != s) return 0; 30 return 1; 31} 32 33int main(void) 34{ 35 char s[10000] = {0}; 36 scanf("%s", &s[1]); 37 38 if (check(s) == 0) printf("wrong\n"); 39 else printf("correct\n"); 40 41 return 0; 42}

読込みを1バイトずらして、ガードにしてます。細かな手抜きは多いですが、余分な文字があっても OK。

投稿2020/06/28 13:52

pepperleaf

総合スコア6383

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

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

kun_monimoni

2020/07/01 10:12

ご丁寧にありがとうございます! 参考にさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問