第30問

さあレオ君、いよいよ最後の問題よ!
もう最後か〜。けっこう楽しかったのになぁ……
あら、嬉しいことを言うじゃない。
ユキ先輩のおかげで、僕もちょっとレベルアップできた気がします!
よかったよかった。それじゃあラスト1問、はりきっていきましょうか!
はーい!

以下は、第29問の答えのプログラムです。数値の並びを連結リスト(linked list)構造で表現し、その合計を関数SumListValues()で求めています。この関数ではループが使われていますが、ループを使わない方法に置き換えたいと考えています。

どう書き直せばいいか、分かりますか?
main.c
#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode {
  int value;
  struct ListNode *pNext;
} ListNode;

int SumListValues(const ListNode *pNode) {
  int sum = 0;
  for (const ListNode *p = pNode; p; p = p->pNext) {
    sum += p->value;
  }

  return sum;
}

int main(void) {
  ListNode node4 = { 40, 0 };
  ListNode node3 = { 30, &node4 };
  ListNode node2 = { 20, &node3 };
  ListNode node1 = { 10, &node2 };

  printf("Sum: %d\n", SumListValues(&node1));

  return EXIT_SUCCESS;
}
実行結果
Sum: 100
第29問は正しいプログラムを、別の正しいプログラムに書き換える問題だったわよね。
はい、そうでした。
そこで、さらに別の方法で正しいプログラムを書いてみよう!っていうのが今回の問題よ。
なるほど。でも、ループを使わない方法なんて、本当にあります?
あるのよ。数値の並びは10203040でしょう?
はい。つまり、求めたいのは「10203040の合計」ってことですよね。
そうね。それを最初の1つと残りの3つを分けて考えたら、「10」と「203040の合計」の2つになるわよね。
え……はい、なります。
その2つを足したら、求めたい合計になるのよ。
ええっ?それって解決になってます?
あら、何かおかしなことを言ったかしら?
だって、「203040の合計」のほうは、結局ループしないと求められないですよ。
そこはもう1回、最初の1つと残りを分けるのよ。
ん?「20」と「3040の合計」ってことですか?
そう!そうやって2つに分ければ、足し算できるでしょ?
あのー、何をどうすればいいのか、さっぱり分からないです……
うん。ちょっと手応えがあったほうが最終問題っぽいでしょ。
そ、そうですね……
じゃあ、ヒントね。合計を求める関数には何を渡しているかしら?
えっと、呼び出し元はmain()関数にあって……ここだな。
  printf("Sum: %d\n", SumListValues(&node1));
引数としてnode1、つまり1つ目のノードのアドレスを渡してます。
すると、1つ目以降の合計が分かるのよね。そこに2つ目のノードのアドレスを渡したらどうなるかしら?
それって、こういうこと?
  printf("Sum: %d\n", SumListValues(&node2));
そっか。この場合は2つ目以降の合計になるんですね!
そういうこと。だんだん答えに近付いてきたんじゃない?
そうなんですか?もうちょっと考えてみます!
この関数から自分自身を呼び出すようにすれば……