第10講 関数の学習
第13話 関数の意義のまとめ

第10話から第12話までの解説に間違いがあったこと、重ねてお礼申し上げます。
私が間違いに気がついたのは、

01 06 11 16 15 12 05 02 08 03 14 09 10 13 04 07
01 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
06 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
11 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
16 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
15 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
12 ○ ○ ○ ○ ○ ○ ○ ○ ○ ○
05 ○ ○ ○ ○ ○ ○ ○ ○ ○
02 ○ ○ ○ ○ ○ ○ ○ ○
08 ○ ○ ○ ○ ○ ○ ○
03 ○ ○ ○ ○ ○ ○
14 ○ ○ ○ ○ ○
09 ○ ○ ○ ○
10 ○ ○ ○
13 ○ ○
04 ○
07

この表を作ったときでした。C言語の時代に、何度も作ったプログラムであったのですが、
10年以上のブランクがあったこともあり、うっかり間違えました。
もちろん、プログラムが正しいか、実験を行うわけですが、すべての場合は1616通りもあるわけですから、
一部の例を作って実験するしかありません。
少しすっきりしなかったのですが、何例か作ってすべて正しく判定したので大丈夫だと誤って判断してしまったわけです。
トレースの重要性を改めて確認した思いです。

前に、この4次元ループプログラムは難解で、初心者の方が解説をなしにプログラムを読んでも理解できないのは恥ずかしいことではないと書きましたが、
プログラム経験が20年近い私でもうっかり勘違いしてしまうことがあるのですから、納得して頂けるかと思います。

さて、上の表を作ってプログラムはさらに次のように改善するともっとすっきりすることに気がつきました。

void f2(void){
  char i;
  char j;
  char k;
  char l;
  String^ w=L"";
  
  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      for(k=i;k<4;k++){
        if(k==i)l=j+1;
        if(k>i)l=0;
        for(;l<4;l++)
{
          if(a[i][j]==a[k][l]){
            h=1;
            break;
          }
          if(h==1)break;
      }
      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==0)label2->Text=L"数字の重複はありませんでした。";
  if(h==1)label2->Text=L"数字の重複がありました。";
}

関数版では、
void f2(void){
  char i;
  char j;
  String^ w=L"";
  char h;

  for(i=0;i<4;i++){
    for(j=0;j<4;j++){
      h=f3(i,j);
      if(h==1)break;
    }
    if(h==1)break;
  }
  if(h==0)label2->Text=L"数字の重複はありませんでした。";
  if(h==1)label2->Text=L"数字の重複がありました。";
}

char f3(char s,char t){
  char i;
  char j;
  for(i=s;i<4;i++){
    if(i==s)j=t+1;
    if(i>s)j=0;
    for(;j<4;j++)if(a[i][j]==a[s][t])return(1);
  }
  return(0);
}
(読者からの御指摘により、本日(2011/01/30)誤りを訂正)
変更点は、
    if(i==s)j=t+1;
    if(i>s)j=0;
    for(;j<4;j++)if(a[i][j]==a[s][t])return(1);

です。こうしたためにif文のif((k!=i) | (l!=j))が不要になりました。
lがj+1から(jがt+1から)始まっているため、l!=jの可能性がなくなったからです。
トレースすると、

i j セル内の数字
0 0 1
k l セル内の数字
0 1 6
0 2 11
0 3 16
1 0 15
1 1 12
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
0 1 6
k l セル内の数字
0 2 11
0 3 16
1 0 15
1 1 12
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
0 2 11
k l セル内の数字
0 3 16
1 0 15
1 1 12
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
0 3 16
k l セル内の数字
1 0 15
1 1 12
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
1 0 15
k l セル内の数字
1 1 12
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
1 1 12
k l セル内の数字
1 2 5
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
1 2 5
k l セル内の数字
1 3 2
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
1 3 2
k l セル内の数字
2 0 8
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
2 0 8
k l セル内の数字
2 1 3
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
2 1 3
k l セル内の数字
2 2 14
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
2 2 14
k l セル内の数字
2 3 9
3 0 10
3 1 13
3 2 4
3 3 7
2 3 9
k l セル内の数字
3 0 10
3 1 13
3 2 4
3 3 7
3 0 10
k l セル内の数字
3 1 13
3 2 4
3 3 7
3 1 13
k l セル内の数字
3 2 4
3 3 7
3 2 4
k l セル内の数字
3 3 7


00000007
の部分すなわちif文によって対象外にされる部分がなくなったのです。

第10講がだいぶ長くなりました。関数の意義をまとめて、この講を閉じることにしましょう。
�T 関数に分けることによって、それぞれのプログラムが短くなって分業が可能になる。
�U 関数に分けることによって、それぞれのプログラムが短くなってわかりやすくなる。
�V 関数に分けることによって、プログラムの構造がより単純になる。
   例 4次元ループが2次元ループに落とされる。
�W 関数の独立性により、構造化プログラミング(プラモデルの独立部品からプラモデルを組み立てるように、独立した関数から全体を組み立てること)が可能になる。
   
C++の場合、できるだけmainは小さくして、1つのまとまりを関数にする習慣を是非ともつけてください。
言い換えれば、構造化プログラミングを意識したプログラミングをする習慣を是非ともつけてください。

関数の意義は、�Tから�Wに尽きるわけではありません。
ポインタによる関数の利用、関数の再帰的使用などを学習すると、
関数がいかに威力を持っているかが実感されます。
ポインタを利用すれば、関数を配列のように利用することができますし、
再帰的使用をすれば、例えば10万次元ループも可能になります。
10万次元ループは、もちろんfor文などのループ文(実は後に学習しますが、ループ文はfor文以外にいろいろあります。)ではもちろん不可能です。
理由は、入れ子式にループ文を10万個も書いていかなければならないからです。
関数の再帰的使用なら、たった1個の関数で10万次元ループどころか、100万次元ループや1億次元ループでさえ可能です。
実際に、後に学習することになる魔方陣作成ソフトでは10万次元ループを優に超えているものもあります。



第12話へ 第11講第1話へ 第12講第1話へ



初心者のためのJava 入門 基礎から応用まで
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第1部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第2部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第3部
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすい vb 入門 vba 入門 基礎から応用まで 第1部
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ