
C言語のきほん|キャスト演算子
キャストは“計算の型”を操るスイッチ!どこを double にするかで、答えが変わる理由が見えてくるよ。
C言語で計算していると、「えっ、2.5になるはずなのに 2.0 になった…」みたいなことが起きます。
原因の多くは、計算が int のまま行われていたことです。
そこで使うのが キャスト演算子。
キャストは「この値は、この型として扱ってね」と明示して、意図した型で演算させるための道具です。
ただしキャストは強力なので、使いどころを間違えると、値が失われたり、最悪クラッシュや未定義動作につながることもあります。便利だけど、丁寧に使うのがコツです。
キャスト演算子の書き方(文法)
キャスト演算子はこう書きます。
(型) 式
- (型) は、変換したい型名を丸括弧で囲みます
- 式 は、変換対象の値や変数です
例:
- (double)a
- (int)x
- (unsigned int)count
キャストで何が嬉しいの?
一番わかりやすい効果:整数の割り算を浮動小数点にできる
int 同士の割り算は、小数点以下が切り捨てられます。
だから「割り算の前」にどちらかを double にしておくと、計算全体が double 側に寄って小数が出ます。
| 書き方 | 中で起きること | 結果のイメージ |
|---|---|---|
| x = a / b; | int / int の割り算 | 2.0 になりがち |
| x = (double)a / b; | double / int で計算 | 2.5 になりやすい |
| x = (double)a / (double)b; | 両方double | もちろん 2.5 |
通常は片方だけキャストすれば十分です。片方が double になれば、暗黙の型変換で相手も double として扱われるからです。
落とし穴1:キャストする場所を間違える(演算の順序)
キャストは「どこを先に計算するか」で結果が変わります。ここが最大の罠です。
たとえば a=5, b=2 なら本当は 2.5 が欲しいのに…
| 書き方 | 先に起きること | x |
|---|---|---|
| x = (double)a / b; | a を double 化してから割る | 2.5 |
| x = (double)(a / b); | 先に a/b を int で計算 | 2.0(手遅れ) |
つまり、キャストは「計算の前」に効かせないと意味が薄くなります。
シンプルな確認プログラム
キャストの位置で結果が変わるのを、短いコードで見てみます。
ファイル名:6_9_1.c
#include <stdio.h>
int main(void)
{
int total = 5;
int people = 2;
double x1;
double x2;
x1 = (double)total / people; /* 先にdoubleにして割る */
x2 = (double)(total / people); /* 先にintで割ってからdouble化 */
printf("正しいキャスト: %.1f\n", x1);
printf("手遅れキャスト: %.1f\n", x2);
printf("メッセージ: キャストは計算の前に効かせるのがコツだよ。\n");
return 0;
}落とし穴2:キャストは強力すぎる(危ない変換もできてしまう)
キャストは「型を合わせる」だけじゃなく、かなり強引なことも可能です。
たとえばポインタ型を無理やり変えるようなキャストは、扱いを間違えると未定義動作の原因になります。
文書の例にあるように、int のアドレスを char のポインタとして扱うと、int を 1バイト単位で覗くような形になり、意図しない読み取りになりやすいです。
ここはポインタの学習が進んだ段階で改めて深掘りするとして、今の段階ではこの一言を覚えておくと安心です。
- 値のキャスト(int ↔ double など)はよく使う
- ポインタのキャストは危険度が高いので慎重に
実践問題
次のプログラムの計算式を、キャスト演算子を使って修正し、実行結果が小数を含む値になるようにしてください。
- 改造のポイントは「割り算が整数のまま終わらないようにする」ことです
- どこをキャストすればいいか考えてみてね
#include <stdio.h>
int main(void)
{
double avg;
int sum = 17;
int count = 4;
avg = sum / count; /* ここを修正 */
printf("平均は%.2fです。\n", avg);
return 0;
}期待する実行結果の例
平均は4.25です。解答例
ファイル名:6_9_2.c
#include <stdio.h>
int main(void)
{
double avg;
int sum = 17;
int count = 4;
avg = (double)sum / count; /* sumをdoubleにしてから割る */
printf("平均は%.2fです。\n", avg);
return 0;
}解説
sum と count がどちらも int だと、sum / count は整数除算になります。
そこで sum を double にキャストすると、式全体が double の割り算になり、4.25 を得られます。
ちなみに、
avg = (double)(sum / count);
は「先に整数除算してから double にする」形なので、4.00 になってしまいます。キャストの位置は本当に大事です。
実践問題
元の pr6_6_2.c は V = 4/3 π r³ の 4/3 が整数除算になるのが落とし穴でした。同じ狙いで半径を変えた類似問題を作ります。
半径 r の球の体積を求めて表示してください。
- 体積の公式は V = 4/3 π r³
- r³ は r × r × r として計算してください
- 4/3 が整数除算にならないように注意してください
- PI は 3.14159 を使います
#include <stdio.h>
int main(void)
{
int r = 3; /* 半径 */
double v; /* 体積 */
const double PI = 3.14159; /* π */
v = _______________________;
printf("半径%dの球の体積は%fです。\n", r, v);
return 0;
}期待する実行結果の例
半径3の球の体積は113.097240です。解答例(キャストあり)
ファイル名:6_9_3.c
#include <stdio.h>
int main(void)
{
int r = 3;
double v;
const double PI = 3.14159;
v = (4.0 / 3.0) * PI * (r * r * r);
printf("半径%dの球の体積は%fです。\n", r, v);
return 0;
}解説
4.0 / 3.0 のように、最初から浮動小数点にしておくと安全です。
ここはキャストで
- (double)4 / 3
- 4 / (double)3
のようにしてもOKですが、定数なら 4.0 と書く方が読みやすいことが多いです。
チャレンジ問題:連立方程式
次の連立方程式の解 x と y を求めるプログラムを作成してください。
ax + by = c
dx + ey = f
条件:
- 係数 a〜f は整数
- 解は一意に存在するものとします
ヒント:クラメルの公式を使うと、次のように求められます。
D = a*e - b*d
Dx = c*e - b*f
Dy = a*f - c*d
x = Dx / D
y = Dy / DD が整数でも、割り算結果は小数になることがあるので、計算の型に注意してね。
解答例
ファイル名:6_9_4.c
#include <stdio.h>
int main(void)
{
int a, b, c, d, e, f;
int D, Dx, Dy;
double x, y;
printf("a, b, c, d, e, f を入力してください。\n");
scanf("%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f);
D = a * e - b * d;
Dx = c * e - b * f;
Dy = a * f - c * d;
x = (double)Dx / D;
y = (double)Dy / D;
printf("x = %f, y = %f\n", x, y);
return 0;
}解説
Dx と D が int なので、そのまま Dx / D をすると整数除算になってしまいます。
そこで (double)Dx にしてから割ることで、浮動小数点の割り算になります。
