BETA

C言語ことはじめはprintf()でいいのか問題

投稿日:2020-03-10
最終更新:2020-03-17

良いと思います(終了)

でも、挫折した人って多いですよね。私もそのうちのひとりです。ずっとプログラミングに手を出せずに来てしまいました。
私が学生だったのは10年以上前なので、今ではそんなことないのかもしれませんが、一般的なC言語の学習のはじまりって「#include <stdio.h>をおまじないで書いて、printf()でHello,worldやってみよう!」だと思います。さんざん議論されていることだとは思うのですが、私は今年に入った最近、そのひとつ低いレイヤーからはじめたことで、10年越しにようやく走り出せるようになったので、それを記録しておきたいと思います。
とても意識の低い学生の例が出てきますので、不快にならないでください。許してください。

その前に、前提として知ってたら役に立ったと感じられるものも並べてみます。

  • 論理回路の基本の基本 (ANDとかORとかXORとかってやつです)
  • PC部品の基本 (とりあえずやろうと思えばPC自作で組めるって感じ)
  • 算数 (数学ってほどではない)
  • 制御構文 (ifとかwhileとか:そっちが先なの?って議論は当然あります)

いつも霧の中にいる気分だった

ゲームばっかりやっていた自分が、その勢いのまま大学生になってみると情報系の学部にいたりします。流れのまま「C言語」の講義を受ける訳です。独習Cなどの本を買うことになり、週に何回かの講義の中で、なんとなく手を付けていくことになります。スマホが全然普及していないガラケーの時代ではありましたが、本当に興味があれば学生になる前からプログラミングには手を付けているはずです。でも、私はそんなこともなく、何の準備もないままに初学者となってしまいました。

#include <stdio.h>はおまじないです

どれだけの人がこのように教わったのでしょうか。
もちろん、一般的なHello,worldを厳密に理解するには本来説明すべきことがたくさんあり、その壁が厚いということもわかります。まだ慌てるような時間じゃない。後でそういうのは分かってくるのさ。そう言い聞かせて進んでいくわけです。段々と道にモヤが掛かっていきます。

printf()を使って文字を表示してみましょう。

急に出てくる関数。それこそがC言語に備わったものなのだという、やや間違った認識。でも、当時の私にはわかりませんでした。これがC言語というヤツなんだと考えた訳です。実際の所、標準ライブラリ以上のものを触っておけば良いというのは正解である気がしています。システムコールを触ってどうこうしようというのが、果たして「プログラミング言語に慣れていく」プロセスとして効率的なのかどうかはもちろん、正しいと断言できるものではありません。

それでも、モヤが増えていくんです。printf()の中身ってのがあるんじゃないかと。includeって結構大事なことやってんじゃないかと。でもお構いなしに進んでいきます。そうした「保留してるもの」が重なっているはずなのに、話題は変数や制御構文などの機能へと移っていくわけです。

補足:当時、私が通っていた大学の「C言語」講義は1年間のカリキュラムだった記憶があります。最終的に単位と認められるには試験を受ける必要がありました。その試験の最後にあった問題は「Hello,worldと出力するプログラムを書け」といったようなものです。レベルが低いと思いましたか?信じられないことに、その試験は紙による筆記試験だったんです。実話ですよ。

知識の分類をして進めよう

いわゆる情報系の学部では、同時に論理回路だとかデータベースだとかの講義も受けることになります。なんら学習意欲のなかった私には、それらが有機的に結びついていることに全く気付けませんでした。あまりに弱いですね。怒らないでください。ほんとすいません。ひとつひとつの講義は単位も取れてなんとかなっていた気がしますが、それがプログラミングに活きていくという発想がそもそもありませんでした。

C言語においてはCPUに近い部分を考慮できます。低レイヤーと呼ばれるそれを、初学者である私はまだ何も理解できていませんが、触れていこうとする格闘はしてみても良いと感じるようになりました。「モヤが掛かったままだけど進める」のが一般的なやり方なのだとすれば、「全然進んでいる気がしないけどハッキリと理解していける」のが、システムコールレベルからの学習だと感じる訳です。

システムコールといっても、せいぜいwrite()で色々触ってみようという程度ではあるのですが、それでも有効だと思います。これは感覚的なことなのかもしれませんが、プログラミングの様々な要素がいっぺんにゴチャっと出てこなくなるからです。変数や制御構文といった本来の機能的なものと、ライブラリに入ってる関数とがいっしょくたになってしまったまま進むというのはしんどい気がします。

プログラミングが得意であった方にとっては「そんな悩み方する??」と思われるかもしれません。でも、若くて柔軟だったはずの10年前の私には「おまじない」から始まるC言語の講義は全くついていけなかったのが事実なのです。そして30代になった今の方が、もっとやれるぞという意識に立てた……その差は大きいと感じています。

苦しいのは事実なのですが、バイト単位で文字列を管理しながら色々と組んでいったり、標準関数を再現しながら学んでみたりといった勉強法はそのままAtCoderなどの競技プログラミングにも活かせると思います。そして何より、冒頭で挙げていた「論理回路」「CPUやメモリなどのパーツの話」「算数(アルゴリズム)がなぜ必要か」「制御構文は別ものと整理する」がかなりわかりやすく自分のちからとして備わることを体感できます。

C言語においてはCPUとメモリのスタックをイメージだけでもいいので想定できると「自分はまだ"書き方"を知らないだけなのだ」と課題を正しく分析できますよね。アセンブリを直接書く訳ではなくても、アドレスや型といったものがどういうものかの想像ができる訳です。ですから、論理回路とCPU/メモリの知識を基本だけでも積んでいるならば、システムコールレベルの関数再現だとかに格闘していくことで、よく言われる<<ポインタこそが壁>>みたいな感覚は薄れるような気がしています。

printf()などの標準関数からとりあえず始めてしまうと、ポインタが出てきた所で当然「いきなりメモリアドレスを意識する」にシフトしなければいけないので、戸惑わない訳が無いんです。これはとても難しい概念だぞ、と打ちのめされてしまう。でも、実際のところはアドレスの問題なだけであって、その操作の「具体的な書き方に慣れていないだけなのだ」と心持ちしてから始められるのとでは、感じる壁の厚さが段違いだと思います。

まずは触ってみようよ、とのジレンマ

教育を考えようとすると、最初の一歩が大切というのは大きな命題です。

ですから最も手ごたえがあり、そして一般的なプログラミング学習にもそのまま展開でき、多言語へ移る際にも不足とならない「標準関数からの学習」は、デメリットが少なく感じられます。実際、私もそう思っています。そもそも文字列を扱う場合に色々想定しなきゃいけないなんてのは、高レベルの言語ではしっかりサポートされていますし、そこで詰まってしまう意義を感じられないというのも尤もな意見だと思う訳です。

なので、C言語ではない主流の言語から、仕事を意識して学び始めるということであれば、どんどんモダンなものに触っていけばいいと感じています。この記事内で私が感じていることとしては「C言語の学習って結構、前提知識が必要だよね」っていうことなのです。

独習をしようとすれば、これらのチグハグさを乗り越えねばなりません。なので、遠回りなようでも冒頭の前提知識のさわりだけでもうまく紹介してくれる人や機会と共に、システムコールレベルから丁寧に学べる何らかの環境が揃う方が、しっかり走り出せるんじゃないかと思います。

何より、今この歳になって10年越しに「今なら自分もできそうだ」と思えるに至ったのが、そんな体験をした為なのです。
C言語ことはじめはprintf()でいいのか問題。実の所は、プログラミング学習ことはじめは「C言語」でいいのか問題に、そのまま繋がっていくのかもしれません。答えはないと思います。

結局は人の縁の方が大きいと感じていますが、プログラミングを学習する目的という「その先」を見つめた時には、どうしても「プログラミングだけじゃないよ」という知識群が登場します。それらをひとりではじめから認識するのは大変なことなので、なぜ分類されているそれらの知識が噛み合っていくのか……が良い感じに整備されてるといいよねと感じる次第です。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

最近ちょっとプログラミングをはじめてみたので怒られない範囲の場所に来ました。

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう