ポインタで配列を歩く
添字を使わない走査
前回、a[i] は *(a + i) だと確認しました。ということは、添字を回す代わりにポインタそのものを動かしても、同じ走査ができます。
int scores[5] = {80, 90, 75, 70, 85};
for (int *p = scores; p < scores + 5; p++) {
printf("%d\n", *p);
}カウンタの i が消えて、代わりに p が要素の上を 1 つずつ移動しています。添字版と結果は同じです。どちらで書いてもよいのですが、ポインタ版に慣れておく理由が 2 つあります。1 つは、C の標準ライブラリや実務のコードがこの形で書かれていること。もう 1 つは、この先の連結リストのように 番号で場所を指せないデータ を扱うとき、走査はポインタでしか書けないことです。
終端をどう決めるか
ポインタ走査で肝心なのは、どこで止まるかです。scores + 5 は最後の要素の 1 つ後ろを指します。前回触れたとおり、この 1 つ後ろは「指すことだけは許されている」場所で、中身を読んではいけません。p < end の比較に使うぶんには安全です。
条件を p <= end と書くと、読んではいけない場所を読みます。うっかり <= にしたときにコンパイラは何も言わないので、ここは自分で見張ります。
終端を先に変数に取り出しておくと、意図がはっきりします。
int *end = scores + 5;
for (int *p = scores; p < end; p++) { ... }scanf にも p がそのまま渡せる
読み込みもポインタで書けます。scanf が欲しいのは書き込み先の番地なので、&scores[i] の代わりに p をそのまま渡せます。
for (int *p = scores; p < end; p++) {
scanf("%d", p);
}&p ではありません。p はすでに番地です。ここで & を付けると、ポインタ変数そのものの置き場所を渡すことになり、走査用のポインタが壊れます。
最大値は値ではなく位置で持つ
合計は値を足していけば済みますが、最高点は少し工夫できます。最高点の値ではなく、最高点を指すポインタ を持ち歩く形です。
int *best = scores;
for (int *p = scores; p < end; p++) {
if (*p > *best) {
best = p;
}
}こうしておくと、値だけでなく「配列の何番目だったか」も best - scores で取り出せます。名前の配列と点数の配列を並べて持っているとき、この差がそのまま名前側の添字になります。次回以降の成績管理でそのまま使う形です。
では、点数の読み込みから集計まで、添字をひとつも使わずに書いてみましょう。
要件
- 点数の読み込みと集計の両方をポインタ走査で書き、添字 [] を使わない
- 終端は scores + COUNT で決める
- 合計を「合計は400点です」の形で表示する
- 最高点を「最高点は90点です」の形で表示する
- 平均を「平均は80.0点です」の形で小数第1位まで表示する
入出力例
main("80 90 75 70 85") → "合計は400点です
最高点は90点です
平均は80.0点です"
main("100", "62", "88", "54", "71") → "合計は375点です
最高点は100点です
平均は75.0点です"
main("45 45 45 45 45") → "合計は225点です
最高点は45点です
平均は45.0点です"