C言語の副作用に関する未定義

このQ&Aのポイント
  • C言語で副作用を持つ演算を含む場合は、その副作用が実行されるタイミングが未定義となっている。
  • 例えば、「a[i++] = i;」のようなコードでは、代入演算子の結合規則が右から左であるため、aのインデックスとしてiが参照されるよりも早くiの値が代入される。
  • そのため、実行結果が予測できず、未定義の動作となる可能性がある。
回答を見る
  • ベストアンサー

C言語の副作用に関する未定義

C言語で副作用を持つ演算を含む場合は、その副作用が実行されるタイミングが未定義となっているようですが、 以下のコード int a[10]; int i; while (i < 10) a[i++] = i; では、 a[i++] = i; の代入演算子(=)の結合規則が右から左であるため、aのインデックスとしてiが参照されるよりも早くiの値を代入しているため、未定義にならないと思うのですが、実際はどうなのでしょうか? (a[i] = i++; の場合は完全に未定義になる。) 実際にこのようなコードを書くことは無いと思いますが、気になったもので。 もしご存知の方がおいででしたら教えていただけないでしょうか。 よろしくお願いします。

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

  • ベストアンサー
  • manayu
  • ベストアンサー率53% (79/148)
回答No.1

未定義ですね。 このURLを参考にしてください。 http://www.em.edu.waseda.ac.jp/~moriya/education/c/lesson4.html

参考URL:
http://www.em.edu.waseda.ac.jp/~moriya/education/c/lesson4.html
tamanegi_majin
質問者

お礼

ずばりとありがとうございました。 やはり値の評価に関する優先順位は定まっていないと見るべきなのですね。 疑問が解決しました。ありがとうございます。

その他の回答 (2)

noname#25358
noname#25358
回答No.3

 演算子の優先順位にはいくつかの例外があり、後置インクリメント演算子もその1つです。  a[i++] = i; の i++ は優先順位が代入演算子よりもさらに低いので、a[i] = i; を実行したあとで i++ が実行されてしまいます。  また、未定義というのは「ゼロ」ではありません。  質問文は、「未定義の i に対して ++ を実行すると1が入る」という前提で話されていますが、特にC言語の場合は間違いです。  未定義値とは、本当に何が入っているか分からない値のことを指すので、もしかしたら、実行された段階で i の中に10とか50000とか3000とかが入っているかもしれないのです。 (VCの場合だと、作為的に 0x5F を入れたりしてるみたいですが)  その場合、質問文中のプログラム自体が動作しないことになりますよね。

tamanegi_majin
質問者

お礼

i=0; を記載するのを忘れていました。 すみません。 No1の方の内容で解決してしまいましたので、補足する間もありませんでしたが、お礼申し上げます。 ありがとうございました。

  • arukamun
  • ベストアンサー率35% (842/2394)
回答No.2

サンプルプログラムを組んで、確認してみるといいですね。 sample1() {   int a[10] ;   int i ;   for (i= 0 ;i<10 ;i++) a[i] = 100 ;   i = 0 ;   while ( i < 10 ) a[i++] = i ;   for (i=0 ;i<10 ;i++) printf("a[%d] = %d\n",i,a[i]); } sample2() {   int a[10] ;   int i ;   for (i= 0 ;i<10 ;i++) a[i] = 100 ;   i = 0 ;   while ( i < 10 ) a[i] = i++ ;   for (i=0 ;i<10 ;i++) printf("a[%d] = %d\n",i,a[i]); } sample1は a[0] = 1 a[1] = 2 a[2] = 3 a[3] = 4 a[4] = 5 a[5] = 6 a[6] = 7 a[7] = 8 a[8] = 9 a[9] = 10 sample2は a[0] = 0 a[1] = 1 a[2] = 2 a[3] = 3 a[4] = 4 a[5] = 5 a[6] = 6 a[7] = 7 a[8] = 8 a[9] = 9 を出力しました。

tamanegi_majin
質問者

お礼

ありがとうございます。 ただ、副作用の作用順序の優先順位はANSIでも定まっていないと聞いていたので、恐らく処理系によって違うのだと思います。 No1の方の内容で解決してしまいましたので、補足する間もありませんでしたが、お礼申し上げます。 ありがとうございました。

関連するQ&A

  • JavaでC言語のポインタ演算風な使い方は

    Java初心者です。ずっとC言語をやっていました。 Javaにはポインタは存在せず(実際は参照渡しなのでポインタその ものなのですが)、ポインタに対する演算はありませんよね。 C言語で、 int buf[2*10]; int *dst = buf; for(i=0;i<10;i++){ dst[0]=a; dst[1]=b; dst += 2; } のようなソースをJavaで書こうとすると、 for(i=0;i<10;i++){ buf[i*2+0]=a; buf[i*2+1]=b; } しか思いつきません。 コンパイルして最適化されれば問題ないと思いますが、 なんか配列中の演算が演算量をとりそうで、気になっています。 もっと高速に処理されるような書き方はないものでしょうか? アドバイスよろしくお願いします。

    • ベストアンサー
    • Java
  • 前置単項演算子の優先順位や言葉の定義

    javascriptの場合 ++ や -- は前置きなら右結合、後置きなら左結合ということのようですが、この結合規則の具体例ってどういったものでしょうか。 そして例えば++a--だとどっちが先に評価されるのでしょうか。(結果は同じだとしても) また2項演算子の + や - などの結合規則は理解できるのですが、単項演算子の場合に結合規則が具体的に何のことを言っているのかどうもよくわかりません。 例えば !--abc や ++a-- のように単項演算子を並べた場合も、どのように結合して何をもって右とか左と言うのか、という点を明確にしたいです。 (特にjavascriptに限った話ではないのでjavaやcなど他の言語での解説でもかまいません) いままであやふやにしてしまっていた言葉や定義をここではっきりしたいです。 具体的な例で示していただけると助かります。

  • C言語

    1 から 1000 までの範囲で 7 の倍数を求め、その合計を表示する にはどうすればよいでしょうか。 という問いに対して、C言語での解き方がまったくわかりません・・・。 #include <stdio.h> /* 標準入出力ライブラリ */ main() { int i; /* int 型の変数 i を宣言 */ i = 7; /* i に 1 を代入し、初期化 */ /* i が 1000 以下であるかぎり、繰り返す */ while( i <= 1000 ){ printf("%dの2乗は %d です\n", i, i * i); i = i + 7; /* i を 7 増やす */ } }

  • C言語で困っています

    C言語で 100:1 99:2 98:3 .......ループ 1:100とやりたいんですが このやりかたがわかりません goto文などを使うのでしょうか? 一応コードは #include <stdio.h> int main(void) { int i,a; for(i=100; i>=1; i--){ for(a=1; a<=100; a++){ printf("%d:\n",i); break; printf("%d",a); } } return 0; } です まったくこれだと右側が出力されなくてだめみたいです どなたかお知恵をください お願いします

  • C言語について

    C言語の問題なのですか、作成したのですが内容がわからないです。テキストを読んでも解説が書いていないので、出来ればどなたか簡単な解説でも教えて頂けるとありがたい。 〈コード〉 #include <stdio.h> int main(void) { short point[] = {234, 819, 18, -6492, 795, 20302, 2431, 9029, 0, -28009}; // 定義と逆順に値を表示する for (int i = sizeof(point) / sizeof(point[0]) - 1; i >= 0; i--) { //sizeofで配列要素数を算出 printf("%d\n", point[i]); } return 0; }

  • C言語に関することについて教えてください

    学校の問題集にでてきた問題がわかりません、どうか教えてください 1 プログラムの役割、必要性について説明せよ 2 プログラムにおける変数と定数の役割を説明せよ。また、ローカル変数の有効な範囲について説明せよ。 3 C言語で使う変数が他について、宣言子と、printf関数、scanf関数それぞれにおいて対応する書式指定子を対応表にせよ。また、変数名を決める際に守るべき文法上の規則と、プログラマとして配慮すべき事項を説明せよ。 4 配列について、その役割と定義方法を説明せよ。 5 コンピュータにおける文字処理に必須なアスキーコードについて説明せよ。 6 C言語における文字列について、文字列定数、文字列変数を説明せよ。 7 C言語における繰り返し処理の文法(for,while,do~while)を、プログラムコード列を示して説明せよ。 8 C言語における条件判断の文法(if,else,else if)を、プログラム列を示して説明せよ。 9 繰り返し、条件判断において利用する論理式(等値演算子、関係演算子、論理演算子等で記迷する式)について、その記迷の方法を論理和、論理積も含めて説明せよ。 10 変数のアドレスについて説明せよ。また、ポインタについて、アドレスとの関連性を踏まえて、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 11 ポインタと配列の関係について、ポインタによる配列操作を列に説明せよ。 12 関数について、その役割と定義方法について説明せよ(戻りがた、関数名、引数リスト)。また、自作関数をそれらを利用するmain関数のプログラムコード例を示せ。 13 scanf関数の戻り値について、その内容を説明して、どのような際に利用すると便利か、プログラムコード例を示して説明せよ。 14 引数にポインタを利用する関数のプログラムコード例を示して、ポインタの必要性、重要性を説明せよ。 15 構造体について、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 16 ファイルポインタについて説明し、ファイル入出力の方法についてプログラムコード例を示して説明せよ。

  • C言語のポインタについて教えてください。

    C言語のポインタについて教えてください。 ・pointer1.c  int main(){   int a;   int *p;   p = &a;     a = 123;   printf("%d", *p);   return 0;  } ・pointer2.c   int main(){ int a[100]; int *p; p = &a[0]; int i; for(i = 0; i < 100; i++) a[i] = i; for(i = 0; i < 100; i++) printf("%d", *p++); return 0; } と二つのソースコードがあるとき、pointer2.cの「p = &a[0]」をpointer1.cのように「p = &a」と書けないのはなぜですか?  また、「&a」は動かすことのできなく、「aを指し示す*p」は動かすことができる変数のようなもの、という認識に誤りはないでしょうか?  宜しくお願いします。

  • 演算子のオーバーロードについて

    []演算子のオーバーロードでつまづきました。 代入文で左辺、右辺、両方ともに[]演算子を使う場合 int &operator[](int i) { return a[i]; } int &operator[]のようにして、戻り値を参照型にしています。 このとき、main関数内で、 ob1[2]=ob2[2];(ob1,ob2はoperator[]関数が関連付けられているクラスのオブジェクト) のようにすると、左辺(ob1)にちゃんと代入されています。 つまりこの場合、main()関数内で、 (int &)型の(this->a[i])(元のオブジェクトは、ob1) に (int &)型の(this->a[i])(元のオブジェクトは、ob2)を代入しているのでしょうか?

  • C言語の問題で困っています。

    C言語の問題で困っています。 誰か教えてください。 下の問題ですが、intがiだけでプログラムするにはどうしたら良いでしょうか? (a)から(d)に入るプログラムをすいませんが教えてください。 お願いします。 【問題】 1以上10以下の整数を昇順に区切って表示するプログラムです。 実行例 1 2 3 4 5 #include <stdio.h> int main (void) { int i; (A) while ((b)){ (c); (d); } printf("¥n"); return(0); }

  • C言語の行列の積

    現在C言語を勉強中で2列2列の行列の積のコードを書きたいのですが、 いまいちうまくできません。 int main () {  int i,j;  int M1[2][2] = {{1,2},{3,4}};  int M2[2][2] = {{-1,5},{-2,-2}};  int A[2][2];  for (i=0;i<2;i++)  {   for (j=0;j<2;j++)   {    A[i][j]=0;    A[i][j]+=M1[i][j]*M2[i][j];    printf("%d\t",A[i][j]);   }  printf("\n");  } return 0; } 調べたりしてなんとか書いてはみたのですが理解が浅く、 コンパイルできても違う答えが返ってきます。 どこがどう間違っていますか? また、どのようにしたらうまいコードになりますか? 何卒、よろしくお願いします。

専門家に質問してみよう