マガジン - C言語教室
はじめに
C言語なんて久しく本格的に書くようなことは無かったのですが、ちょっとした出来事があって説明する羽目になりました。
C言語教室始まる
ということで作ったテキストを公開しようと思いはじめたのが、この教室です。基本的な文法は書かれているものが既にたくさんあるでしょうし、他の言語での経験がある方であれば、すぐにわかるだろうというところはあえて省いています。厳密さを求めれば、細かな文法上の説明はかなり面倒なものになりますし、最初にそんなことをしていればせっかく盛り上がったやる気がどこかに行ってしまいます。まずは「手を動かせ!」です。
ということで、この教室はまったくC言語を見たことが無い方には向いていないかもしれません。どちらかというと少し勉強してみたけど、良くわかっていないとか、他の言語の経験はあるのだけど、C言語も勉強してみたいという方のほうがあっていると思います。もちろん、私のように最近、使っていないのでいろいろ忘れてしまったけれど思い出したいという方も歓迎です。
なお、C言語を使うPC上の環境については、利用するハードウェアやOS、パッケージによって大きく異なるので、この教室の中では説明しません。お使いのOSに合わせてググるなどして環境を構築してみてください。もしくは身近な人に作ってもらってください。すぐに手を動かしたい人のために ブラウザで動く C言語実行環境 をご紹介していますが、一般的なC言語と少しだけ異なる挙動を示す部分もあるので、ご注意の程を(なるべくこの環境で動作するように確認はしています)。
最後まで行ってもきっとC言語を網羅したことにはならないと思います。とはいえわからない時にはちょっと調べれば大丈夫というところまではやっておきたいと思います。
C言語教室 第1回 - 関数呼び出し
関数呼び出しを通じて、呼び出し側の引き数の値が呼び出される関数の引き数にコピーされることを学びます。関数の中で宣言した変数は、その関数でしか使うことが出来ず、たとえ名前が同じでも別の関数と別のものであることを理解します。
C言語教室 第2回 - 参照渡し
関数を呼び出して、呼び出した側の変数を呼び出した先の関数で変更をするには、値ではなくて参照を引き数として渡すことで変更できることを学びます。変数の参照を得る方法と、参照から変数の値を得る方法を理解します。
C言語教室 第3回 - 配列という入れ物
同じ性質の変数が多くある場合、配列という形で変数をまとめる方法があることを学びます。さらに配列の配列であるとか、配列を参照を使って値を得る方法を理解します。
C言語教室 第4回 - 配列を関数に渡す
配列を関数の引き数として渡すことはできないけれども、配列の参照を渡すことができるので、参照を渡して配列変数の値を使う方法を学びます。
C言語教室 番外編1 - 第4回の課題について
第4回で出された課題についての解答及び解説を行っています。配列の参照とポインタ型の似ているけど違う部分も説明しています。また「最も小さい整数の値」をシステムの定義から使う例も載せています。
C言語教室 第5回 - 文字と文字列
文字は char 型、文字列は char 型の配列として扱うこと、文字はシングルクォーテートで括り、文字列はダブルクォートで括ることを学びます。また表示されない文字や、他の用途で使われる文字を使う時のエスケープ文字を覚えます。さらにC言語の文字列は、文字の集まりの最後にヌル文字が置かれることを理解します。
C言語教室 番外編2 - 第5回の課題について
第5回で出された課題についての解答と解説をしています。配列で表現していた文字列をポインタを使う形に書き換えていく例を示しています。またnoteの記事で頂いた答案の添削も載せています。
C言語教室 第6回 - 文字列操作
文字列をコピーしたり複数の文字列を繋げることにより、文字列に対する基本的な考え方を学びます。配列をポインタで扱う方法を理解します。また文字列の最後にあるヌル文字の扱いに注意します。
C言語教室 番外編3 - 第6回の課題について
第6回の課題について解説しています。呼び出した関数で使う領域は呼び出し元で確保しなければならないことと、確保した大きさを超えて領域を使ってしまうとどうなるかを説明しています。
C言語教室 第7回 - 動的なメモリ割り当て
これまでは必要なメモリを予め確保する方法でプログラムを書いていましたが、ここで必要になった時点で必要なだけのメモリを確保する方法を学びます。確保したメモリは「必ず」解放しなければならないことに注意します。
C言語教室 番外編4 - 第7回の課題について
第7回の課題について解説しています。関数によって得られたメモリ領域を解放しなければならないことを、どのように扱えば良いかが議論になりました。また動的なメモリが実行時に確保できなかった場合の処理や NULL ポインタについても触れています。
C言語教室 第8回 - 文字列を扱う標準ライブラリ
C言語標準の文字列処理ライブラリ関数のうち、代表的なものを紹介しています。それぞれの関数の動作と呼び出す時に使う引き数の型について説明しています。これまでに説明していなかった const および restrict について簡単に解説しています。
C言語教室 番外編5 - 第8回の課題について
第8回の課題について説明しています。変数の初期化や引き数に NULL が渡された場合の対処についてが議論されています。
C言語教室 第9回 - 演算子いろいろ
C言語で使える演算子について、カテゴリごとに整理して説明します。注意点についても少しだけ補足しています。
C言語教室 第10回 - 文字種判定と文字コード
アルファベットの大文字、小文字の判定や表示可能文字であるかなどを調べる標準ライブラリ関数を説明します。文字コードに依存せず意図を明示することが大切であることを学びます。
C言語教室 解答編 第10回
第10回の課題及び演習の解答を載せています。文字コードの符号と終端文字の扱いに注意が必要なことが解説されています。
C言語教室 第11回 - プリプロセッサとマクロ
# で始まる行はコンパイルに先立ちプリプロセッサによる文字列置換が行われます。プリプロセッサで使う代表的な #include と #define について説明します。また引き数がある #define を使ってマクロを記述する例を学びます。
C言語教室 解答編 第11回
第11回の課題と演習の解説をします。おまけとして短絡評価の話もあります。コンパイラによって異なる結果が出る例が話題になっています。
C言語教室 第12回 - 中間まとめと振り返り
これまでの教室で、やったことを簡単に触れた後、「空白とインデント」で空白をどのように入れるのか、「ポインタ変数」でPascalとアセンブラでのポインタの扱い、「配列変数とポインタ変数」でイテレータ、「コメント」でコメントの内容が間違っていてもエラーにならない話をしています。
C言語教室 第12回(続) - 課題と演習
まとめと振り返りが長くなってしまったので、課題と演習をあらためて投稿しました。今までの中間テストということにして、9つの課題とひとつの演習が出されています。
C言語 - main関数の引き数を組み立てる
前回の演習で、main 関数の引き数を解釈する内容が出たのですが、GUI 環境などで main 関数に引き数を与えることが難しい場合のために、main 関数を呼び出したかのように機能するサンプルコードを載せました。
空白で区切られた文字列から、標準ライブラリ関数である strtok を使って文字列の配列を作っています。
C言語教室 解答編 第12回 と オーバーフローのはなし
中間テストの課題のうち、課題1~7 について、解答例を載せて解説しています。閑話では、C言語では演算結果が代入する型の範囲に収まらないオーバーフローが発生しても知ることができないので注意する必要が有ることに、他のプログラミング言語ではどうなるかも含めて触れています。
頂いた答案についても課題1~7の分にコメントしています。変数を初期化するのにポインタ型では NULL は正しいのですが、数値型には使わない話と、ループ処理の中での continue と break の使い分けを簡単に取り上げました。
C言語教室 解答編 第12回(続)
課題8 と 9、演習の解答を載せています。閑話では、プログラムを呼び出す際にシェルがどのようにコマンドラインを main に渡すのかについてに触れています。シェルのワイルドカードなどの正規表現の扱いと、エスケープ文字などについて学ぶ必要が有ることに触れています。
課題の解答では、文字型の符号ありと無しの間で適切な型変換を行う難しさと、一旦確保した領域の大きさを変更する realloc について取り上げています。演習では、受け取った引き数を処理するための getopt に触れています。
頂いた答案についてですが、文字型の変数に 0x80 以上の値が含まれている時に話と、表示可能ではない文字を表示してしまうことへの危険性を取り上げました。それから exit 関数でプログラムを終了させる時の引き数の値について説明しました。またオーバーフローするかどうかが型の符号のあるなしで挙動が変わってしまうので、ループが抜けられなくなる問題が取り上げられています。
C言語教室 解答編 第12回(続続) - ChatGPT による答案提出
最近、話題のチャット型人工知能である CharGPT に課題を解かせたところ、答案に耐えられる内容だったので、答案を紹介してコメントをしました。
内容以前の話しとして、どうやらタブは 2 で、どうインデントしているのかという観察と、いずれにコードでも引き数のチェックは行っておらず、ライブラリ関数の戻り値のチェックも行われていなことを発見しました。
いずれに解答も設問に正しく回答しており、特に引き数付きマクロの展開においても、きちんと括弧が使われており、また変数名やコメントも適切で英語力に関しては下手な日本人よりも既に優秀なようです。
設問の文章に曖昧なところがあると、意図しない回答が得られてしまったり、設問毎に人格が異なる(言語も異なる)のにビックリはしますが、「よくある」コードを書くだけであれば充分なことがわかりました。
C言語教室 第13回 - 文字コードと符号の取り扱い
中間テストで符号についての問題が議論されたので、符号、特に文字型の符号についてを取り上げました。また型の値の最大、最小といった値とオーバーフローの関係についても触れています。符号なし型の数値リテラルの記号と暗黙の型変換についても説明してあります。最後にマルチバイト文字列についても簡単に触れました。
C言語教室 第14回 - 変数型のサイズ
整数を扱う int 型の他にサイズの異なる整数を扱う short 型、long 型、そして long long 型について説明します。変数だけではなく数値を直接コードに書く数値リテラルについても触れています。これらの型の間で発生する型変換と、数値以外にもポインタ型や文字型の異なるサイズの型があるという議論もあります。
C言語教室 第15回 - 構造体の基本
同じ型の変数をまとめるのが配列で、異なる型の変数をまとめるときに使うのが構造体です。構造体の型を定義する時と、その変数を使う時の宣言について説明しています。構造体は配列にすることも出来、構造体の中に構造体を含むことも出来ます。
C言語教室 解答編 第14、15回 - と、余りの符号
第14回(型のサイズ)と第15回(構造体)の課題と演習の解答を載せています。閑話として割り算の余りに符号があるのか無いのかという話を書きました。おまけとしてコンパイラの最適化処理でバグが出るととても困るという経験を紹介しています。
頂いた回答に対してコメントもあり、その中で数値の3桁区切りの話題が出ています。locale を設定してもうまく動作しないケースもあることに触れました。
C言語教室 第16回 - 構造体あれこれ
構造体へのポインタ変数の使い方と、構造体変数への代入と比較について説明しました。また初期化についても簡単に触れています。
C言語教室 余談1 - 数字は何桁ごとに区切るのか
第14,15回の回答で出てきた数字を3桁区切りの文字列に変換するコードを書いていく過程を紹介しました。最初にまずちゃんと動くコードを書いてから、冗長な部分を見つけ出し直していきます。ライブラリにある関数であっても自分で書くことにより、理解を深め、必要なときに処理を少し変えることも出来るようになります。
C言語教室 第17回 - 共用体とは何か
構造体と似ているように見える共用体ですが、その使い方は随分と異なっていて、具体的な使い方をいくつか紹介しています。また構造体変数がどのようにメモリに格納されているか、アライメントとパディングについても触れています。
C言語教室 解答編 第16、17回 - と、データの構造化
第16、17回の課題の解答をしています。余談としてなぜ構造体というものが必要で、オブジェクト指向プログラミングに繋がっているかに触れています。構造体の参照を配列とポインタ、それぞれで引き渡す例を載せています。共用体ではエンディアンについても説明しました。
C言語教室 第18回 - ビットフィールドと typedef
構造体や共用体でメンバ変数の占める領域をビット単位で指定できるビットフィールドの使い方を説明しています。ビット単位で指定しても全体としてのサイズはその合計にならないことに注意が必要です。また typedef キーワードを使うことで型の別名を作ることができ、構造体や共用体の宣言で使う例をあげています。
C言語教室 第19回 - 単方向リスト
同じ型の変数をまとめて扱う仕組みとして配列がありますが、構造体を使うことで複数の変数をまとめるリストの仕組みを説明します。リストには種類があり、最初は先頭からのみ辿ることが出来る単方向リストを取り上げます。リストを使って配列と同じような処理をする方法を学びます。
C言語教室 解答編 第19回 - リスト構造についての補足
第19回の解答例を解説しています。そもそもどうしてリストというものが必要なのかについて補足しています。またコードでは説明しきれなかったリストの構造を図を使って説明しました。リスト処理の関数で登場したポインタのポインタについて、あらためて説明しました。
C言語教室 第20回 - 双方向リスト
単方向リストの構造に戻るためのポインタを追加した双方向リストについて説明しました。ポインタの関係を図示してあります。
C言語教室 解答編 第20回 - アルゴリズムと計算量(O)
第20回の課題についての解答例を解説しています。データ構造は種類によって、どのような違いがあるのか「アルゴリズム」と「計算量」について、簡単な説明をしました。双方向リストを処理する主な関数を示しました。
C言語教室 第21回 - 循環リスト
単方向リスト、双方向リストに続き、両端のポインタを繋いでしまう循環リストと端を管理する番兵ノードの使い方について説明しています。これで実装されている C++の STL list コンテナについても簡単に触れています。
C言語教室 解答編 第21回 - と C言語あれこれ
C言語教室 第22回 - 素数を求める
C言語教室 第23回 - スタックとキュー
C言語教室 解答編 第23回 - と、AIによるプログラミング支援
C言語教室 第24回 - 関数ポインタとは
C言語教室 解答編 第24回 - と、オブジェクト指向の入り口
C言語教室 第25回 - コールバック関数
C言語教室 解答編 第25回 - と、記号の話
C言語教室 第26回 - いろいろなソート
C言語教室 解答編 第26回 - と、再帰呼出し
C言語教室 第27回 いろいろなソート(続)
C言語教室 余談2 - ソートアルゴリズムを比較してみる
C言語教室 解答編 第27回 - と、C言語の良いところ
C言語教室 第28回 いろいろなソート(続続)
C言語教室 解答編 第28回 - と、最近のソート事情
C言語教室 第29回 プログラムを走らせるまで
C言語教室 第30回 複数に分かれたソースファイル
C言語教室 第31回 インクルードって何?
C言語教室 第32回 プロトタイプ宣言とインクルードガード
C言語教室 第33回 static ってなにさ?
C言語教室 第34回 - 型修飾子あれこれ
C言語教室 第35回 constの闇 と 第34回の解答
C言語教室 第36回 論理と列挙
C言語教室 第37回 名前と予約語 と 第36回の解答
C言語教室 第38回 関数を呼ぶ手順
C言語教室 第39回 宣言文と実行文と初期化
C言語教室 最終回 お付き合いありがとうございました
今回の教室ではとりあげられませんでしたが、以下の内容についても、何らかの形でまとめておきたいとは思っています。
2種類のファイル入出力ライブラリ
エラー処理とlongjmp
オブジェクト指向
メモリ管理
ログ出力とデバッグ支援
ネットワーク
プロセスとシグナル
並行処理とスレッド
高度なファイル処理
実は他の言語についても、ほぼ同じような内容で教室をやってみて、言語による違いがわかるようにできたら面白いかもと思っています。C++であるとかC#、VisualBASICにpythonあたりを考えているのですが、既にとても良いリファレンスがありますし、誰も興味を持ってくれないかもと心配はしています。
ヘッダ画像は、以下で見つけたC言語のロゴを使ってます。
https://commons.wikimedia.org/wiki/File:The_C_Programming_Language_logo.svg
この記事が気に入ったらサポートをしてみませんか?