• ベストアンサー

for文の;で区切られる3つの要素は文扱いになるのですか?

すみません。昨日、某巨大掲示板で質問したのですが、アクセス規制喰らったので。。ここで聞かせてください。C言語を色々と実験中の者です。 int a[]={1,2,3,0}, *p=a-1; for(;*p++;){ // 何らかの処理 } とすると、*pが終了条件に当てはまってないか確認されてからp++されるということをしりました。 これは printf("%d", *p++); の一文がまず*pの値が(インクリメントする前の値が)%dに代入され表示されて、そのあとにp++でインクリメントされるのと似ています。というか、動作は一緒です。これは、後置インクリメント演算子は、その一文が評価されてから、インクリメントされるということですが。 そうすると前述のfor(;*p++;)のp++;の部分も文と考えれらるような気がするのですが。。;で区切られていますし、やはり文法的に言うと文になるのでしょうか? マルチになるのかもしれませんが、よろしくお願いします。某巨大掲示板をプロバイダ規制喰らったので。。

質問者が選んだベストアンサー

  • ベストアンサー
  • dummyplug
  • ベストアンサー率58% (134/230)
回答No.2

結論から言うと、文ではなく式です。 質問の中には色々間違った解釈があるのですけれど、まず*p++の解釈を覚えてください。後置インクリメント演算子は「対象の左辺値(ここでは変数p)の値がインクリメントされ(+1した値に置き換えられる)、その値はインクリメント前の値」という演算子です。 ですから、例えばprintf()の例で、まず*pの値が~というのは違っていて「pの値が+1される。(p++)の値は+1されるまえのpの値。*(p++)の値は+1されるまえのpの指しているアドレスの値。それが%dに対応して(文字列化されて)表示される」です。決して「一文が評価されてからインクリメント」などという「文」を単位とした実行順序の解釈と式の評価とは関係ありません。 文の解釈と(一つの文の中の)式の評価順序(代入順序も然り)は関係ありません。 もう一度、もとの話に戻って説明すると >*pが終了条件に当てはまってないか確認されてからp++される というのは違っていて、 1) pのインクリメント 2) p(インクリメント前)の指すメモリからの値の取り出し 3) 2で取り出した値が0かどうか(終了条件)を判断 という順序です。インクリメントのタイミングは文の終わりとかそういうタイミングとは関係なく、式の評価の中で行われるものです。 ただし、コンパイラがどういう順序で実行するようにコードを出力するかはまた別の問題です。仮に順序を変えたとしても上のような解釈に影響を与えない範囲で(例えばpの値が参照されるまでインクリメント値の代入を遅らせるコードを出力するとか)出力コードの順序を変更することはあるでしょう。

kamkamkam3
質問者

お礼

どうもありがとうございます。 とてもよく、インクリメント演算子がよくわかりました。+1されてるんだけど、表示される値は+1される前の値なんですね。こんなこと、どの書籍にものっていないので、教えていただきとても助かります。 あと、for文の終了条件の順序もおかげさまで完全に理解できました。for文とか本で言う一通りの使い方はわかりましても、このような完璧な動作内容まで理解できるととても感動しますね。 また、コンパイラによって出力される機械語が違うというのは2chでよくみるんですが、自分には理解できなかったのですが、一番最後の詳しい解説により理解できました。ん~、なるほど各メーカーのCコンパイラによって規約にそぐわない範囲で出力コードが違うという事なんですね。 しかし、とても勉強になりました。私など、独習Cとネットくらいしか情報手段がないので。。 本当に参考になりました。正直なところ、ちょっと感動を覚えています。Cは細かいところが真のおもしろさとも思えました。とてもご丁寧な回答ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

Cの場合、第1節は「式」または「宣言」です。したがって「文」ではありません。 ちなみに、C++では第1節は「文」になります。ただし、一般的な文ではないので、ここに記述できる内容は限られています。具体的には、forの第1節に、for文やgoto文やreturn文などは記述できませんし、複合文も記述できません。記述できるのは、式文と単純宣言だけです。 また、第2節には、 for (int i = 0; char c = str[i]; i++) のように宣言を含めることができますが、これは文扱いではありません。宣言できるのもスカラ型に限られます。

kamkamkam3
質問者

お礼

なるほど、式、文以外に宣言という手もあるのですね。 そういわれてみるとそうだなあとおもいます。Javaをやっていたこと無意識にfor(int i=0;~;~)とやってましたが、あれは文なんですね。CとC++での定義の違いがこんなところにもあるんだなあと感心しております。 例で紹介いただいたfor文の第2節は宣言になるんですね。C++も興味があるので、近いうちに色々調べてみようとおもいます。 私は元来単純な計算が好きだったので、Cの素朴なプログラムに工夫をするのが今面白いです。いい頭の体操にもなりますし。 どうも今回はありがとうございました。感謝します。

全文を見る
すると、全ての回答が全文表示されます。
  • dummyplug
  • ベストアンサー率58% (134/230)
回答No.3

ANo.2で回答したものです。 少し補足します。 ある記述が(C言語の文法に照らし合わせて)「文」であるか「式」であるかというのはC言語の文法を調べれば正しい意味で判断することができます。ですので、できれば実験などといわずにそういう規約(規格)を参照するのがよいと思います。 ここでは質問の場合について、一例を示します。 C言語には複文というものがあります。いくつかの文をとりまとめたもので、一つの文を書けるところに書くことができます。例えばif文の書式(文法)は if (式) 文 ですが、条件式が成り立つとき(値が真であるとき)に複数の文を実行したいことはあります。そこに複文を使います。こんな感じです。 if (a[i] > x) {  x = a[i];  index_max = i; } この{ ... }の部分が複文です。ifの条件成立時に実行する文は一つだけ書くことができます(上記のif構文)けれど、そこに複数の文を書くために一つの複文にまとめています。 上に書いたように「一つの文を書けるところには複文を書くこと」ができます。では、次の記述は許されるでしょうか。 for (i=0; { i++; check(); i < 100; }; ) ... for文の構文は for (式; 式; 式) 文 であって、()内の";"は単に式の区切りです。式につけて文を構成するための";"とは違うものです。

kamkamkam3
質問者

お礼

2度目の回答ありがとうございます。 なるほど。式と文の明確な違いもやはりしっかり理解しないといけないですね。英文法とかだとわりあいアバウトでも会話が通じますが。。試験は通らないですもんね。 文法というのがここまで厳しいか?というのが、ちょっと意外であり、正直な感想です。私はサンデープログラマなのであれなんですが、仕事なんかだと厳しくなきゃやってられなさそうですね!もともとWinAPIをやっているためにCを細かく知ろうとしたんですが、なんかCの単純だけど、機械語に近い面白さを知りまして。。もっぱら、こっちやってます。 とにかく、これからは、規約を調べてみてみようとおもいます。 2度にわたる、ご丁寧な解説ありがとうございました。とても、勉強になりました。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

文法的に言うと文です。あってますよ。 質問とは別のところで気になるところがふたつ。 1.「*pが終了条件に当てはまってないか~」ではなくて、真/偽の判定です。 2.「*p=a-1;」のあとすぐfor文の中で*pを評価してますが、これは環境によってはクラッシュしますし、真/偽の判定も意図した通りにはなりません。

kamkamkam3
質問者

お礼

どうもありがとうございます。 なんか、Cは細かいことが結構厳しくとり決まっていますね。私はJavaやらPHPをやっていたのですが、Cの厳しい文法の取り決めが新鮮でもあり混乱の元でもあります。。 ご指摘いただきました、1,2についての問題点ですが、2の場合はかなりあぶないんですね。なにぶん、本とネットしか情報収集手段がないので、そこまで書いてある情報にたどり着けませんでした。私は、サンデープログラマなので・・・ 有益な情報をありがとうございました。2については、気をつけます。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • Perlインクリメントデクリメント

    あっていますでしょうか? インクリメント演算子とデクリメント演算子 インクリメント(加算)演算子は変数の数値を一つ増やす。 デクリメント(減算)演算子は変数の数値を一つ減らす。 ++ インクリメント演算子 変数の値を1増やす $a++ ++$a $aの値を1増やす -- デクリメント演算子 変数の値を1減らす $a-- --$a $aの値を1減らす $a=1; 変数$aに1を代入する print "はじめは$aでした。\n"; $aの代わりに1が入り はじめは1でした。と表示する。 $a++; $aに1を足す。 print "1増えて$aになりました。\n"; $aの代わりに2が入り、1増えて2になりました。 と表示する。 $a--; $aから1減らす。 print "1減って$aに戻りました。\n"; $aの代わりに1を入れて 1減って1に戻りました。 と表示する ↓ 実行結果 ↓ はじめは1でした。 1増えて2になりました。 1減って1に戻りました。 $a++ と ++$a の違い インクリメント演算子、デクリメント演算子には2通りの書き方があります。 ++$a(前置)と$a++(後置) --$a(前置)と$a--(後置) 前置の場合は変数の参照より先に演算が行われます。 後置の場合は変数の参照より後に演算が行われます。 $x=$a=1; 変数$xと$aに1を代入する。 $x=++$a; $aに1を足した後に$xに代入する。$xの値は2になる。 $x=$a=1; 変数$xと$aに1を代入する。 $x=$a++; 変数$aの値を$xに代入した後に$aに1を足す。$xの値は1。 文字もインクリメント出来ます。 $x="A"; "A"を$xに代入する。 $x=++$x; Aから一つ増やしてBにして$xに代入する。 $x="aaa"; "aaa"を$xに代入する。 "aaa"を一つ増やして"aab"を$xに代入する。 ただし、文字のデクリメントはできません。

    • ベストアンサー
    • Perl
  • for文

    整数を読み込んで、その値を0までカウントダウンしながら表示するプログラム作りたいのですが、 while文ではできたのですが、for文ではうまくいきません。 どこが間違っているのでしょうか? OS:Windows XP C++Builder X パーソナル #include <stdio.h> int main(void) { int i; int num; printf("整数を入力してください:"); scanf("%d", &num); for(i = num; i <= 0; --i) { printf("%d", i); } return 0; } 宜しくお願いします。

  • C言語でfor文を用いたプログラミングについてです。

    C言語のプログラミングの課題で以下のような表をfor文を用いて作るというものが出ました。 商品名 単価(円)個数(円) 計  A  50   20   ***  B  90   30   ***  C  30   80   ***        合計金額   *** A,B,C及びそれぞれの単価、個数の値はキーボードからの入力で、***は演算によりその結果を出力するようにします。つまり、商品名(1文字)と単価、そしてその個数をキーボードから入力すると、単価と個数をかけた値と、それら全ての合計が出力されるようなプログラムを作るということです。 私は以下のようなプログラムを作りました #include<stdio.h> int main(void) { int a,b,c,sum,allsum,i; printf("商品名 単価 個数 計\n"); for(i=1;i<=3;i++) { a=getchar(); scanf("%d %d",&b,&c);  sum=b*c; allsum +=sum; putchar(a); printf(" %d %d %d \n",b,c,sum); } printf("合計金額 %d\n",allsum); return 0; } しかしこれでは合計金額がちゃんと表示されなかったりしてうまくいきません。おそらくfor文の中身に問題があると思うんですが…。どうか正しいプログラムと、なぜこのプログラムではうまくいかないのかを教えていただきたいです。なにぶん初心者なもんで、よろしくお願いします。

  • for文

    for文なのですが、 scanfで得た、 iを for文のi--で、一づつへらしてますが、 0でfor文がおわりますが 0で終わりの記述がない気がするんですが、 どうしてでしょか? int main(void) {    int i;    printf("正の整数を入力してください。\n");    scanf("%d",&i);    for( ; i ; i--)    printf("qが入力されました。\n");    return 0; }

  • インクリメントについて

    インクリメントについて C言語のプログラム中に(1)の文(前置演算子)が存在するのですが、(2)の文(後置演算子)に置き換えても構いませんか? if(a) ++a; ・・・(1) if(a) a++; ・・・(2) 教授下さい。 よろしくお願い致します。

  • for文を簡単な処理に書き変えたい

    いま、配列を作る作業をしているのですが、for文を使うと、forをいくつ書けば良いのか分からない状態です。 作ろうとしている配列が、A[X][Y]で、Xの要素数は固定で良いのですが、Yの要素数が実験のたびに変動するためです。そして、処理したいのが、この配列の各列の値を適当な値(このfor文の前に値が決まっています)を代入することです。 例えば、for文だと、Y=3のときには for(i=0;i<○;i++){ for(j=0;j<○;j++){ for(k=0;k<○;k++){ A[line][0] = C[i];//(Cという配列のi成分) A[line][1] = B[j]; A[line][2] = E[k]; } } } のように書くような内容なのですが、Yが増えると、for文も増やさないといけません。 ここで、再帰処理のような方法をつかってうまく書きたいのですが、どう書いたら良いのか分かりません。 一般的なfor文の書き換え方みたいなことでも良いので、教えて頂けませんか?宜しくお願いします。

  • for文

    #include <stdio.h> int main(void) { int i; int sum=0; int num, tmp; printf("整数は何個かな:"); scanf("%d",&num); for(i=0; i<num; i++){ printf("No.%d:",i+1); scanf("%d",&tmp); sum+=tmp; } printf("合計値は:%d\n",sum); printf("平均値は:%.2f\n", (double)sum/num); return(0); } 上の文のforの箇所を for(i=1; i<=num; i++){ printf("No.%d:",i); scanf("%d",&tmp); sum+=tmp;   } としても結果的に同じですよね? どっちでもいいかどうか迷ってます。教えて下さい。

  • if文の中にfor文なのか、for文の中にif文なのか

    for文の中に分岐を作って計算するのと、if文を先に書いてからfor文にするのとではどちらが一般的ですか? for ( i = 0; i < n; i++) { if ( a > b ) { y = i; } else { y = i * 2; } printf( "%d", y ); } とするか、 if ( a > b ) { for ( i = 0; i < n; i++) { y = i; } } else { for ( i = 0; i < n; i++) { y = i * 2; } } printf( "%d", y ); とするかという事です。 ちなみにプログラムは適当ですのでちょっとしたミスはご勘弁ください。 個人的には後者の方が分岐が少ない分負担は減ると思うのですが、前者の方がすっきりとしているのでこちらを使いたいのです。 もちろん、微々たる差なので好きな方を使えという意見もあると思いますが、皆さんはどちらを使いますか?

  • for文~break

    break文に達した時、for文から抜けますか?それとも、if { }から抜けるんですか? for文はどこまで影響下にありますか? if ( i==5 ) printf ("サーバーが見つかりません"); まででしょうか? また  if ( i == 5 ) で5なら、実行としていますが、 6,や,8など5 以外でも、サーバーが見つかりません と if文が実行される見たいですが、なぜですか? 教えてください。 #include<stdio.h> int main(void) { int array[5][2]={ {1,14}, {2,28}, {3,19}, {4,8}, {5,15}, }; int sever; int i; printf("番号を入力してください"); scanf("%d",&sever); for( i=0 ; i<5 ; i++ ) if ( sever == array[i][0] ){ printf ( "%d 番には, %d 人います。\n",sever,array[i][1]); break; } if (i==5) printf("サーバーが見つかりません"); return 0; }

  • C言語の勉強をしていて、for文と戻り値を使った階乗について分からずに

    C言語の勉強をしていて、for文と戻り値を使った階乗について分からずに困っています。 以下の点に留意して、階乗を計算するプログラムを作成する。 階乗とは、数字を1つづつ減らしながら掛け合わせたものです。つまり 5の階乗:5×4×3×2×1=120 3の階乗:3×2×1=6 となります。 main内 1)整数型の変数kazu、kekkaを宣言する。 2)“階乗を計算します。”を表示する。 3)実行例と同様の表示になるように、“整数を入力してください”を表示し、入力された値を、変数kazuに読み込む。 4)作成する関数名は、kaijyoとし、kazuを引数とし、戻り値をkekka に代入する。 6)“○の階乗は ○です。”と表示する。 関数kaijyo内 1)引数を変数名xとする。 2)整数型の変数i、valを宣言する。 3)計算結果をvalに入れていくために、valを初期化する(下記注意参照)。 4)iをカウンターとするfor文と複合代入演算子を使って階乗を計算する。 5)valの内容が戻り値となるようにする。 注意:階乗を計算するために、for文の中で複合代入演算子を使って階乗を計算します。しかし、for文に入る前のvalの初期化には注意が必要です。0に何を何回かけても0だと言うことを思い出してください。 という問題です。 それで私は下の通りに作りました。 #include <stdio.h> int kaijyo(int x); void main(void) { int kazu,kekka,kaijyo,sum; printf("階乗を計算します。\n"); printf("整数を入力してください"); scanf("%d",&kazu); kekka=kaijyo(kazu); printf("%dの階乗は%dです。",kazu,kekka); } int kaijyo(int x) { int i,val; val=1; x=1; for(i=1;i<=val;i++){ x=x*i; } return val; } しかし、メイクして実行してもどの階乗でも256になってしまいます。 どこが間違っているのか分からずに困っています。 よかったら教えてください。 よろしくお願いします。 カテゴリを間違ってしまっていたらすみません。

このQ&Aのポイント
  • PCとプリンターの接続に問題が発生しているmfc-j5800cdwについて相談したい
  • mfc-j5800cdwが再起動やアプリのインストールでもPCと接続されない問題について
  • mfc-j5800cdwのPCとの無線LAN接続がうまくいっていない問題について
回答を見る