• ベストアンサー

インクリメント++の計算

インクリメントの前置きと後置きの計算の考え方がいまいち飲み込めないですが 例:int a=5 , w; w=++a + a++;   printf("w=%d. a=%d",w,a); このときのwの値とaの値は? (一応試してみたらw=12 a=7になりましたがなぜでしょう?)

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

  • ベストアンサー
回答No.3

この式で、w=12 a=7 になったのは たまたま、そのコンパイラで、その オプションだったらそうなったという だけのことで、No.2 の回答にあるよ うに、「未定義動作」=コンパイラ によって、どんな結果になるかわから ないというのが正解です。 さて、++ の前置と後置の区別は、正 式には以下のようになります。 前置(たとえば、++a) ・式の値は、a をインクリメントしたもの ・副作用として、a そのものをインクリメ  ントする ・動作の順序は規定しない 後置(たとえば、a++) ・式の値は、a の値そのもの ・副作用として、a そのものをインクリメ  ントする ・動作の順序は規定しない ということで、時々入門書に書いてあるよ うに、「インクリメントしてから評価」と か、「評価してからインクリメント」とい うことまでは規定されていません。 ※ただし、規定通りの動作をさせる方法の ひとつではあります。 そして、「副作用として、a をのものをイ ンクリメント」というのが、確実に行われ るのが、No.2 の回答にある、「副作用完 了点」で、大抵の場合(例外あり)は、 ; までになります。 つまり、 a = 5; w = ++a; なら、 w == 6 (式の値は、インクリメント後) a == 6 (副作用として、a をインクリメント) a = 5; w = a++; なら、 w == 5 (式の値は、インクリメント前) a == 6 (副作用として、a をインクリメント) となります。 実際、こういう式であれば、インクリメント してから評価という解釈をしても、同じ動作に なります。 一方、 w=++a + a++; という式は、たとえば、代表的なもので以下の ような動作をします。 (例1) ・++a の時点で、評価とインクリメント完了  (この評価完了の時点で、a = 6) ・a++ の時点で、評価とインクリメント完了  (この評価完了の時点で、a = 7) ・結果として、 w = 6 + 6 = 12 a = 7 (例2) ・++a の時点で、評価は完了ただし、インクリ  メントはしない(副作用完了時点までにイン  クリメント完了すればいいから)  この時点で、a == 5 のまま ・a++ の時点で、評価は完了ただし、インクリ メントはしない(同上)  この時点で、a == 5 のまま ・計算結果を w に代入 ・最後に、インクリメント実施(この後、a == 7) ・結果として、 w = 5 + 6 = 11 a = 7 (例3) ・基本的な流れは、例2と同じ。  ただし、インクリメントは、1回だけ ・結果として、 w = 5 + 6 = 11 a = 6 そのほかにも、いろいろな可能性があります。 そして、w = ++a + a++; だと、上記のように いろいろな結果が出る可能性がありますが、 w = (++a) * 2; とか w = (a++) + (+bb); とか、 正しい式であれば、例(1~3)のいずれでも 同じ結果になることがわかると思います。

poyo3
質問者

お礼

未定義だと成り行きで変わってしまうのですね。 回答ありがとうございます。

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

その他の回答 (4)

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

未定義の動作である以上、処理系を特定し、処理系のドキュメントに具体的な振る舞いが規定されていないかぎり、それ以上の議論は無意味です。 未定義の動作の場合、コンパイルできるかどうかも含めて、どうなるか分からないのです。

poyo3
質問者

お礼

そういうものなんですね。回答ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • chie65535
  • ベストアンサー率43% (8536/19406)
回答No.4

まず「加算(+)の右辺と左辺は、どっちが先に計算されるか判らない」です。 ・ケース1 インクリメントは即時に実行し、右辺から先に計算するコンパイラの場合。 まず、右辺のa++が計算されます。この式の値は「インクリメントする前の値」を持ちますから「右辺の値は5」です。そして、aがインクリメントされて6になりますが、その6という値は使われません。 次に、左辺の++aが計算されます。この式は「インクリメントした後の値」を持ちますから、まず6になってるaがインクリメントされて7になり、その7という値が式の値になり「左辺の値は7」です。 これで5と7が求まったので、足し算されて12になります。 ・ケース2 インクリメントは即時に実行し、左辺から先に計算するコンパイラの場合。 まず、左辺の++aが計算されます。この式は「インクリメントした後の値」を持ちますから、まずaがインクリメントされて6になり、その6という値が式の値になり「左辺の値は6」です。 次に、右辺のa++が計算されます。この式の値は「インクリメントする前の値」を持ちますから「右辺の値は6」です。そして、aがインクリメントされて6になりますが、その6という値は使われません。 これで6と6が求まったので、足し算されて12になります。 次に「あとでインクリメント」は「式中の、どの位置でインクリメントしても良い」のです。逆に言えば「どの位置でインクリメントされるか判らない」のです。 ・ケース3 a++で、インクリメントをすぐに行わないコンパイラの場合。 もし、a++でインクリメントするのを「加算が終了したあと」に行うコンパイラの場合、加算の右辺と左辺のどちらを先に計算しても「加算が終了したあとに行うインクリメント」は加算結果に含まれないので、wは11になるでしょう。 ・ケース4 上記以外。 ---- で、今回は、偶然、ケース1かケース2のどちらかになったようですが、どっちになったかは判りません。もしかしたらケース4で、結果も偶然なのかも。

poyo3
質問者

お礼

そうでしたか。回答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

> 例:int a=5 , w; > w=++a + a++; >   printf("w=%d. a=%d",w,a); > このときのwの値とaの値は? 未定義の動作になります。 副作用完了点から次の副作用完了点までの間に、同じオブジェクトを複数回更新してはいけません。

poyo3
質問者

お礼

なるほど。そういうものなんですね。回答ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • TinyPine
  • ベストアンサー率30% (719/2386)
回答No.1

前に置くのは先に加算されます 後に置くのは後に加算されます。 w=++a  ここで、aは5に1加算された6に成ります +  a++ ここで wには aの現在値である6が加算されます、その後1加算されます; 従ってw = 12 aには最後のaの値、7が結果として表示されます。

poyo3
質問者

お礼

そういうことでしたか。回答ありがとうございます。

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

関連するQ&A

  • 前置き・後置きインクリメント。

    いつも大変お世話になり誠にありがとうございます。 標記の件。 参考書を見て、考えましたがピンときません。 どなたか解りやすく説明してもらいませんでしょうか? 2種類のコードと実行は下記の通りです. test1.c #include <stdio.h> int main(void) { int a = 0; int b = 0; b = a++; printf("代入後にインクリメントしたのでbの値は%dです。\n", b); return 0; } C:\MinGW>gcc test1.c -o test1 C:\MinGW>test1.exe 代入後にインクリメントしたのでbの値は0です。 test2.c #include <stdio.h> int main(void) { int a = 0; int b = 0; b = ++a; printf("代入前にインクリメントしたのでbの値は%dです。\n", b); return 0; } C:\MinGW>gcc test2.c -o test2 C:\MinGW>test2.exe 代入前にインクリメントしたのでbの値は1です。 前置き・後置きインクリメントの違いを論理的に ご説明願えませんでしょうか。 ご回答の程宜しくお願い申し上げます。

  • インクリメント演算子

    はじめまして。プログラミングについて、とても初歩的な所で つまづいています。 変数を一つだけかつ、インクリメント演算子のみを用いて 整数値を一つ入力し,その整数値を1ずつ増やした結果を出す 4,5,6,7,8  (←このようにしたい) というプログラミングを書きたいのですが、どこのサイトを見ても 5個の文字の例はありませんでした。 2個までは以下の例でできました。 #include <stdio.h> main() { int a; printf("整数値を入力"); scanf("%d",&a); printf("1ずつ増加%d,%d,\n",a++,a); } もう、この問題で何日も立ち止まっています。 お願いです、どなたか助けてください。

  • インクリメント/デクリメント演算子を使った計算

    Javaでのインクリメント演算子とデクリメント演算子を 使った計算についての質問です。 int a = 10; int b = a++ + ++a + --a - a--; このコード処理後の変数a,bの値の計算方法(考え方)が つかめず苦戦しています。 解答はa=10,b=22だそうです。 ちなみに例えば次のコードのb=a++;のように 右辺と左辺が1つずつの場合は理解しやすいです。 int a = 1; int b = 0; b = a++; //処理A 処理A後の変数a,bの値は b=aをした後でa=a+1を行うので a=2,b=1 となることは理解できます。 ご教授のほどよろしくお願いします。

  • インクリメント演算子について

    インクリメント演算子について プログラミング超初心者です。 大学のプログラミングの課題で インクリメント演算子を使って 数字をひとつずつ大きく(小さく)していくという課題が出ました 私が作ったプログラムは以下のとおりです #include <stdio.h> int main(void) { int x ; //変数宣言 printf("整数値を入力してください:"); scanf("%d",&x); printf("1ずつ増加\n"); printf("%d,",x++); printf("%d,",x++); printf("%d,",x++); printf("%d,",x++); printf("%d\n",x); printf("1ずつ減少\n"); printf("%d,",x--); printf("%d,",x--); printf("%d,",x--); printf("%d,",x--); printf("%d\n",x--); } ちなみに、整数値は10にしました。 結果は 1ずつ増加 10,11,12,13,14 1ずつ減少 14,13,12,11,10 と、望んでるものになったのですが、疑問があるので質問させていただきます。 xを変数にすると、x++はx+1になると思うのですが表示されたのは10、11、…と 10から表示されました。 しかも、増加していった最後のxはなぜ14になるのでしょうか? 課題は出来たのですが、頭が混乱しています… 詳しく解説をお願いします。

  • インクリメントしてくれません

    配列mousの各要素を配列tousと照らし合わせ、マッチしたら変数countにインクリメントし、何回マッチングしたかを返す関数を作りました。 でも、なぜか1回しかインクリメントしてくれません。 確認のため試しにcount++部分をputf("テスト表示")に置き換えた場合マッチングした回数だけ「テスト表示」表示されました。 じゃあなぜ、変数countは一回しかインクリメントされないのでしょうか? #include <stdio.h> int DataMatch(int *, int *); void main() { int mous[6] = { 1, 15, 12, 23, 33, 42}; int tous[7] = {10, 15, 19, 23, 33, 42, 11}; int test; test = DataMatch(mous, tous); printf("%d%\n", test); } ////////////////////////////////////////////////// int DataMatch(int *buffer1, int *buffer2) { int i, j, count; for(i = 0; i < 6 ; i++ ){ for(count = 0, j = 0; j < 6; j++){ if(buffer1[i] == buffer2[j]){ count++;//インクリメントしてくれない! break; } } } return count; }

  • プログラミングCの四則計算について質問です

    どうしてもわからなかったのでご指摘お願いします。 以下のプログラムを四則計算ができるプログラムに変更したいのですがどこを直せばいいのでしょうか? /* ansp5_7 */ #include <stdio.h> void wasa(int a,int b,int *w,int *x,int *y,float *z); main() { int d1,d2,wa,sa,seki; float syou; printf("data1,data2="); scanf("%d,%d",&d1,&d2); wasa(d1,d2,&wa,&sa,&seki,&syou); printf("wa=%d,sa=%d,seki=%d,syou=%5.2f\n",wa,sa,seki,syou); } void wasa(int a,int b,int *w,int *x,int *y,float *z) { *w=a+b; *x=a-b; *y=a*b; *z=(float)a/b; }

  • インクリメント演算子の前後

    インクリメント演算子(++や--)について伺いたいのですが、 以下のような場合、変数の前と後ろで何か処理上違いはあるのでしょうか? //文字列の最後までポインタを進める while ( *p1 ) { ++p1; } printf("%d" , *p++); のように(文法が間違っていたらすいません)、 出力した後でインクリメントするといった使い方の違いは分かるのですが、インクリメント単独処理での前後の違いがあれば教えていただきたいです。

  • 後置インクリメントの計算過程について

    後置インクリメントの計算過程について Javaに関して初めての質問となります。よろしくお願いいたします。数日前に学習し始めたばかりの超・初心者です。 現在、基本的な演算について、インクリメント・デクリメントのそれぞれ前置と後置の違いを学習したところなのですが、どうも後置の理解が完璧でないようで、仮に変数をxとした場合、式内にxが二度出てくる場合の後置の計算が理解できません。 具体的には int x, y; x = 10; y = x++ + x++; 上記でコンパイルした結果、y=21となる過程を教えていただけませんでしょうか。 私の理解では、x++は計算に使用した後にxに1を加算するので、まず y = 10 + 10 で、y = 20 となり、その後にxに1を加算してx=11が私の理解です。 よろしくお願いいたします。

    • ベストアンサー
    • Java
  • C++ ポインタ初級

    C++で、自作関数内でメインの数字をインクリメントします。 自作関数はVOIV型でやりたいんです。 #include <stdio.h> void plus( int * ); main( ){  int a = 1;  int *&p = &a;  plus( p );  printf( "%d" , *p ); } void plus( int *i ){  ( *i )++; } int型の変数を2つ宣言したけど、1つでやる方法はないですか? #include <stdio.h> void plus( int * ); main( ){  int a = 1;  plus( &a ); // aのアドレスを渡して、  printf( "%d" , a ); } void plus( int *i ){ // アドレスの値を  ( i )++; // インクリメントしたつもりだけど } 結果は1のままでした。

  • Switch caseの書き方について

    int a; scanf("%c", &a); switch (a) {      case 'w':        printf("a = w\n");        break;      default:        printf("?\n");        break; } 上記のように書いて「w」を入力すつと「?」が返ってきます。 int a,b; scanf("%d %c", &b,&a); で「20w」と入力すると「w」が返ってくるのですが、 「%c」だけだとうまくいかないのはどうしてでしょうか? 初歩的な質問で申し訳ないのですが、教えてください。