わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

再帰の問い方

今年のCプログラミングの試験問題は,ひどいものでした.授業をきちんと聞けば正解は分かる(正解が答えられるよう準備できる)けれども,語句について,2年以降の授業で使うのか定かでないものを問うていました.
典型的なのが,再帰の問題です.
過去の自分の科目の試験で,どのような問題を出してきたかを調べてみました.いずれもPDFで公開していますが,これまでのポリシーに従い,URLは挙げません.

2003年度試験問題より

[1] 以下のそれぞれについて,標準的なC言語の規格もしくはプログラミングの心がけとして正しいものには○,間違っているものには×を解答せよ.

19. 再帰呼び出しは,無限ループを回避するために用いられる.

20. 再帰呼び出しは,帰納的あるいは循環的に定義されている対象と取り扱うときに,使用できるか検討するとよい.

2004年度試験問題より

[1] 以下のそれぞれについて,標準的なC言語の規格もしくはプログラミングの心がけとして正しい文になるよう《……》の中から選び,その番号を解答しなさい.

(12) 階乗やフィボナッチ数列は,帰納的に定義される数式であり,プログラミングにおいては《(1)再帰呼び出し|(2)グローバル変数》を用いると簡潔に記述できる.

2005年度試験問題より

[1] 以下のそれぞれについて,標準的なC言語の規格もしくはプログラミングの心がけとして正しい文になるよう《……》の中から選び,その番号を解答しなさい.

(11) 関数の内部で自分自身を呼び出すことを,《(1)自己|(2)再帰》呼び出しという.

[2] 以下のそれぞれのプログラムコードについて,実行すると何を出力するか,解答しなさい.

(5)

void count(int num)
{
  if (num <= 0)
    return;
  count(num - 1);
  printf("%d\n", num);
}
...
  count(5);

2006年度試験問題より

[3] 以下のソースファイル replace.c を読んで,各問に答えなさい.*1

#include <stdio.h>
#include <string.h>

#define STRMAX 10

char *strrep(char *str, const char *from, const char *to)
{
  char buf[STRMAX];
  char *p, *q, *r;

  strcpy(buf, str);

  p = strstr(buf, from);
  if (p == NULL) {
    return str;
  }
  q = p + strlen(from);
  r = str + (p - buf);

  *r = '\0';
  strcat(r, to);
  strcat(str, q);

  return str;
}

int main(int argc, int argv)
{
  char string[STRMAX] = {0};
  char *input, *from, *to;

  if (argc < 4) {
    printf("few parameters\n");
    return 1;
  }

  input = argv[1];
  from = argv[2];
  to = argv[3];

  if (strlen(input) + 1 > STRMAX ||
      strlen(input) - strlen(from) + strlen(to) + 1 > STRMAX) {
    printf("too long string\n");
    return 1;
  }

  strcpy(string, input);
  printf("before: %s\n", string);
  strrep(string, from, to);
  printf("after:  %s\n", string);

  return 0;
}

(9) 関数 strrep の内部を変更(プログラムコードの追加や削除をしてもよい)してコンパイルし,「./replace abcabc a A」を実行したところ,出力の2行目は「after: AbcAbc」となった.どのように変更すればよいか,概要またはプログラムコードを解答しなさい.

2007年度試験問題より

[1] 以下のそれぞれについて,標準的なC言語の規格もしくはプログラミングの心がけとして正しい文になるよう《……》の中から選び,その番号を解答しなさい.

(8) 再帰呼び出しをする関数がうまく動作するのは,《(1)関数内のauto変数が,関数呼び出しごとに生成される|(2)再帰呼び出しをする関数は,関数形式マクロで実現されている》からである.

再帰の良問とは?

2006年度[3](9)について,再帰が陽に現れていないので,補足しますと,「関数 strrep の内部に1行だけ追加して」と変更すれば,再帰呼び出しをするしか正解はありません.
さて,2005年度[2](5)と,2006年度[3](9)で,コードを読む問題,書く問題を課していますが,いずれも実用性は乏しく,通常,再帰なしで書くべきものです.
残りの問題は正誤判定で,いずれも消去法か,再帰の関数の例を思い浮かべることで,容易に正解にたどりつけるようにしています.とはいえ,語句や表現でよくないものが目立ちます.とりわけ2007年度の文中にある「auto変数」は,教科書に書かれていない俗語であり,試験ではその種の言葉を使わないようにすべきだった*2のですが,「授業資料にあるから」と,コピー・ペーストで取り出したのでした.
同じセメスターで実施している,Cのプログラムを書く科目の資料では,再帰呼び出しをする関数の構成方法を分割して書かれています.私もあの記述を参考にして,試験でもそこを問うべきだなと考えるようになりました.
それと別に,レポート課題で再帰呼び出しを使うコードを見せ,動作を答えてもらうというのも有望です.実は,今年度に冬休みの宿題でしていました.そこでは2次元平面上の探索でした.他に再帰を使うべき問題は,あるかなあ…といっても,毎年,再帰呼び出しをテーマにしなくてもいいと言えばいいのですが.

*1:main関数の第2引数argvの型は間違いですが,これは原文のままです.試験問題では小問の(1)に,このデバッグを行ってもらっています.

*2:答案で,教員の信念で使うべきでない語句が出たとき,教科書に書かれているのであれば,そこはバツや減点にすべきではないでしょうね.適切な意味で使用しているという条件をつけてですが.