for文を for (A; B; C) D とします。
A は初期化、B は判定、C は更新、D は処理です。
B の判定が 3回ループ続行 で、4回目にループ終了になるとすれば、
次のように実行されます。
A
B D C (1周目)
B D C (2周目)
B D C (3周目)
B
1周目は C が実行されないのではなく、ループの最後で実行されます。
ソースに書かれているのが、A B C D の順なのに、B の次が D だから
1周目は C が実行されないと思っているのでしょうか?
ch の値が気になるのなら、ch = *q; の行にブレークポイントを置いて、
この行の実行前の ch の値を見て、ステップ実行で
ch = *q; 実行後の ch の値がどう変わるかを見ましょう。
ch = *q; は3回通るので、その全部の値を見てください。
コメントをお願いします。
追記
疑問があります。なぜforループの二周目以降のデバッグでのstr[]の中身はstr == NULLであるのに、一週目のみstr[]の中身はstr == NULL ? "(NULL)": strであるかについてです。
質問の最初の部分について回答します。
Visual Studio で変数の値を見ていますよね。
変数strの値として、その変数のアドレスと、
そこから'\0'までの文字列が表示されています。
str の前の「右向き△」をクリックして「下向き▽」にしてください。
str[0]~str[27] がすべて表示されます。
表示ウィンドウが画面の下にあって全部見えないなら、
その表示ウィンドウをドラッグして右側に移動して縦に長くしてください。
str[0] が 115 's'
str[12] が 63 '?'
str[22] が 58 ':'
str[27] が 0 '\0'
外側の for(;;) のループの 1周目で *q = 0;
を実行する前は
str[27] が '\0' なので、str は文字列全体が表示されます。
*q = 0;
を実行すると、str[12] が 0 '\0' になり、
変数 str の文字列表示は "str == NULL" だけになります。
str[0] から str[12] までの文字列を表示しているからです。
2周目で *q = 0:
を実行すると、str[22] が 0 '\0' になりますが、
変数 str の文字列表示は "str == NULL" のままです。
str[0] から str[12] までの文字列を表示しているからです。
3周目で *q = 0:
を実行すると、元から 0 の str[27] が 0 のままで、
変数 str の文字列表示は "str == NULL" のままです。
str[0] から str[12] までの文字列を表示しているからです。
なお、printf("|%s|\n", p); で表示しているのは、
str の中の p から q までの部分文字列です。
1周目は str[0]~str[12] の "str == NULL"
2周目は str[13]~str[22] の " "(NULL)""
3周目は str[23]~str[27] の " str"
以上のことを Visual Studio で試してみて確認し、
説明が理解できたかどうかをコメントしてください。