都道府県穴埋めゲーム

#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "str == NULL ? \"(NULL)\": str";
char* p, * q; int ch; p = str;
for (;;) { for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1; }
}

の!(*q == '?' || *q == ':' || *q == 0);において、なぜ'?'、':'、 0を否定しているのにchには'?'、':'、 0が代入され、内部処理が働くのでしょうか?

A 回答 (3件)

> ふぇ〜?



「ふぇ〜?」じゃねぇんだよ。
フザケてる?
フザケてるのなら止めますが。

どっちにせよ、貴方は

* 逐次処理を理解していない

かあるいは、ここ

https://oshiete.goo.ne.jp/qa/12500603.html

で書いた

* 本体が空のfor文

のどっちかを理解してない、ってこった。
どっちだ?
前者ならプログラミングの入門書を最初っから丁寧に勉強しなおせ。
後者ならプログラミングの入門書に書かれてあるforの文法をもう一回読んでみろ、ってこった。

以下後者の「空のfor文を依然として全く理解していない」前提で書いておく。
もう一回問題の箇所を抜書しておく。

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

ここの1行目、for文は「本体が存在しない空のfor文」だ。正式名称は知らんけどな。
ここを、敢えて、現代的な書法で書き直すと上のコード部分は次のようになる。

for(q = p; !(*q == '?' || *q == ':' || *q == 0); q++) {
; /* 本体が何も存在しない。従ってポインタqが進むだけで他に何もしない */
}
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

あるいは次のように書いても良い。

for(q = p; !(*q == '?' || *q == ':' || *q == 0); q++) {;} /* 本来ならサイテーでもこのように書くべき */
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

そういう風に書き換えてコンパイルして実行してみろ。全く問題なくコンパイルを通るだろ?実行結果も同じだ。
言い換えると、

for (何とやら) {;}

の省略記法が

for (何とやら);

だ。
そして後者は意味不明になりやすいのでなるたけ使うべきではない書き方だ。
何故なら貴方はこの書き方のせいで混乱したんじゃねぇのか。

つまり、件のforの下に続く五行

ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

は件のforには属していない。あくまで外側にあるfor(;;)傘下のブロックに属している。

なぁ。
ひょっとしてこの五行(ch = *q〜p = q + 1)がfor(q = p; !(*q == '?' || *q == ':' || *q == 0); q++)のブロックに所属してる、って勘違いしてた?
だからんな事はないっての。「本体が空のfor」だ、って何度説明した?

これはな、IDEとか使って、自動インデントとか有効にしてればすぐ分かるんだよ。まぁ、開発環境で何使ってるんだか知らんけど。
仮に件の五行がfor(q = p; !(*q == '?' || *q == ':' || *q == 0); q++)の形作るブロックに所属してるんだったら、インデント(字下げ)が起きる筈なんだよ。
それは起きないの。あるいはIDEを使って自動インデントを有効にしてるなら「起きなかった」だろ?
それは

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

の6つは全部平等にfor(;;)が形作るブロック属していて、結局この6つの間には「逐次処理」が素直に実行されてるだけ、なんだって。
だから

> !(*q == '?' || *q == ':' || *q == 0);において、なぜ'?'、':'、 0を否定しているのにchには'?'、':'、 0が代入され、内部処理が働くのでしょうか?

は明らかに「バカな質問」なんだよ。
何故ならどっちにせよ、

> !(*q == '?' || *q == ':' || *q == 0);において、なぜ'?'、':'、 0を否定している

のと

> chには'?'、':'、 0が代入され、内部処理が働く

ってのは直接は全く関係がない。
結局逐次処理に従って粛々と処理されていけば書かれた通りに順番に実行されていってるだけ、だからだ。

分かったかい?
    • good
    • 4
この回答へのお礼

ありがとうございます。

お礼日時:2021/08/08 20:09

?


何言ってんの?

貴方、こんな質問したら

「ワタシはプログラムの読み方が分かりません」

って言ってるだけですよ?
「プログラムの読み方が分からない」って言ってる人間に対して言える事は

「プログラミングの勉強を基礎からやりなさい」

としか言いようがないです。
・・・・・・いや、ホンマこんなクソみてぇなコードを背伸びして読んでねぇで基礎の基礎からやり直せよ。教科書の最初っから、だ。
ホンマ「全く分かってない」って事になってんだって。
本音言うと「バカな質問してんじゃねぇ」ってなカンジだ。

特別に概要を纏めておいてやる。
耳かっぽじってよく聞きやがれ。

昔、エドガー・ダイクストラと言う偉い計算機科学者が、プログラムと言うのは基本的に3要素しかない、と言う事を纏めた。
その3つとは

1. 逐次処理
2. 分岐処理
3. 反復処理

だ。
2.はC言語で言うと主にif構文、3はforだwhileだと言う構文の事だ。一見初心者が一番引っかかるのはここだ、とか思われている。
一方、1.の逐次処理。「ちくじしょり」と読む。
何書いてんだかサッパリ分からんかもしれんが、要するに

「プログラムは書かれた順番通り、上から下へと処理されていく」

ってこった。一見すげぇクソみたいに当たり前の事と思われる。
ところがだ。
経験上、「クソみたいなど素人が」実は一番引っかかるのがここなんだ。
貴方の事だよ。
「プログラムは書かれた順番通り、上から下へと処理されていく」ってのが実は全く分かっていない。

取り敢えず余計なモノを取っ払った問題の箇所を抜き書きしてみる。

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);
ch = *q;
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

この部分もダイクストラと言う学者が言った通り、「上から順番に一つ一つ順序よく実行されていく」んだ。「上から順番に」だ。決してどっかにいきなり飛んだりはしない。
ところが、1行目が反復になっている。
と言う事は、1行目の反復処理が終了しない限り2行目には移らない、って事だ。
当たり前だよな。
いや、プログラム書いたり読んだりする事に慣れた人にとってはあまりにも「当たり前」なんだけど、貴方みたいな「ど素人」な人にとっては実は当たり前ではない、と言う事が今露見してる。だから意味不明な質問をする事になってるんだ。

1行目の反復処理が終了するには終了条件が必要だ。その1行目の反復の終了条件が

(*q == '?' || *q == ':' || *q == 0);

つまり、ポインタqが指し示した場所が'?'か':'か0だった時、だ。この時に反復が終了する。
Cのforの文法上、「非終了条件」的なモノを書かないといけない。つまり「この条件を満たす間繰り返しをせよ」って事だな(実はこれが前書いた通り「本体が空のfor」なんで「繰り返すべき本体がない」ってのがややこしさを生んでいるが)。結果、上の終了条件を否定したモノを構文上要求するわけ。
いずれにせよ、だから1行目は

!(*q == '?' || *q == ':' || *q == 0);

と記述する事を要求してる。それだけ。それ以上でもそれ以下でもない。

もう一回繰り返す。1行目が終了しないと2行目が始まらない。その為1行目には終了条件が必要で、それが(Cの文法上)!(*q == '?' || *q == ':' || *q == 0);と記述されてるだけ、だ。「1行目を終了する為だけ」だ。そうじゃないと2行目に進めない。

分かるか?1行目を終了させる為に!(*q == '?' || *q == ':' || *q == 0);が存在する。
「chには'?'、':'、 0が代入され、内部処理が働く」のとは「全く関係がない」のだ。

もう一回問題の箇所を抜き出して書く。

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);
ch = *q;                   /* '?'か':'か0が代入される */
*q = 0;
printf("|%s|\n", p);
if (ch == 0) break;
p = q + 1;

1行目、が終了されてはじめて2行目が実行される。2行目で何かが代入されてるが、極論「構文的には1行目とは全く関係がない」のだ。単に1行目で計算されたポインタqを利用しているだけ、である。構文的には

i = 1
j = i + 2

とか書いてるのと全く同じだ。

分からなければ悪い事言わんから入門用の教科書の最初っから勉強しなおせ。
ポインタもまだ早い。勉強不足に準備不足だ。
じゃなければ。
プログラムを読む際に一番引っかかるのは「逐次処理」だ、って事は既に話した。言い換えると「全くのど素人」と「慣れた人」の違いは、逐次処理、ってプログラミングの流れを自然に読めるか読めないか、と言う辺りになる。
逐次処理が分かってない人は、貴方のように「全く別の文として記述してるのに無理矢理結びつけて考えようとしてドツボにハマる」のだ。
と言う事は、逐次処理を意識して読むしかない。どっちにせよ「書かれた通りに上から下へと順番に処理していく」のがプログラム言語の記述法だ。逐次処理を意識してプログラムを読むように訓練するしかない。
    • good
    • 4
この回答へのお礼

ふぇ〜?

お礼日時:2021/08/08 16:47

否定を外して以下で読み替えれば解りやすいんじゃないですかね


どモルガンだかなんだかという法則でしたっけ?

for (q = p; (*q != '?' && *q != ':' && *q != 0); q++);
    • good
    • 0
この回答へのお礼

なんて賢いんだ!?

お礼日時:2021/08/08 16:48

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!