0. 目次
1. はじめに
この記事は,PythonやJavaScript等の基礎を理解しているけれども,Cについてはまったく知らない人に向けた教科書的な記事である.そのため,プログラミングそのものを基礎から学びたい人は他の記事を参照すべきである.また,Cについてのある程度の知識がある人にとっては物足りないものとなるだろう.
また,筆者は本記事が初投稿であるため,至らない点があると思われる.できる限り正確な情報を伝えられるように注意を払っているが,解釈の誤り等が含まれている可能性もある.その点は読者諸君に了承いただきたい.
なお,本記事は「MYJLab Advent Calendar 2021」13日目の記事である.12日目の記事のトピックは,@Kakki78氏のReactによる管理画面の作成についてであった.興味があれば,アドベントカレンダーの他の記事も閲覧していただきたい.
2. Cとは
2.1. Cとは
Cとは,1972年にアメリカ合衆国・ベル研究所の計算機科学者デニス・M・リッチー (Dennis M. Ritchie) が開発した手続き型言語である.正式名称は「C」だが,アルファベット1文字ではわかりにくいため,「C言語」という通称で呼ばれることが多い.
ここで手続き型言語とは,アルゴリズムの記述を主体とする言語を指す.他の手続き型の例としては事務処理に適したCOBOLや科学技術計算に適したFortran,Fortranをベースにした初心者向けの言語であるBASIC,テキスト処理やCGI (Common Gateway Interface) の開発に適したPerl,さらには近年注目度が高まっている汎用向け言語のPythonなどが挙げられる.
2.2. Cの歴史
1960年代初頭,極めて初期のプログラミング言語であるCPL (Combined Programming Language) が開発されると,1960年代中期にはマーティン・リチャーズ (Martin Richards) によってその簡易版であるBCPL (Basic Combined Programming Language) が開発された.
続けてリッチーと同じくベル研究所所属のケン・トンプソン (Ken Thompson) によってBが開発されると,その改良版であるnew Bを経てCが誕生した.
補足: BとCの名前の由来
「B」という名称の由来としては,BCPLの頭文字を取ったとする説や,トンプソンがBより以前に開発した言語であるBonから取ったとする説がある.さらには,Bonの名前の由来でもあるトンプソンの妻・ボニー (Bonnie) が由来であるとも言われている.
また「C」という名称の由来としては,アルファベットのBの次にくる文字である「C」から取ったとする説や,「BCPL」という文字列においてBの次にくる文字である「C」から取ったとする説がある.いずれにせよ,「CはBに次ぐ言語である」という意味から名付けられたことは確かといえるだろう.
2.3. Cの標準化
Cは,もともとUNIXの移植のために開発されたシステム記述言語であった.その汎用性の高さから,次第に大型のコンピュータから小型の組み込みシステムまで,あらゆるコンピュータシステムに普及していった.
この流れに連れて,ブライアン・W・カーニハン (Brian W. Kernighan) とデニス・M・リッチーの著作である『K&R』の巻末に記載されていた参照マニュアルが,Cの標準的な仕様とみなされるようになっていった.
しかし,『K&R』に記されていた仕様には曖昧な部分が多く,それぞれの開発現場において独自の「方言」(dialect) が用いられる事態が発生した.これは,C本来の汎用性が高いという特性を活用できなくなることを意味する.
この問題を受け,多くの標準化団体によってCの標準化が推し進められた.1989年には米国国会規格協会 (ANSI) が,続く1990年には国際標準化機構および国際電気標準会議 (ISO/IEC) がCの標準化を行った.また1993年には日本工業規格 (現: 日本産業規格; JIS) としてCの標準化が規定され,1999年にはISO/IECの標準化規格が改訂された.
3. コンパイル
3.1. コンパイルとは
コンパイル (Compile) とは,高水準言語によって記述されたソースプログラムを一括に低水準言語である機械語へ翻訳することである.また,コンパイルを実行するソフトウェアをコンパイラ (Compiler) という.なお,反対にソースコードを一行ずつ逐次解釈していくソフトウェアをインタプリタ (Interpreter) という.
ところで,Cで記述されたプログラムはコンパイルを行ってから実行することが一般的である.Cにもインタプリタ式の環境は存在するが,Cの利点である速度が犠牲になってしまうため,ほとんど使用されることはない.
3.2. コンパイルの仕組み
コンパイルは,以下の3つの過程から構成される.
- プリプロセス
- コンパイル
- リンク
ここからわかるように,「コンパイル」という言葉はソースコードの翻訳における一連の処理を指す場合もあれば,その内の2番目の処理を示す場合もあるので注意が必要である.以降は,これら3つの過程について順に説明する.
プリプロセス
プリプロセス (Preprocess) とは,「前に」を意味する接頭辞 "pre-" と「過程」「処理」などを意味する "process" が指し示す通り,「前処理」のことである.プリプロセスは,ソースプログラムを整形してコンピュータが解釈しやすくする役割を持つ.
Cおよびその派生系であるC++では,#include
や #define
といったプリプロセッサディレクティブ (Preprocessor Directive) によって前処理の内容を直接記述することができる.
コンパイル
コンパイル (Compile) は,本来は「出処がさまざまな文章や資料をかき集めて1つの書物にまとめる」という意味の言葉であり,直訳すると「編纂する」「編集する」となる.コンパイルでは,以下のようにして目的プログラム (オブジェクトプログラム) を生成する.
- 字句解析
- ソースコードを変数名や定数,予約名,記号などのトークン (Token) と呼ばれる最小単位に分解する
- 構文解析
- トークンから構文木を生成し,プログラムが文法的に正しいかどうかをチェックする
- 意味解析
- プログラムに意味的な誤りが含まれていないかをチェックする
-
最適化
- 無駄な処理を取り除き,プログラムサイズや処理時間の最小化を行う
- コード生成
- 目的プログラムへの変換を実行する
リンク
リンク (Link) とは,「つなげる」「結合する」といった意味が示すように,前述のコンパイルによって生成された複数の目的プログラムを組み合わせることである.リンクを実行するプログラムをリンケージエディタ (Linkage Editor; 連係編集プログラム) またはリンカ (Linker) という.
そして,リンクによって完成する最終的なプログラムを実行可能ファイル (Executable File; 実行ファイル) という.また,プリプロセスから実行可能ファイルの生成までの一連の流れをビルド (Build) と呼ぶこともある.
3.3. Cのコンパイラ
Cのコンパイラのうち,代表的なものとしてはまずGCC (GNU Compiler Collection) が挙げられる.UNIX系OSに関連するフリーソフトウェアの開発・配布を行うGNUというプロジェクトにより公開されたコンパイラである.
かつてはGNU C Compilerという名称でCやC++のみに対応していたが,次第にJavaやFortranなどの多くの言語をサポートするようになった.
もうひとつの主要なコンパイラとしては,Appleが開発したClangがある.GCCと比較して高速なコンパイルを行うことができるだけでなく,メモリの消費量も少ない.さらに,ClangはGCCとの互換性が高く,GCCの拡張機能にも対応している.
こうしたClangの高性能な特徴から,以降のプログラムの演習ではClangによるコンパイルの方法を紹介することとする.
4. Cの基礎
4.1. 事前準備
Clangのインストール
まず,CのコンパイラであるClangのインストールを実行する.ここでは詳しいインストール方法の説明を省略する.その代わりに,参考になるWebサイトを以下に提示する.
-
Windows:
- ページ後半の「2. Clangを使う」を参照する
- 個人用Windowsでのプログラミング環境構築
-
Mac OS:
エディタの準備
Visual Studio Codeによるエディタの準備方法は,以下の通りである.
- Visual Studio Codeを起動する
- 任意のディレクトリに移動する
- ターミナルを起動する
-
clang --version
コマンドでコンパイラが正常にインストールされているかを確認する - 拡張子
.c
のファイルを作成する (ファイル名は任意)
なお,この記事では,エディタとしてVisual Studio Codeを使用することを前提としている.ただし,コマンドラインが実行できる環境であればどのエディタでも実行可能であると思われるので,細かい点は各自で読み替えていただきたい.
4.2. Hello, world
まずは定番の "Hello, world" を実行する.以下のプログラムを記述する.Cのプログラムの雰囲気を味わうためにも,できればコピー&ペーストではなく,いわゆる「写経」を行うことを推奨する.
なおファイル名は自由であるが,ここでは説明の都合上 hello.c
とする.
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
プログラムの実行
以下の手順に従ってソースプログラムをコンパイルし,それを実行する.
-
clang hello.c
コマンドでコンパイルを行う - 実行可能ファイル
a.out
の生成を確認する
(Windowsではa.exe
というファイル名になる) -
./a.out
または./a.exe
と入力し,プログラムを実行する - 文字列 "Hello, world!" の出力を確認する
記述するまでもないかもしれないが,出力は次のようになる.
Hello, world!
ところで,上記の方法ではソースプログラムのファイル名にかかわらず,実行可能ファイル名は a.out
になる.これは明らかに不便であるので,実行可能ファイル名を指定してコンパイルする方法を紹介する.
-
clang -o hello hello.c
コマンドでコンパイルを行う - 実行可能ファイル
hello
の生成を確認する
(Windowsではhello.exe
というファイル名になる) -
./hello
または./hello.exe
と入力し,プログラムを実行する - 文字列 "Hello, world!" の出力を確認する
出力は当然,上記とまったく同じになる.
Hello, world!
なお,hello.c
以外のファイル名のコンパイルを行う場合には,上記の手順における hello
や hello.c
を適宜置き換えるだけでよい.
プログラムの解説
まず,1行目はプリプロセッサディレクティブである.#include
はヘッダファイルを読み込む擬似命令であり,ヘッダファイル stdio.h
は標準入出力 (Standard Input/Output) のためのモジュールである.
続く3行目以降では,関数 main()
を定義している.main関数は必須であり,プログラム実行時に最初に呼び出される.また,main関数の返り値の型は整数型intにする必要がある.つまり,void main(void) {}
などは許容されない.
4行目は,stdio.h
に含まれる関数である printf()
を用いて "Hello, world!" の出力を行っている.printf関数は書式付き文字列を標準出力する関数である.ちなみに,関数名の "f" は書式 (format) の意味である.なお,Pythonのprint関数のようにデフォルトで改行されないため,改行コード \n
を文字列の末尾に置く必要がある.
5行目では,return文でint型の数値0を返している.これは,「main関数の返り値は0にする」という規則があるからである.このような決まりごとがある理由は,返り値0がプログラムの正常終了を意味するからである.
補足: 正常終了と異常終了
正常終了と異常終了の意味合いを,コマンドラインで体感する.補足ではあるけれども,重要な要素を含んでいる.
まず,ターミナルで ./hello && ls
(Windowsのコマンドプロンプトでは ./ hello.exe && dir
) というコマンドを入力する.その結果として,"Hello, world!" の出力に続けてカレントディレクトリ内のファイルやフォルダの一覧が表示される.実は,これで正常終了が確認できている.
続いて,プログラム hello.c
ののmain関数の返り値を0以外の整数値に変えてからコンパイルする.そして再び ./hello && ls
( ./ hello.exe && dir
) を入力すると,"Hello, world!" だけが出力される.やや不可解に思われるかもしれないが,これで異常終了の確認ができている.
さて,なぜこのような動作になるのかを説明する.上記のコマンドにおいて重要な点は,&&
である.&&
は,「左側のコマンドと右側のコマンドの両方を実行する」と考える読者が多いかもしれない.実際のところ,初心者である筆者もその1人であった.しかし,実際は「左側のコマンドが正常に終了したときに右側のコマンドを実行する」という意味を表す.
したがってこの例では,main関数の返り値が正常終了を意味する0となっている前者の場合のみ,左側のコマンド ./hello
( ./hello.exe
) に続けて右側のコマンドである ls
( dir
) が発火する.それに対して,main関数の返り値が0ではない後者の場合,左側のコマンド ./hello
( ./hello.exe
) が実行されても,それが正常に終了したとはみなされない.そのため,右側のコマンド ls
( dir
) は実行されなくなるのである.
4.3. 入出力プログラム
引き続き,定番の入出力プログラムを実行する.以下のプログラムを記述し,任意のファイル名を指定してコンパイルする.
#include <stdio.h>
#include <string.h>
int main(void) {
printf("Input your name: ");
char name[32];
scanf("%s", name);
int length = strlen(name);
printf("Your name is %s./n", name);
printf("Name length: %d/n", length);
return 0;
}
このプログラムを実行すると,次のような表示とともにキーボードによる入力を要求されるので,任意の名前を「スペースなしの半角英数字」で入力する.
Input your name:
例えば "Sephiroth" と入力すると,以下のようにして名前とその文字数が出力される.
Input your name: Sephiroth
Your name is Sephiroth.
Name length: 9
プログラムの解説
まず,2行目では新たなヘッダファイル string.h
を読み込んでいる.これは文字列を扱うための関数群からなるモジュールである.
6行目では,文字列を格納するための変数を文字型charの配列として宣言している.name[32]
とあることから,配列の要素数は32である.すなわち,文字列 name[]
は半角英数字32文字まで扱える.
7行目は,stdio.h
内の標準入力のための関数 scanf()
を用いている.第1引数の %s
は入力変換指定子である.これは,入力した値をどのような値として扱うかを示すためのものである.%s
は,入力値を文字列として扱うことを意味する.
なお,scanf関数は半角スペースを入力することができないという問題がある.さらに,詳細は省略するが,この関数にはそれ以外にも多くの欠陥がある.そのため,今回のような学習などの目的を除いて,一般的にscanf関数を使うことは非推奨である.少なくとも実務で使用されることは絶対にないといってよい.
続く8行目では,string.h
に含まれる関数である strlen()
が用いられている.この関数は,基本的な半角文字の長さを返す.ただし,全角文字は3文字分として扱われる.そのため,今回の例において名前を「セフィロス」という日本語で入力すると,15文字として出力される.
他にも,フランス語におけるアクセント付きの文字 "é" や合字 "œ" などは2文字分として扱われたり,中国語で用いられる漢字は日本語と同様に3文字分として扱われたりする.このような現象が起きる理由については,後述のプログラムの解説とともに説明することとする.
そして9行目と10行目の文字列内には,%s
や %d
といった出力変換指定子が記述されている.これは入力変換指定子と同様に,出力する値をどのような値として出力するかを指定するものである.%s
と %d
は,それぞれ文字列と整数に対応している.ちなみに,浮動小数点数に対応する出力変換指定子は %f
である.しかし,入力変換指定子は %lf
である.
5. ポインタ型
5.1. Cの主なデータ型
本記事の最も重要な項目の解説に入る前に,Cの主なデータ型について以下のリストで確認する.
- void
- 引数や戻り値がないことを示す型
- 整数型 int
- ブーリアン (false, true) はそれぞれ整数0, 1で表現する
- 単精度浮動小数点数型 float
- 32ビットで表される小数
- 倍精度浮動小数点数型 double
- 64ビットで表される小数
- 文字型 char
- C言語には文字列型が存在しないため,文字列は文字型の配列として扱う
- 配列
- 複数の同じ型の変数をまとめて扱う型
- 構造体
- 複数の異なる型の変数をまとめて扱う型
- ファイルを扱うための型であるFILEは,構造体である
- ポインタ型
- 次節以降,詳しく説明する
5.2. ポインタ型
ポインタ型とは,変数のメモリ上の格納場所を示す特殊な型である.格納場所は16進数のアドレスで表される.
ポインタ型を使用することで,ある変数 x
に別の変数 y
のコピーではなく,変数 y
のアドレスを渡すことができる.このとき,x
の値を書き換えると,参照元の変数である y
の値も書き換えられることになる.これは,単なる値の代入 x = y
が示す挙動とは大きく異なる.
さて,このように説明したけれども,おそらく混乱する読者がほとんどであろう.ポインタ型は,実際にプログラムを書かなければその本質を理解することが難しい概念である.
5.3. 変数のアドレスを見る
まずは変数のアドレスを確認するために,以下のソースコードをコンパイルし,実行する.
#include <stdio.h>
int main(void) {
int x = 10;
int nums[5] = {5, 15, 25, 35, 45};
printf("address of var x: %p\n", &x);
for (int i = 0; i < 5; i++) {
printf("[%d] %p\n", i, &nums[i]);
}
return 0;
}
このプログラムの実行結果は次のようになる.なお,環境によってアドレスの数値は異なる.
address of var x: 0x7ff7b794d478
[0] 0x7ff7b794d480
[1] 0x7ff7b794d484
[2] 0x7ff7b794d488
[3] 0x7ff7b794d48c
[4] 0x7ff7b794d490
プログラムの解説
5行目では,配列 nums[]
を新しく宣言しつつ,初期化を行っている.注意すべき点は,初期化にはブラケット []
(bracket; 角括弧) ではなくブレース {}
(brace; 波括弧) を用いることである.
6行目では,変数 x
のアドレスを標準出力している.第2引数には, x
の前に変数のアドレスを求めるための演算子 &
がついている.なお,ポインタ値 (アドレス) に対応する出力変換指定子は %p
である.
また7行目から8行目までのfor文では,配列 nums[]
の各要素にそれぞれ対応するアドレスを出力している.実際の出力結果を眺めてみると,実行環境によらず,アドレス値が4ずつ増えていることがわかる.これは,1個の整数型intの変数がメモリ中の4バイトを消費するからである.このことから,要素数5の配列 nums[]
の全体の消費バイト量は 4 * 5 = 20
であることがわかる.
ちなみに,これと同様の考え方を用いて上述のプログラムにおけるstrlen関数の奇妙な現象を説明できる.実は,strlen関数は正確には文字列のバイト長を返す変数である.char型において,ASCIIに対応する基本的な半角英数字や半角記号はすべて1バイト分を消費する.そのため,"Sephiroth"という半角英字9文字からなる名前を入力すると,9バイト,すなわち9文字であると正しく出力される.しかし,"é" や "œ" といった符号付きの文字や合字は2バイト分,日本語や中国語などの全角文字は3バイト分を消費する.したがって,"セフィロス" という全角文字5文字からなる名前を入力すると,15バイト,つまり15文字として出力されることになる.
補足: 配列の要素数を求める方法
上記のプログラムの7行目では, nums[]
の要素数である5をそのまま入力している.これでは配列の長さを変えたときに値を逐一書き換える必要が出てくるため,保守性に欠けてしまう.そのため,JavaScriptの .length
やPythonの len()
のような,配列の要素数を求めるメソッドや関数を使用したくなる.しかし,Cにはこれに相当するものは存在しない.
そのため,変数の消費バイト量を求める演算子 sizeof
を用いて, sizeof(nums) / sizeof(nums[0])
または sizeof nums / sizeof nums[0]
とする.この式では,「配列全体の消費バイト量」を「配列の要素1個分の消費バイト量」で割ることで要素数を得ている.今回の例では 20 / 4
となるから,配列の長さ5が求まる.
5.4. ポインタ型を体感する
アドレスについて確かめた後は,ポインタ型を体感する.そのために,以下のソースプログラムをコンパイルして実行する.
#include <stdio.h>
int main(void) {
int x = 10;
int y = x;
int *z = &x;
y = y * 2;
printf("x: %d, y: %d n", x, y);
*z = *z * 2;
printf("x: %d, z: %d n", x, *z);
return 0;
}
出力結果は以下の通りである.
x: 10, y: 20
x: 20, z: 20
このプログラムでは,初期値10の変数 x
はどの行においても2倍されていないように見える.しかしながら,ポインタ変数 (ポインタ型の変数) z
によって,x
の値が20に書き換えられている.
プログラムの解説
まず,4行目では変数 x
に整数値10を代入している.
続く5行目では,変数 y
に変数 x
が示す値10を渡している.
また6行目では,変数名の前にアスタリスク *
をつけてポインタ変数 z
を宣言し,さらに変数 x
のアドレス値 &x
を渡している.
7行目において,変数 y = 10
に2を掛けている.このとき,当然ながら,コピー元の変数である x = 10
には何の影響も与えない.
よって,8行目では変数 x
は初期値10として出力され,変数 y
は 10 * 2 = 20
として出力される.
さらに9行目では,x
のアドレスを指し示すポインタ変数 z
に間接参照演算子 *
をつけることで,z
の通常の変数と同じように扱っている.このとき,ポインタ値 z = &x
をたどって x
が参照されるため,*z
は変数 x
と同等となる.したがって *z
に2を掛けると,変数 x = 10
も2倍されることになる.
その結果,10行目では *z
は 10 * 2 = 20
として出力され,参照元の変数 x
も 10 * 2 = 20
として出力される.これが x
に直接触れることなく,さながら魔法のごとく x
の値を書き換えることができる理由である.
なお,今回のプログラムでは整数型intへのポインタ型を取り上げた.しかし,実際にはどんな型に対してもポインタ変数を宣言できる.さらには,ポインタ型へのポインタ型という多重ポインタ型を作成することもできる.
5.5. ポインタ型の罠
ところで,前述のプログラムにはポインタ型の罠ともいえる要素をすべて仕込んでいる.その罠とは,記号アスタリスク *
である.以下の3つの *
は,すべてまったく異なる意味をもつ記号である.
- 乗算演算子
*
- 掛け算の記号
-
n = n * 3;
など
- ポインタ変数を宣言する記号
*
-
int *p = &n;
など -
int* p = &n;
も同じ意味である - 複数のポインタ変数を1行で宣言する場合は,
int *p1, *p2;
とする -
int* p1, p2;
とすると,p1
がポインタ型,p2
が普通のint型になる
-
- 間接参照演算子
*
- ポインタ変数を通常の変数と同等に扱うための記号
-
*p = *p + n;
など
同じ記号に違う意味をもたせることは,プログラマーに混乱を与えかねない.したがって,アスタリスク *
はCの欠陥の1つである.しかし,この点は今さらどうしようもないので,これらを意識的に区別して使用しなければならない.
6. まとめ
最後に,本記事のまとめである.
- CはUNIXの移植のために作られた「私的」な言語である
- scanf関数やアスタリスク
*
など,明らかな欠陥が多い - 記述量が多くて煩雑だが,それを上回るほど汎用性に優れている
- scanf関数やアスタリスク
- コンパイルの仕組み
- プリプロセス,コンパイル,リンク
- 実行可能ファイルの生成 (ビルド)
- Cの基礎文法
- for文や関数などの基本構造は,他の言語と大差ない
- プリプロセッサディレクティブ (疑似命令)
- 入力変換指定子,出力変換指定子
- 演算子
&
およびsizeof
- main関数の返り値は0にする
- 文字列型は存在しない
- ポインタ型
- 理解が容易ではない
- アスタリスク
*
には要注意 - メモリを意識したコンピューティングが可能になる
- 複雑だが,低水準言語に近い記述が可能になる
- コンピュータの仕組みを実感できるため,学習に向いている
Cは,総じて面倒な言語である.しかし面倒であるがゆえに,そこには「何でもできる」という強烈な魅力がある.
7. おわりに
以上でプログラミング言語Cおよびその基礎の解説は終わりとなる.やや堅苦しくて読みにくい点も多かったであろうが,Cの魅力が伝わったならば幸いである.この記事を読んでCは難しい,わかりにくいと感じたならば,それはむしろ好機である.自ら手を動かして理解をより深めてみてほしい.しかし何を言っているのかさっぱり理解できないという場合には,プログラミングそのものの基礎に今一度立ち返ってみることを推奨する.逆にこの内容を容易に把握できたならば,それは素晴らしいことである.決して驕ることなく,さらなる高みを目指すべきである.
ところで,Cの文法について特筆すべき事項はまだ多く残っている.しかし,それをすべて記載すると記事として長くなりすぎてしまい,読者を退屈にしかねない.よって,さらなる追加事項についてはまた別の機会に紹介したい.
それでは,アドベントカレンダーのバトンを14日目の@Kuroi_Cc氏に渡して本記事の締めくくりとする.数ある記事のうち,拙著を読んでくれた読者諸君に感謝申し上げる.
流れゆく時に身をまかせて,
@linked34ce
参考文献
- 月江 伸弘「徹底攻略 基本情報技術者教科書 令和3年度」インプレス,2020年
- 森 孝夫「C言語の始まりを知っていますか?」Interface,2010年
- BohYoh.com「C言語の歴史」柴田望洋後援会,言語科学研究所
- Dennis M. Ritchie「The Development of the C Language*」Bell Labs/Lucent Technologies
- 通信用語の基礎知識「B」
- C言語「C言語とは」
- Programming Place Plus (参照ページ多数)
- 守屋 悦朗 「プログラミング言語総論」早稲田大学,2006年
- IT用語辞典バイナリ「GCC」
- 通信用語の基礎知識「clang」
- 寺尾 敦「個人用Windowsでのプログラミング環境構築」東京大学
- 知能計測制御研究グループ「情報処理基礎・プログラミング演習」兵庫県立大学
- 須﨑 純一「基本事項:プログラムの構成、コンパイル、実行」京都大学
- 苦しんで覚えるC言語 (参照ページ多数)
- 旅の記録「stdio.h の意味と読み方」
- C++で開発「ヘッダファイルとは」
- 床井 浩平「補足:終了ステータスについて」和歌山大学
- はてなブログ ささやかな日々記「PowerShell フォルダ・ファイル一覧の参照について」