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

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

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

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

Q&A

4回答

1523閲覧

for文の条件と論理演算子の「否定」

carnage0216

総合スコア194

C

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

0グッド

0クリップ

投稿2021/08/08 02:11

編集2021/08/08 02:41

1,質問があります。

#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が代入され、内部処理が働くのでしょうか?

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

2,質問

#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);を(*q == '?' || *q == ':' || *q == 0);とした場合、画像のようなエラーが出るのですが、なぜでしょうか?また(*q == '?' || *q == ':' || *q == 0);とした場合、どのような処理のプログラムになるのでしょうか?
エラー画像

3,最後に以下のようにプログラムを書くと

#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; } } }

以下のようなバグが起きました。これはバグということでかたずけていいでしょうか?
というか、なぜこの様な実行結果になったのかが、わかりません。

|| || || || || || || || || || || ||

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

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

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

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

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

m.ts10806

2021/08/08 02:29

タグに「デバッグ」を入れている割にデバッグ全くしてないですよね。ふざけてますか?
m.ts10806

2021/08/08 02:30

>以下のようなバグが起きました。 書いた通りに動いた結果。書いたのは誰?
pepperleaf

2021/08/08 02:31

> これはバグということで バグと言うのは、こうあるべきという事に対して、異なる動きをする事ですが、期待する動きとはなんでしょうか? それが無いとバグとは言えません。 なお、ソースを見る限り、書かれたように動作してると思われます。 また、指摘がすでにあるようですが、過去の質問の続き?
carnage0216

2021/08/08 02:37

続きというか、新たな疑問点です。
Zuishin

2021/08/08 02:38

> 以下のようなバグが起きました。これはバグということでかたずけていいでしょうか? 国語力。
episteme

2021/08/08 03:02 編集

その疑問を解消するためにデバッガ使ってるんじゃないのか? あちこち書き換えてその挙動を観察するのがデバッガの目的。観察しているか? マルチポストの「ルールを守らない」理由はなにか? マルチポストのルールを知らないのか? それとも知ってて無視か?
thkana

2021/08/08 03:36

「ルールなんて守らなくても罰則があるわけじゃない」から守る必要を感じないのでしょう。 ついでに言えば、「罵倒した相手でもしばらく期間をおいて質問すれば応えてくれる」という学習をさせてしまったように思いますが如何?
退会済みユーザー

退会済みユーザー

2021/08/08 04:43

回答付ける人が居る限りやめないでしょうな。
m.ts10806

2021/08/08 07:22 編集

本人の姿勢(と根本的な理解力)が変わらない限りどこで聞いても同じ。
guest

回答4

0

1

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

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

「*q が '?', ':', '\0' のいずれか」ではない 間 loopを繰り返すのだから、
「*q が '?', ':', '\0' のいずれか」となった時点でloopを抜ける。

2

!(*q == '?' || *q == ':' || *q == 0);を(*q == '?' || *q == ':' || *q == 0);とした場合、画像のようなエラーが出るのですが、なぜでしょうか?

「*q が '?', ':', '\0' のいずれか」である 間 loopを繰り返すのだから、
loopを抜けた時点で *q は '?', ':', '\0' ではない。
したがって if (ch == 0) break; によって 外側のloop:for(;;) ... を抜けることができない。

3

これはバグということでかたずけていいでしょうか?

それが期待する動作であるなら、バグではない。如何なる動作を期待していたのか?

投稿2021/08/08 02:45

編集2021/08/08 02:52
episteme

総合スコア16612

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

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

carnage0216

2021/08/08 03:53

loopを抜けた時点で *q は '?', ':', '\0' ではないため、forの処理内容が働かない、 ゆえに ch = *q; *q = 0; printf("|%s|\n", p); if (ch == 0) break; p = q + 1; が働かないため、要はif (ch == 0) break; が働かないため、永遠にループするということですか? すいません、もうすこしわかりやすく教えてください。
episteme

2021/08/08 04:01

↑は1,2,3のどれに対するもの?
episteme

2021/08/08 04:12

ともかくエピカス(僕のことよね?)の解説は(あなたには)「壊滅的にわかりにくい」らしいから、 わかりやすいコタエを期待しないでね。
carnage0216

2021/08/08 04:35

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

2021/08/08 04:37

回答で述べた。 > 「*q が '?', ':', '\0' のいずれか」ではない 間 loopを繰り返すのだから、 > 「*q が '?', ':', '\0' のいずれか」となった時点でloopを抜ける。
kazuma-s

2021/08/08 04:50

「なぜ'?'、':'、 0を否定しているのに」 '?'、':'、 0を否定していません。括弧の中の値を否定しています。 括弧の中は、「*q が '?'か ':' か 0 か」です。 どれとも等しくない場合、この値は 0 です。 ! でそれを否定すると 1 です。だからループを実行します。; と q++ を実行します。 どれか一つに一致すると、この括弧の中の値は 1 です。 ! でそれを否定すると 0 です。だからループを終了します。 この for文の次の文の ch = *q; を実行します。 すると ch には一致した文字が入ります。
fana

2021/08/08 04:52

forがダメならwhile… という話すらどうやら無理だったようなので これはもうフローチャートを描くところからやったほうがいいんじゃないかな
episteme

2021/08/08 05:00

低評価の理由を求む。
carnage0216

2021/08/08 05:12 編集

kazuma-sさんの解説が一番わかりやすいです。やっぱkazuma-sは天才だぁ。
carnage0216

2021/08/08 05:23

ん、for文のループが終わったら、次の文の ch = *q; を実行するのですか?
carnage0216

2021/08/08 05:49 編集

>> 括弧の中は、「*q が '?'か ':' か 0 か」です。 文字列の?や;や0と一致した場合は1でありが、!により0となりループ終了、そして、ch = *q; が実行され、?や;や0がchに代入されるという事でしょうか? あれ、ループしている時にしか中身の処理を実行できないから?や;や0がchに代入できないんじゃ、、、。
Zuishin

2021/08/08 05:38

「わかりやすい」という言葉をわからない時に使う国語力。
episteme

2021/08/08 06:02 編集

> for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++); > というループはループ内で実行すべき文がない (いわゆる空文) であることがわかっていますか? > ch = *q; はこのループが終わった後で実行されるのであって、ループ内で実行されるものではないですよ。 に、あなたは「それはわかっております」と答えたぞ?
episteme

2021/08/09 22:03

...音沙汰なくなりましたが、解決したんですかね?
guest

0

#1

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++); というループの意図を日本語にするなら「*q'?' ':' 0 のいずれでもない間は繰り返す」ということは理解できているでしょうか? これは逆に言うならば「繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれかである」ということです。

ですから ch = *q; が実行されると ch には必ず '?' ':' 0 のいずれかが入っていることになるのです。

#2

上記の条件を逆にするということになりますから「*q'?' ':' 0 のいずれかである間は繰り返す」という意味になります。 そして「繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれでもない」ということを意味します。

'?' でも ':' でも 0 でもないところを全て 0 に置き換える処理になります。 そして if (ch == 0) break; が成立することは決してないので元の文字列の終端に到達しても延々と処理を継続してしまうのでデタラメな場所のメモリを書き換えてしまいます。

確保していないデタラメな場所にアクセスした結果は未定義であり、何がおきてもおかしくありません。

#3

上のコードから推察すると文字列を '?'':' で分割したいという意図があると思うのですが、質問3の書き換えはどのような意図でしょうか?

目的 → それを実現するコードを書く → 意図通りではない

というのがバグであって、何を意図して書き換えたのかわからないとどうとも答えられません。

投稿2021/08/08 02:43

SaitoAtsushi

総合スコア5684

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

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

carnage0216

2021/08/08 03:11

一番目 >>「繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれかである」 なるほど、繰り返しが終わるのは否定されている '?' ':' 0 のいずれか*qに代入されるときですよね。 分かりやすいです。ありがとうございます。 二番目 >>「繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれでもない」 文字列の中の '?' ':' 0 のいずれかは条件(*q == '?' || *q == ':' || *q == 0);により *q = 0; により0になると思います。なぜ '?' ':' 0 以外の文字が0になり、かつif (ch == 0) break; が成立することは決してないのでしょうか。理解できなくてすいません。 3番目に関してはこのように書いたときになぜ結果がこうなるのかという疑問ゆえに質問しました。
SaitoAtsushi

2021/08/08 03:42

> if (ch == 0) break; が成立することは決してないのでしょうか。 繰り返しますが質問2は質問1の逆の状況なんですよ。 0 のときなら for (q = p; (*q == '?' || *q == ':' || *q == 0); q++); のループが続いてしまうので、このループが終わった後に 0 であることはあり得ません。 > 3番目に関してはこのように書いたときになぜ結果がこうなるのか そのようなプログラムになっているからとしか言いようがないです。 別の結果になるべきという理解をしているのであればどういう動作をしてどういう結果になると考えているのか、その根拠は何か解説していただければ間違っている箇所を指摘できます。
carnage0216

2021/08/08 03:50 編集

あの1について、 繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれかである」とのことですが、 否定された'?' ':' 0 のいずれかである時にforのch = *q; が実行されるのはなぜでしょうか? ch = *q; が実行されると ch には必ず '?' ':' 0 のいずれかが入っていることになるのです。とのことですが、 '?' ':' 0 は否定されているため、forのch = *q; は実行されないのではないかと思うのですが、どうか何を間違っているのか教えてください。
carnage0216

2021/08/08 03:53

「繰り返しが終わったときは q が指している先 (*q) が '?' ':' 0 のいずれかである」 ですが、 for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++) ch = *q;より、 '?' ':' 0 のいずれかの文字がchに入るのではないかと思ってしまいます。
SaitoAtsushi

2021/08/08 04:16

根本的な勘違いがあるような気がするので念のために確認しますが for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++); というループはループ内で実行すべき文がない (いわゆる空文) であることがわかっていますか? ch = *q; はこのループが終わった後で実行されるのであって、ループ内で実行されるものではないですよ。
carnage0216

2021/08/08 04:29

それはわかっております。 しかし、 for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++)ch = *q;のch = *q;においてはループが実行されている時に実行されるのでしょうか?
SaitoAtsushi

2021/08/08 04:44

申し訳ないですが質問者が何を分かっていないのか私には理解できなくなったので応答はこれで終わります。 この件については以降はコメントしませんので他の方の回答に期待してください。
episteme

2021/08/08 04:47

for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++) { ch = *q; } を(デバッガで)ステップ実行すればわかることを訊くのか? 回答者はデバッガではない。
episteme

2021/08/08 04:54

低評価の理由を求む。
guest

0

for文を for (A; B; C) D とします。
A は初期化、B は判定、C は更新、D は処理です。

C

1 for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++) ; 2 ch = *q;

このようなコードがあった時、
A は、q = p
B は、!(*q == '?' || *q == ':' || *q == 0)
C は、q++
D は、;

ch = *q; は for文の一部ではありません。
for文の次の文です。for文が終了したら、その次に実行されます。

さて、質問です。
単独の ; が空文であり、何もしない文であることを知っていましたか?

C

1 for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++) { 2 ch = *q; 3 ... 4 }

このようなコードがあった時、
D は、{ ch = *q; ... } です。
D は、ループの一部です。
B の判定でループ続行のとき、D が実行されます。
ch = q; も実行されます。
D の実行終了後、C の q++ が実行されます。
次にループ判定の B が実行されます。

ループ終了後には ch = *q: は実行されません。

追記
Visual Studio のステップ実行は行単位なので、

C

1 for (q = p; !(*q == '?' || *q == ':' || *q == 0); q++);` 2 ch = *q;

これだと for文の動きが分かりません。
そこで、次のように書き換えてからデバッグ実行してみてはいかがでしょうか?

C

1 for (q = p; 2 !(*q == '?' || *q == ':' || *q == 0); 3 q++) 4 ; 5 ch = *q;

追記2
何をするコードかを分かっていないのではありませんか?

文字列を区切り文字('?' と ':')で分割して、
分割された各文字列を表示するプログラムです。

すべての行にコメントを付けてみました。

C

1#include <stdio.h> 2 3int main(void) 4{ 5 char str[] = "str == NULL ? \"(NULL)\": str"; // 配列strを文字列で初期化 6 char *p, *q; // p と q は、分割した文字列の先頭と末尾を指すためのもの 7 int ch; // ch は、発見した区切り文字を入れるためのもの 8 p = str; // p はポインタで、str[0] のアドレスを持つ。str[0] を指す 9 for (;;) { // 無限ループ。途中の break でループを終了 10 // 次の for文は、str中の区切り文字の位置を探すためのもの 11 for (q = p; // q はポインタで、最初は str[0] を指し、 12 // for(;;)ループの 2回目からは分割した残りの文字列の先頭を指す 13 !(*q == '?' || *q == ':' || *q == 0); 14 // q の指す文字が区切り文字や strの終端でなければ、ループを続行 15 q++) // q は、str中の次の文字を指す(ループの本体の ; の次に実行) 16 ; // ループの本体の文だが何もしない 17 18 ch = *q; // ch は、上のforループ終了後 q が指している区切り文字 19 *q = 0; // q が指している str の文字を '\0' に変える。分割できた! 20 printf("|%s|\n", p); // str中の p から q までを表示 21 if (ch == 0) // str の最後まで達したならば、 22 break; // for(;;) のループを終了 23 p = q + 1; // p は、今 分割した残りの文字列の先頭を指す 24 } 25}

分からないのはどこですか?

投稿2021/08/08 07:00

編集2021/08/10 02:51
kazuma-s

総合スコア8224

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

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

0

!(*q == '?' || *q == ':' || *q == 0);において、なぜ'?'、':'、 0を否定しているのにchには'?'、':'、 0が代入され…

forが理解できないならwhileで書いてみたらいいじゃない(2回目).

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

のループをwhileを用いて書いたらこう↓

C

1//最初に,変数qにpの値を代入する 2q = p; 3 4while( 1 ) 5{ 6 // qが指す先が '?' であればループを抜ける 7 if( *q == '?' )break; 8 // qが指す先が ':' であればループを抜ける 9 if( *q == ':' )break; 10 // qが指す先が 0 であればループを抜ける 11 if( *q == 0 )break; 12 13 //qの値を更新 14 q++; 15}

で,このループの直後に ch = *q; がくるのだから,こういう話になっているわけだ↓

C

1//最初に,変数qにpの値を代入する 2q = p; 3 4while( 1 ) 5{ 6 // qが指す先が '?' であればループを抜ける 7 if( *q == '?' )break; 8 // qが指す先が ':' であればループを抜ける 9 if( *q == ':' )break; 10 // qが指す先が 0 であればループを抜ける 11 if( *q == 0 )break; 12 13 //qの値を更新 14 q++; 15} 16 17//ループの直後に,chに *q の値を代入する処理がある 18ch = *q;

このwhileのループ中に *q が '?' になったとき,chには何が代入されることになるのか?
って考えたら,これはもう自明だと思うのですが,どうでしょうかね.

投稿2021/08/08 06:53

fana

総合スコア11996

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問