パスワードを忘れた? アカウント作成
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。

やる夫と学ぶプログラミング言語 C」記事へのコメント

  • by gonta (11642) on 2009年12月30日 15時43分 (#1695970) 日記

    >> 初心者に変数がグローバル変数だけと思わせるような筋、stdio.hをインクルードする理由を解説しない点についてはタレこみ人はどうかと思うが

    これね、教えたことがない人のセリフ。教えると、こうするしか無いのよ(main()の外にint宣言おいてあるのはいただけないが)。

    関数の概念の前にmain()関数があって、メモリの概念の前に"やscanfの&があったり、プリプロセッサの前に#includeがあったり、とどめ、printf()なんて可変長引数をとる、どう考えても最初に教えちゃいけない関数だったり。

    ある程度目をつぶって教えるしかない場所なんですよ。で、ポインタやってから戻って「実はscanfの&は・・・」というように教えるしかない。main()の引数char** argvなんて・・・じゃん。

    --
    -- gonta --
    "May Macintosh be with you"
    • 新入社員にCを教える講座を持ったことがあります。プログラミング初心者対象で。
      「プログラミング初心者にC言語を教えるのは間違ってる」と再三にわたり進言したのですが「業務で使用する言語を最初に教えないと」と却下。
      なんとか講義時間を8時間(1時間を週2で全8回)確保して、以下の流れで教えました。

      1コマ目:コンピュータの構造。CPU毎に機械語が異なる。コンパイラ。宿題は「C言語以外のプログラミング言語を調べてくること」
      2コマ目:なぜ複数の言語があるのか。同じソースから異なる機械語にするには。コンパイラの移植。宿題は「クロスコンパイラとはどんなものか調べてくること」
      3コマ目:適当に書いたテキストファイルをコンパイラに食わせる。なぜエラーが出るのか。宿題は無し。(だいたいシェルに慣れてなかったり質疑応答で潰れる)
      4コマ目:Cの解説スタート。変数について。数学と異なる記号の使い方。function(関数)について。C言語はfunctionを組み合わせて作る。

      int sum(int x, int y){
          int ans;
          ans = x + y;
          return ans;
      }

      宿題は「なぜsum関数をコンパイラに渡しただけでは駄目か考えること」(だいたいは文の区切りだの宣言だので時間がなくなる)
      5コマ目:コンパイラはmain関数を決めうちで読み込む。mainでsum(4, 5)とかしてみる。コンパイラが困るのでプロトタイプ宣言がある。結果をディスプレイに出す関数は既にある。ソースコードにコピペする代わりにincludeしよう。.hについて。プリプロセッサとリンカの話。宿題は「プリプロセッサは何をしてくれるか調べること」
      6コマ目:printfで結果の出力。forでのループ。ifでの分類。偶数だけを出力してみる。
      7コマ目:配列の話。3で割り切れる数だけ配列に入れてみる。配列の出力。文字列が無い話。配列の先頭と\0の話。やっとHello World!
      8コマ目:fizzbuzzを作ってみよう。質疑応答。

      教えることを絞り込んだので、きちんと理解してもらえたようで意外に好評でした。
      あとオマジナイを極力排除した組み立てにしたので「自分で理解してから使う」癖が付いたようで部署に戻ってからもスムースだったようです。
      目をつぶって教えなくて良いように考えたら、なんとかなるもんですぜ:-)

      Cを教えるのに、コンパイラの説明から入らないのは無謀ですし、プリプロセッサの説明をせずに標準ライブラリは使えません。
      やる夫のは、せっかく前フリ長いんだからもっともっと丁寧にやって良かったんじゃないかなあ。
      # Hello World!までの距離が長い言語は初学者向きではないと思うのですが、いまだに中々理解が得られないのが寂しいところ:-P
      # たまにCに慣れたやつが居るのでその時は数独ソルバーかCのコメントを取り除くプログラムを書いてもらってました。

      親コメント
      • by Anonymous Coward

        「プログラミング初心者にC言語を教えるのは間違ってる」と再三にわたり進言したのですが「業務で使用する言語を最初に教えないと」と却下。

        これはどちらも一理あるとは思いますが、教える内容のレベルにもよるでしょうね。
        例えば「やる夫の~」も読みましたが、プログラミングの基礎であってC言語である必要が全くありません。
        この場合はC以外で教える方がいいかも。

        kousokubusさんも書かれているように

        Cを教えるのに、コンパイラの説明から入らないのは無謀ですし、プリプロセッサの説明をせずに標準ライブラリは使えません。

        この辺の解説(ソースファイルの分割/リ

    • Re:とは言うけどね (スコア:2, すばらしい洞察)

      by Anonymous Coward on 2009年12月30日 16時21分 (#1695980)

      >> 初心者に変数がグローバル変数だけと思わせるような筋、stdio.hをインクルードする理由を解説しない点についてはタレこみ人はどうかと思うが

      (main()の外にint宣言おいてあるのはいただけないが)。

      それがまさに「初心者に変数がグローバル変数だけと思わせるような」ジャマイカ。
      このソースならローカル変数で書けるし、後々main()以外の関数を導入した際に説明が容易だと思う。

      親コメント
      • by haratake (365) on 2009年12月30日 18時53分 (#1696042)

        ここは、グローバル変数でよいと思いますよ。
        初心者なんですから、グローバルもローカルもわからないでしょ。
        おそらく、初心者にはローカルの概念が難しいと思われ、
        関数を教えるにせよ、最初はグローバルで教え、
        そのあと、ローカル変数を教えつつ、
        それぞれのスコープの違いなどの特徴を学ぶのがスムーズかと。

        最初は、問題を単純化して覚えやすくするために、
        正しくないことでも、あえて正しいと教えることも多々ありますからね。

        親コメント
        • Re:とは言うけどね (スコア:3, すばらしい洞察)

          by SteppingWind (2654) on 2009年12月30日 20時09分 (#1696076)

          初心者はmain()以外の関数なんて分からない(少なくとも自分から作ろうとはしない)から, グローバルとローカルのいずれか一つで話を進めるならローカル変数だけにした方が後での実害は少ないです.

          おそらくプログラマと称している人の半分程度は, 関数を作ることができないと考えておいた方が安全です.

          親コメント
          • おそらくプログラマと称している人の半分程度は, 関数を作ることができないと考えておいた方が安全です.

            マジすか?!
            じゃいったいそういう彼らは関数作らないで何を作るんで?

            親コメント
            • Re:とは言うけどね (スコア:5, おもしろおかしい)

              by Anonymous Coward on 2009年12月30日 22時27分 (#1696126)
              バグじゃないかなー
              親コメント
            • by SteppingWind (2654) on 2009年12月30日 22時28分 (#1696127)

              基本的にはmain()関数, あるいは仕様書に提示されているエントリ関数(これもstubは事前に提供されることが多い)だけで, 内部的にはのべたんで記述します. それが1万行を越えたとしても, 決して複数の関数に分割することはありません.

              関数とは彼らにとっては既存の機能を呼び出すために存在するもので, 自分で作成するものではないのです.

              親コメント
              • Re:とは言うけどね (スコア:2, すばらしい洞察)

                main()も関数…って茶々は他のコメントで入れたので置いておくとして。

                それ書いてる本人は辛くないんですかね?
                main()に全部書いてねって言われたら、それは普通に書ける人にとってはむしろ拷問ですよねぇ?
                (関数がダメってことは多分関数型マクロはもっとダメですよね?)

                かの史上初のプログラマブルな計算機である解析機関(機械式、残念ながら完成しなかった)にさえ
                Ada女史がサブルーチン・コールの仕掛けを入れようとしたという歴史もありますし、
                1万行にもなる場合、「必要は発明の母」的に関数書きたくなったりしませんかね?
                #高校生の頃(1980年代前半)、FORTRAN入門でズラズラ変数並べる代わりに配列を習った記憶があるけどそんな感じに。>「必要は発明の母」
                必要性・動機があれば学習は速そうなものですが…。

                親コメント
              • by Anonymous Coward
                そうですね。
                .NET系だとイベントハンドラ内にゴリゴリ書かれてしまいますね。

                そもそも教える側が関数/メソッドを切り出すための考え方を教えていないので
                関数を書くと、追跡すべきコードが分散して読みにくくなるとしか思ってないと思います。

                当然、教える側も分かってません。
              • by Anonymous Coward
                Cプログラミング診断室で紹介されていた最長不倒関数みたいなのは
                さすがに見たことがですけど、同じような処理をコピペで複数の関数に
                撒き散らすってのは普通にあります。
                おまえ、それ関数にしようよ、もしバグってたら全部直すの大変だよ、
                と言うと、「あ、そうか!」という顔をします。
                でも言われないと関数化しないんですよね。
              • by Anonymous Coward

                大昔のBASICしか知らないような人がlabelとgotoがあって良かったって言ってたのを思い出してアタマがまた痛くなった

              • Re:とは言うけどね (スコア:2, すばらしい洞察)

                by SteppingWind (2654) on 2009年12月31日 13時23分 (#1696276)

                main()に全部書いてねって言われたら、それは普通に書ける人にとってはむしろ拷問ですよねぇ?

                私にとっても拷問です. でもここで気をつけなくてはならないのは, それが「普通」であるという認識が間違っている(かもしれない)ということです. 自称プログラマの内のかなりの割合が, 問題を論理的に分割して対応するよりも, 既存の処理パターンを高機能エディタやIDEで集積して一つの物にすることの方が簡単と思っている(らしい)ことです. 前者を解析型, 後者を集積型と呼ぶとすると, 解析型ではプログラミングに際して常に考えることを要求されるのですが, 集積型では仕様書に従ってパターンを並べていくだけなので考えなくてもよいということみたいです. ですからそんなプログラムを書く当人は, 苦労はするけど決して拷問とは考えていないみたいです.

                ちなみに, さらに酷い拷問は, こうして作られたプログラムをメンテナンスさせられることです.

                親コメント
              • by Anonymous Coward
                修正するのも拷問だから普通に書ける人はそんな環境に何時までも居ないでしょう。

                # 世の中(職場)に不満があるなら自分を変えろ。それが嫌なら耳と目を閉じ口をつぐんで孤独に暮らせ。それも嫌なら…
                ## 世の中(職場)からドロップアウト、ですかね。その後普通に書ける環境を探して転職する、と。

                ## 職場環境の改善に自ら乗り出すって手もありだけれど…
              • by Anonymous Coward

                集積型というのは、単に恐い物しらずなだけだと思う。
                そういう集積型で作られたものはスパゲッティプログラムになりやすく、作った本人にも
                デバッグできなくなる。

                解析型は将来を予測しながらコードを書くので、必要があれば解析型だけでなく集積型の
                スタイルを取ることもできる。しかし現実的にみて集積型のスタイルが望ましいことが
                滅多にないため、ほぼ全ての場合で解析型/分割統治型のスタイルを取ることになる。

              • 名大、東工大、九大の学生さんたちや、某F社の研究所の同僚、先輩などプログラミングする人々を眺めてきましたが、本当に「main()に全部」をやった人を実地で見たことは(「笑い話」としては出てきても)なかったんですが、これは実はあんまり普通でない環境なんでしょうか?

                親コメント
              • ## 職場環境の改善に自ら乗り出すって手もありだけれど…

                以前、乗り出しました。
                プロジェクトのメインツールの作り直しの機会に。

                といってもさすがに「main()に全部」な人は居なかったので
                そこの改善ではなく「Unitテスト書きましょう運動」。
                「原理主義的だ!」とブツつかれつつも、結果として若干改善。

                しかし今ひとつうまくモジュール化がなされた設計になってなかったので、結果としてテストしにくく、今ひとつテストが不十分なモジュールが発生・・・。現在担当者の異動によりそこを引き継いだのでリファクタリング中。

                親コメント
            • by rose (10717) on 2009年12月31日 11時55分 (#1696265)

              プロシジャ?

              戻り値voidで結果をグローバル変数に格納とか、よく見かけちゃいます。

              親コメント
            • by keepiru (34886) on 2009年12月31日 16時11分 (#1696311) 日記

              スパゲッティでは?

              親コメント
            • by heavensgate (21016) on 2010年01月01日 22時06分 (#1696743)

              日本の4年生大学を卒業していて、関数という言葉は知っているはず(数学で出てきますから)なのに、
              それがプログラミングで出てくる「関数」と結びつかない、ってことはありますよ。
              やってることは数学の関数と同じなのに。

              パラメータが複数あって、結果が一つだけ出てくるのだから、これは関数でしょ?
              で、関数として作っておけば、他から使い回せるでしょ?

              って言っても、なかなか関数を作れない、ってのは、実際に新人教育で教えてみて半分以上いたし……

              ただ、こういうのは、「処理を分割すること」がそもそもできてない。
              ある処理を、細かい処理の箇条書きにばらしてみることが上手くできないんですね。
              ここができるかどうかが、そのままプログラミングができるかどうかにつながるかと思います。

              --
              -- To be sincere...
              親コメント
              • まぁでも、数学、特に解析学とかでやる関数は連続関数なんでイメージしにくいかもしれませんね。対応関係よりグラフとかのイメージのほうがどうしても鮮烈でしょうし、離散的な対応関係に拡張して考えるのは若干ギャップがあるのかもしれません。

                もちろん連続関数も集合論的な意味での関数を基礎においていて、そこをわからないとちゃんと理解はできないとは思うんですが、離散数学とかやらないとイマイチ想像しにくいのかもしれません。工学部だと計算機関係に進まないと離散数学はやらないで解析方面だけで終わる可能性もありますからね。

                また値の対応関係としての関数と計算手順として書かれた関数の関係も若干ギャップがある可能性もありますね。

                親コメント
              • プログラミングで出てくる「関数」と結びつかない

                関数型言語をかじった立場で見れば、C言語の関数って数学的な関数とは、副作用のあるなしの所が全然違うんだもの。結びつかないのはある意味、当然じゃないですか?

                私はC言語の"function"を「関数」って訳したのは結果的にあまり良くなかったと思ってます。今考えれば「機能単位」くらいかな。でも最初に「関数」って訳語をあてた時、C言語は「分かっている人が使う言語」でしたからね。そこは責められないし、関数という言葉が「分かっている人達」に広まった状況から別の言葉を使うと、更に現場で混乱しそう。じゃあどうすれば良かった、これからどうすればいいのかと言われると分かりませんが。

                「C言語の関数って機能単位の事なんですよ、数学の関数とはちょっと違う」って研修の時に言うのかなぁ。

                --
                vyama 「バグ取れワンワン」
                親コメント
              • by Anonymous Coward
                まあ確かに4年生大学を卒業して(そのうえ2年大学いって)いるのだが、関係データベースの関係という言葉が数学のリレーションだということを 知ったのはRDB使って10年くらいたってからだよ。。。俺。。 関数を作れない人は関数を使えないのかな。たぶん、そうじゃないんだよね。そのmainのなかに、printf("hogehoge") とかふつうにかいてるよね。 使えないんだったらそれはそれでわかるんだが、使ってるものを作るのは心がけ次第とか教え方次第なんじゃないかなあとおもったりするね
              • by heavensgate (21016) on 2010年01月04日 16時17分 (#1697647)

                機能単位としてしまうと、「式の中に繰り込むことができる」というのが上手く表現できないと思います。
                結局、関数という訳語が一番なのではないかと。

                関数が数値以外を返すことがある(もしくは何も返さない)ってとこにブレークスルーがあるのかなあ。

                --
                -- To be sincere...
                親コメント
              • by Anonymous Coward
                FORTRANにはFUNCTIONとSUBROUTINEというものがあってじゃな……
        • Re:とは言うけどね (スコア:1, すばらしい洞察)

          by Anonymous Coward on 2009年12月30日 19時55分 (#1696073)

          初めて何かをやる場合などは、最初に教わった方法・手順で後々まで覚えていく事って結構あると思うので、
          意味もわからないところから教えるのであれば、ローカル変数使用した方法で教えていって
          コードを組むときの定石として覚えてもらうって方法もアリかなぁとは思います。
          (手段としては#include をおまじないと教えるのと同レベルかもしれませんが・・・)

          親コメント
      • by Anonymous Coward on 2009年12月31日 15時49分 (#1696307)

        > 後々main()以外の関数を導入した際に説明が容易だと思う。

        関数の部分で ベタ書き → 関数化 と教えるのなら
        変数についても グローバル → ローカル と教えた方が合理的じゃありませんか?
        問題点の説明も、構造化の歴史をなぞった方が教えやすい

        数年、Cを教えていた事があります。
        初めからグローバルで教えた事も、ローカルにした事もありますが
        ある程度のステップを踏んで学習する際は、後から覚えた方法を(より良い方法だと思って)使う傾向にあります。

        グローバル→ローカルで教えたときは、ローカルで書く学生が多かったですが
        ローカル→グローバルで押してた時は「こっちの方が便利だ」と思ったのか、グローバルで書く学生が多かったような記憶があります

        ちゃんと説明はしたんですけどね

        親コメント
        • Re:とは言うけどね (スコア:1, すばらしい洞察)

          by Anonymous Coward on 2010年01月01日 4時58分 (#1696489)

          ある程度のステップを踏んで学習する際は、後から覚えた方法を(より良い方法だと思って)使う傾向にあります。 グローバル→ローカルで教えたときは、ローカルで書く学生が多かったですが ローカル→グローバルで押してた時は「こっちの方が便利だ」と思ったのか、グローバルで書く学生が多かったような記憶があります ちゃんと説明はしたんですけどね

          それはどうでしょうか。単に最近聞いたほうを使っただけのように思いますが。 詳細な説明なくグローバルで進め、途中でローカルとの使い分けを学ぶと、 defaultがグローバルで,特定の使用状況のときローカルをつかうように捉えそうです。 perlは言語仕様的にそうなってしまいますが、Cではローカルが基本で他との共有が 必要なもののみグローバルにすべきでしょう。 教える順番の問題というより機能の違いを教えきれていないというか...

          親コメント
        • by Anonymous Coward
          > 関数の部分で ベタ書き → 関数化 と教えるのなら
          > 変数についても グローバル → ローカル と教えた方が合理的じゃありませんか?
          > 問題点の説明も、構造化の歴史をなぞった方が教えやすい

          いや、やる夫は根本的に間違っているわけで、その一部だけを捉えて合理的だなんだといっても不毛なだけです。
    • 文章だけなら、たれたれと書き流す事も出来るのですが、
      AA連投というスタイルから「細かい事を書き連ねるのが困難」
      という制約があったのではないでしょうか。

      「テンプレのセリフ書き換えりゃ出来るんだろ?」
      と感じる人も居るかと思いますが、
      意外に工数がかかりますので。

      また、文字数ばかりがかさんでいくのも、
      作っていていまいち許しがたいので、
      詳細な説明文を織り込むのは、
      中々難しいのではないかと。

      親コメント
    • 概念教えるんじゃなければ、scanf なんてそもそも教える必要無いでしょう。
      親コメント
    • by Anonymous Coward

      ポインタ教えないならC言語である必要ないですよね
      とっつき辛いし流行りのオブジェクト指向的なプログラムを学ぶのも難しいし
      RubyとかPythonとか覚えてもらった方が百倍役にたつと思いますよ。

      • by Anonymous Coward
        そうですね。
        何よりも問題なのはプログラミングとC言語をまとめて教えているところです。C言語はおよそプログラミングの学習に向かない。
    • by Anonymous Coward
      ならば代わりにTiny BASICを教えればO.K.

      真面目に話をするなら、きっちりプログラミング言語を教えたければC言語なんぞ捨ててALGOL系の言語を使えばよろしい
    • by Anonymous Coward
      >> (main()の外にint宣言おいてあるのはいただけないが)。

      ここの意味が判りません。 void main()派?
      main関数はintを返しますよね?(少なくともC初心者への教育環境としては)

      「詳細は後で説明するから、まずはmain関数は
      int main(int argc, char **argv)
      で始めると覚えとけ。」でいいのでは。

      引数を与えることができなかったり,戻値が不定なプログラムは、後々不便なことになるので、
      最初は使わないにしても、呼出形式は初めから引数を受け取り,intを返す形で書き始めることを推奨したい。
      void main(void)は、組込等の特殊環境の宣言を許容するための併論規格だと思い
      • by Anonymous Coward

        (main()の外にint宣言おいてあるのはいただけないが)。

        ここの意味が判りません。 void main()派?
        main関数はintを返しますよね?(少なくともC初心者への教育環境としては)

        違います。

        int n;
        int main() { ... }

        と、int 型のグローバル変数を利用している件について言っています。

      • by Anonymous Coward

        あー違う。関数の返り値とか引数の話してない。単に変数の話。

        第二話最後のやる夫の回答で言えば

        #include <stdio.h>
        int a; //<-この一行
                     
        int main()          
        {                 
        a = 4 * 5;         
        printf("%d\n",a);   
        return 0;        
        }

        を問題にしてる。global変数とlocal変数のごっちゃ怖いのはこのあと、menseki関数とか定義して

        #include <stdio.h>
        int a;

        int menseki(int a, int b)
        {
          int p;
          p = a * b;
          return p;
        }
                     
        int main()          
        {                 
        a = menseki(4, 5);         
        printf("%d\n",a);   
        return 0;        
        }

        ってソース書いたとき、どんな答えが返ってくるか予想がつかないこと
          (コンパイラがmenseki関数のlocal変数「a」とglobal変数「a」を区別するか同一視するか?)
        (若干違うけど、global/localで同じ変数名(hogeとか)入り乱れたソース(数万行)で、
         「-O2」と「-O1」で答え違う、というデバッグした経験ア

        • by Anonymous Coward

          なぁんだ。グローバル変数のことは別に言及してあるし、"変数宣言"でなく"int宣言"と
          殊更に型を限定するような書き方だったので、別の点があって指摘してるのかと深読みしてました。

          int a;

          int menseki(int a, int b)
          {
              int p;
              p = a * b;
              return p;
          }
                       
          int main()          
          {                 
          a = menseki(4, 5);         
          printf("%d\n",a);   
          return 0;        
          }

          ってソース

アレゲは一日にしてならず -- アレゲ研究家

処理中...