このページでは、変数名++
と ++変数名
との違いについて説明していきます。簡単のため、変数名
は i
であるとして説明していきます。つまり、i++
と ++i
の違いについて説明していきます。もちろん、変数名が x
や j
の場合もあり、そういった場合は x++
と ++x
、j++
と ++j
と記述されることになりますが、変数名が異なるだけで、これらの違いは i++
と ++i
の違いと同様の違いがあります。
i++
と ++i
の共通点
まずは、i++
と ++i
の共通点についておさらいしておきましょう。
これらは両方とも i
をインクリメントを指示する命令となります。インクリメントとは変数の値を 1 だけ増加させる命令のことを言います。
つまり、i++
や ++i
が実行された次の行で i の値を評価した場合、両方とも i
の値は i++
/ ++i
によって 1
増加した値となります。ちなみに、i--
/ --i
の場合はデクリメントを指示する命令となり、i
の値を 1
減少させる命令となります。
例えば、下記のように値が 0
の i
に対して i++
の処理を実行した後に printf
で i
を出力した場合と、
i = 0;
i++;
printf("i = %d\n", i); // i = 1
下記のように値が 0
の i
に ++i
を実行した後に printf
で i
を出力した場合とでは “同じ結果” が得られることになります。
i = 0;
++i;
printf("i = %d\n", i); // i = 1
このように、i++
と ++i
のみを実行する処理においては、両方ともインクリメントが行われるだけで、得られる結果はどちらの場合も同じになります。
i++
と ++i
の違い
この2つに違いが現れるのは、“評価結果の利用” と “インクリメント” を1つの処理(1つの行)の中で行おうとした場合になります。
分かりやすい例が下記となります。下記では x
に代入される値と、y
に代入される値とが異なる値となります。具体的には、x
には 0
が代入され、y
には 1
が代入されることになります。
i = 0;
x = i++;
printf("x = %d\n", x); // x = 0
i = 0;
y = ++i;
printf("y = %d\n", y); // y = 1
なぜ、このように代入結果が異なるのでしょうか?
これは、i++
と ++i
とでは、評価されるタイミングが異なるからになります。異なる言い方をすればインクリメントが行われるタイミングが異なるからになります。
スポンサーリンク
i++
:インクリメントが後に行われる
まず、i++
の場合は評価の後にインクリメントが行われます。
そのため、x = i++
を行なった場合、インクリメントよりも先に右辺の評価(i
の評価)が行われます。
インクリメントが行われる前に評価されるわけですから、この時点での評価結果はインクリメントされる前の i
の値となります。x = i++
実行前の i
の値が 0
であれば、評価結果は 0
となります。そして、x
には右辺の評価結果が代入されることになります。そのため、x
に代入される値は 0
となります。さらに、インクリメントは評価後に行われ、i
の値は 1
増加することになります。
このように、i++
のように 変数名++
でインクリメントを実施する場合、インクリメントが変数の評価よりも後に行われることになります。そして、このようなインクリメントを後置インクリメントと呼びます。++
が 変数名
よりも “後ろにある” ため「インクリメントが後に行われる」と考えると動作が覚えやすいと思います。
++i
:インクリメントが先に行われる
それに対し、++i
の場合は評価よりも先にインクリメントが行われます。
そのため、y = ++i
を行なった場合、インクリメントが右辺の評価(i
の評価)よりも先に行われます。
したがって、まずは i
の値が +1
され、それから右辺の評価が行われることになります。そして、その評価結果が y
に代入されることになります。y = ++i
実行前の i
の値が 0
であれば、まず i の値が 1 に増加し、それからその結果が評価結果となって y
に代入されます。つまり、y = ++i
実行後の y と i の値は両方とも 1 になります。
++i
のように ++変数名
でインクリメントを実施する場合、インクリメントが変数の評価よりも先に行われることになります。そして、このようなインクリメントを前置インクリメントと呼びます。++
が 変数名
よりも “前にある” ため「インクリメントが先に行われる」と考えると動作が覚えやすいと思います。
このように、i++
と ++i
とでは i
のインクリメントが実行されるタイミングが異なります。言い換えれば、i
が評価されるタイミングが異なります。i++
や ++i
を単独で利用する場合、評価結果は無視されることになるため、i++
と ++i
は結果的に同じ処理となります。しかし、評価結果が利用される場合、例えば上記のような評価結果が左辺の変数に代入されるような場合は、i++
と ++i
のどちらを利用するのかによって得られる結果が異なることになります。
使い方を誤るとバグの原因に
先ほどは代入の例を示しましたが、i++
と ++i
におけるインクリメントと評価の順番は代入時だけでなく、あらゆるケースで同様になります。
例えば下記のように do while
ループの継続条件に i++
と ++i
を使用した場合ではループの実行回数が異なることになります。当然、ループによって得られる結果(下記の場合は x
の値)も異なることになります。
x = 0;
i = 0;
do {
x = x + i;
} while (i++ < 10);
printf("x = %d\n", x); // x = 55
x = 0;
i = 0;
do {
x = x + i;
} while (++i < 10);
printf("x = %d\n", x); // x = 45
また、下記のように if 文の条件に i++
と ++i
とを使用した場合も成立 or 不成立が異なることになります。
i = 0;
if (i++ == 0) { // 成立する
printf("Hello World!\n");
}
i = 0;
if (++i == 0) { // 成立しない
printf("Hello World!\n");
}
このように、インクリメントと評価が実行されるような処理を記述した場合、i++ と ++i とを誤って利用してしまうと意図した動作にならずバグの原因になってしまいます。
自身のやりたいことを考え、それを実現するのに適した方を使うようにしましょう。
スポンサーリンク
使い分けは不要?!
ここまでの説明を読んでいただければ i++
と ++i
の違いについてはなんとなく理解していただけたのではないかと思います。
でもなんだかややこしいですね…。使い分けるのは難しそうです。
もし難しそうで使い分けに困りそうなのであれば、正直使い分けしなくてもいいようにソースコードを書いてしまうのでも良いと思います。
ここまで説明してきたように、i++
と i++
の違いが生じるのは代入や条件式に利用するなど、インクリメントを行うだけでなく評価結果が利用される時になります。単にインクリメントすることを目的に i++
や ++i
を単独で実行した場合には違いは生じません。
ということで、インクリメントと式の評価の利用を同じ処理の中で実行しないようにしてやれば使い分けに困ることはありません。
そのため、使い分けに困るようであればインクリメントと式の評価を別の処理として実行するようにしてやれば良いです。
例えば下記の処理であれば、
x = 0;
i = 0;
do {
x = x + i;
} while (++i < 10);
次の処理のように書いても得られる結果に違いはありません。このように書き換えた場合、i++
の部分は ++i
に置き換えても同じ結果となります。
x = 0;
i = 0;
do {
x = x + i;
i++;
} while (i < 10);
個人的には後者の書き方の方が好きですし、分かりやすいと思っています。i++
と ++i
が巧みに使い分けられているソースコードも魅力的かもしれませんが、慣れていないと i++
と ++i
の違いが直ぐに思いつかず、直感的に分かりにくくなってしまうと私は思っています。
そのため、私もC言語のソースコードを何年も書いてきましたが、おそらく、一度も ++i
は使ったことがないです。インクリメントをする場合は常に i++
を利用しています。そして、評価結果が利用されないようにインクリメントの処理は単独で記述するようにしています。
そうすれば、i++
と ++i
で得られる結果に違いは無くなるため、どちらか一方に統一することができます。私の場合は、最初に習ったのが i++
ということもあり、i++
で統一するようにしています。これが個人的に一番分かりやすいかと…。逆に、意味も無いのに i++
と ++i
とを混在させると読み手が混乱する可能性があるのでやめた方が良いと思います。
いろいろ調べてみると i++
と ++i
では処理時間が異なるなどの記事も見つかりましたが、大きな違いではないはずなので、まずは分かりやすく書くのが良いと思います。そのため、個人的なオススメは i++
のみに統一し、インクリメントと評価結果の利用、具体的にはインクリメント後の変数の値の利用は分けて記述するのが良いと思います。
ここは個人的な意見にはなりますが、おそらく同じ意見を持っている方も多いのではないかと予想します…。
まとめ
このページでは、i++
と ++i
の違いについて解説しました!
この2つは i++;
と ++i;
といったように、インクリメントのみを行うのであれば結果に違いはありません。しかし、while (i++ < 10)
や if (++i == 0)
、x = i++
など、インクリメントだけでなく式の評価結果の利用が行われる処理も実行されるように記述すると、i++
と ++i
のどちらを利用するかによって得られる結果に違いが生じることになります。
具体的には、i++
の場合は評価よりもインクリメントが後に行われるため「インクリメント前の値」として評価されることになります。それに対し、++i
の場合は評価よりもインクリメントが先に行われるため「インクリメント後の値」として評価されることになります。そして、この違いにより評価結果が利用される際に異なる結果が得られることになります。そのため、この違いについて理解しておかないとバグが発生する可能性が高くなります。
これらを使い分けるのであれば、このページで説明した違いをしっかり意識してソースコードを書くようにしましょう!また、インクリメントと評価結果の利用のタイミングを別にしてやれば違いを意識せずに i++
や ++i
を利用することもできます。この点についてもしっかり覚えておいてください!
オススメの参考書(PR)
C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!
まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。
- 参考書によって、解説の仕方は異なる
- 読み手によって、理解しやすい解説の仕方は異なる
ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?
それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。
なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。
特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。
もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!
入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。
https://daeudaeu.com/c_reference_book/