質問への回答
キャストは変数型を一致させる為だけに必要です。
「エラーになる」か「警告が出るがコンパイルが通る」か「エラーも警告も無し」かはコンパイラ依存になると思います。
データ型にキャストする必要があると参考書には書いてあります.
つまりこれに対する回答は「必要がある」かどうかと言われると「必ずしも必要ではないケースもある」という回答になる気がします。
勿論あるべき姿は変数型の一致したプログラムです。
キャストして合わせるのも問題ありませんが(※1)、私個人としては配列の先頭メモリアドレスをpに代入するという意味でp = &a[0]
やp = &balance[0][0]
という書き方が理解しやすい形かと思います。この書き方の場合型が一致しているのでキャストも不要です。
※1について
これらは全て同じ「配列の先頭メモリアドレス」をp
に代入します。
p = balance
, p = &balance
, p = &balance[0]
, p = &balance[0][0]
どれも正しい「配列の先頭メモリアドレス」を代入している為プログラムは期待通りに動きます。
しかし、型が一致していない為コンパイル時にエラーまたは警告が出る場合があります。
この点を解決する為にキャストして型を「強制的に一致」させます。
Cのキャストは強制的なので場合によっては安全でない場合があります。
C++ではCのような何でも強制的にキャストできてしまうキャストは邪道とされてます。
余談
話が少しズレますが、実際のメモリと配列とポインタの関係については以下の画像を見て頂ければイメージが出来ると思います。
c
1int a[10] = {10, 20, 30}, *p;
2p = &a[0];
c
1float balance[10][5], *p;
2p = &balance[0][0];