デバッグは「問題を簡単にして境界線を出す」のが大基本!マルペケの質問箱に頂いている質問の中で、たまに問題を難しいまま解こうとして難儀されている方がいらっしゃいます。これはデバッグの基本である「問題を簡単にして境界を出す」ができていません。問題を簡単にするほどデバッグ作業で間違いを見つける速度は格段に向上します。いたずらに数値を追う本丸な攻めをする前に、外堀を埋めてバグを弱体化するのです。3;}}これら関数に文字列を渡せば簡単な暗号・復号ができます。0;}さて、これをDebug版で実行するとどうなるか?実はメイン関数が終了する間際にこんなエラーが出ます:「え〜、何だこりゃ!」とびっくりするわけです。「スタック周りの変数'str'が破損してるよ」と言われています。スタックの意味合いを知っていれば何となく察しが付くのですが、そうでないと何がなにやらです。バグなのは間違いありませんが、ではどうやってバグを見つけるか?ここで考えるのが「問題を簡単にする」です。問題を簡単にする方法には色々あります。上の例ですと渡している文字列が長いですよね。このままだとデバッガで追うのも大変ですし、第一暗号化した答えが正しいか確かめるのも一苦労です。問題を簡単にする方法その1は「入力データを把握できるくらい小さくする」です。str変数を思い切って「"a"」だけにしてしまいます。入力データを把握できるサイズにする。暗号化すれば"d"になるのがわかりますね。0;}ではこれで実行です...あっと、残念!やはり同じエラーが出てしまいます。入力に入れた文字列そのものに原因があるのではなく、何か関数内のロジックにおかしな部分があるようです。ここで大切なのは「文字列部分は正しそうだ」という事を突き止めた事です。「コード内にある正しい部分以外に間違いがある!」んです。上の例ではstr変数は問題無いと考えられたため、convertStr関数かdecryptStr関数に間違いがありそうだとあたりを付けられたわけです。問題を簡単にする方法その2は「正しい部分を増やす」です。今str変数は正しそうである事がすでにわかっています。convertStr関数とdecryptStr関数は正しいのか?それを検証するために、まずconvertStr関数だけ通してみます。入力データを把握できるサイズにする。暗号化すれば"d"になるのがわかりますね。0;}さて、これでどうでしょう...おっ、今度はエラーが出ません。convertStr関数は少なくともエラーを引き起こしてはいないようです。入力データを把握できるサイズにする。暗号化すれば"d"になるのがわかりますね。0;}さぁ、エラーが...で、出ません。コメントアウトを外すとエラーが出ます。「あれ?わ、わかんない!?」ではないんです。ここは、「両関数とも単独ではエラーにならないようだ」と考えます。ここで初めて関数内の挙動に疑いをかけます。\0(ナル文字はそのまま)となっているのでしょうか?この表、実は大切な事を訴えかけています。\0(ナル文字はそのまま)という検証だったらうんざりしますよね。答えが複雑過ぎるんです。自分が把握できるレベルにまで答えを簡単にすれば、検証は非常に簡単になるんです!ここでstr変数を格納しているメモリ領域をメモリウィンドウで観察してデバッグしてみます。入力前は、と正しく「a、\0」が入っています。00」になれば正解です。convertStr関数を通してみましょう:あれ!!64は良いのですが、ナル文字\0(00)が03になっています。ナル文字も3文字進められているのがわかります。3;}}あ!forループの条件文が「<」ではなくて「<=」になっています!これだと例えば「"a"」という文字列を渡すとlenが1になり、ループが2回まわってしまいます。終端文字がこの段階で消えてしまいます。ちなみに、これ自体は極めて危ないのですが配列内であるためエラーにはなりません。3;}}もう一度メモリウィンドウを見ると:はい、想定した答え通りになりました。「答えがわかっているとデバッグ作業は極めて簡単になる!」んです。一応このままdecryptStr関数も通してみましょう:大丈夫ですね(^-^)。これで、すべて想定した動きになってくれました。上の例で肝になっているのは「答えが既知である」という事です。これ、ひじょ〜〜〜に大切なデバッグの考え方です。上の例で「文字列を色々と入れて動くかどうかテストする」という方法も取れます。いうのは「パターン解析」の一種と言えます。色々なパターンを試してみて傾向を探るというデバッグ方法です。いう方法も必要ですが、これは確率的な判断になってしまいます。なくて、もし正しい答えを知っているならば、コードを狭めて正しくならなかった一点を突き詰めれば、あっという間にバグを突き止められます。「バグの境界線」を高速に割り出せるんです。上の例では、まず冗長だった入力文字列を小さくして答えを知りました。次に、両方の関数のいずれかをコメントアウトしてコードを狭めました。関数の入力と出力を見比べて「正しいかどうか」をチェックしました。これは答えを知っているからこそできるデバッグ方法です。結果として、convertStr関数が間違った挙動をしていたのを突き止めました。いうのは、プログラムのあらゆる所で応用できます。マルペケの質問箱に非常に多く頂いているのが「スキンメッシュアニメーションがうまくいかない」という質問です。スキンメッシュアニメーションは非常に沢山の情報を複雑に組み合わせて実現します。バグの大好きな環境と言えます。うまく出ないんですね。そこで「うまく出ない〜〜!」と困るのではなくて、問題を簡単にして境界線を出すんです。スキンメッシュの出力結果を自分の知る値になるように、メッシュの情報を可能な限り小さく小さくします。それこそ三角ポリゴン2枚を貼り合わせるくらいに簡略化して、ボーンも2本のみにしてしまいます。すれば、スキンメッシュに使用される情報の殆どを既知の値として認識出来るようになります。答えも難しくなく求められるはずです。それが出来ないというのは、スキンメッシュの仕組みそのものを理解していない事になりますので、まずはそこから勉強しないとバグは取れません。仕組みが理解できれば具体的な答えを出せますから、先の例のように「よし、ここまでのコードは正しい値を出しているな」と、正しく動いている範囲をどんどん広げていく、逆に言えばバグの境界線にどんどん迫る事ができるわけです。そのうちきっと「あ!」という瞬間に出会えます。これを発展させていくと「テスト駆動型開発」という開発手法にたどり着きます。JavaとEclipseで学ぶTDDテスト駆動開発」が読みやすいかなと思います。難しい問題を難しい状態で考える必要はありません。簡単にして、バグをあぶり出してしまいましょう。