ワテはかなり昔にC言語を覚えた。
ポインタと言うのが出て来るが、それが理解しにくくて途中で挫折する人も多いようだ。
確かに、C言語以外の言語ではポインタは殆ど使われない。
なので Basic, JavaScript, Java, PHP, … などC以外の言語で初めてプログラミングを覚えた人にとっては、C言語のポインタというのは確かに難解だろう。
ネット上には、数多くの有名C言語サイトがるようだが、不肖ワテも、C言語入門の記事を書いてみる事にした。
それらの有名サイトを見てみると、ワテにはハードルが高過ぎるものが多い。敷居が高いと言うか、玄関のドアを開ける前に挫折するくらい難解なものもある。第一章の最初の部分から理解出来ない。
そういうサイトはワテは苦手だ。
なのでワテ自身が自分の知識を整理しながら、改めてC言語を理解し入門書を書くという感じで進めたい。
今後、時間が有る時に、ボチボチと記事を追加して行きたいと思っている。
では、本題に入ろう。
C言語入門[1/5] はじめに
前提条件
以降の説明では、前提条件として、少なくともある程度はプログラミングの知識がある人を前提としています。
理想的には、授業などで何かの言語を使って簡単なプログラムを書いた経験があると良いです。
しかし、経験が無くても、理解できるように書くつもりですので、分かり辛い所がありましたら、コメントなどでお知らせください。分かる範囲でお答えします。
なお、間違い、勘違いなど有る可能性がありますので、何かお気づきの点やご不明な点がありましたら同じくコメント欄からお知らせ頂けると有り難いです。
では、いよいよ始めましょう。
カーニハン&リッチーのhello, world
C言語の教科書として有名な
プログラミング言語C 第2版 (石田晴久 訳)
英語版 The C Programming Language (Second Edition)
(Brian W. Kernighan、Dennis M. Ritchie)
この本では、冒頭にこういうサンプルプログラムが出て来る。
#include <stdio.h> main() { printf("hello, world\n"); }
非常に有名なサンプルなので誰でも知っているだろう。
Kernighan & Ritchie を略してK&Rの hello, world
のサンプルだ。
これが hello, world の元祖であり、その後に登場した各種プログラミング言語の入門書においても、まず最初のサンプルプログラムで hello, world と出力する例が載っているのは、このオリジナルのK&Rの hello, world に由来しているのだ。
まあ、そういう歴史的な経緯はさて置き、
冒頭の #include文で stdio.h というファイルをインクルードしているが、C言語の場合、
printf(), puts() などの標準出力関数 (standard output function)
scanf(), gets() などの標準入力関数 (standard input function)
と呼ばれる関数群を使いたい場合には、とりあえずこのファイルをインクルードしておけば良い。要するに画面に何らかの文字を出力したり、あるいはキーボードなどから入力を取得したい場合に使う関数などだ。
standard input and output header files の略だと思う。たぶん。スタジオHでは無い。
なんでファイル名を不等号 <> で囲むのか?
なんで # が付くのか?
などの疑問が湧く人もいるかもしれないが、それはC言語の文法でそう書く規則になっているからだ。それ以上の深い意味は無い(と思う)。
さて、上記のサンプルなら初めてC言語を勉強し始めた人でも大体意味は推測出来るだろう。
hello, world
と画面に出力するのだ。
末尾の \n は改行を意味する文字だ。
また、行の末尾には ; が必要となるが、この形式は他の言語でも多いので馴染みやすいと思う。
これ以降の説明では、Visual Studio 2013あるいは2015を使ってCプログラムを書いています。これからC言語を学習しようと思っている人は、Visual Studioなどの開発環境をインストールすると良いでしょう。
ワテのお勧めは Visual Studio 2015 Community だ。
無料なのでお勧めしたい。
別の hello, world
最近の教科書ではこいういうサンプル(下図)のほうが多いと思う。
#include <stdio.h> int main(int argc, char *argv[]) { printf("hello, world\n"); return 0; }
* の記号はポインタを意味する。
いきなりポインタが出て来たぞ。
その説明は下のほうでやるとして、今は分かるところから見て行こう。
mainの左にあるintはmainと言う関数がint型(=整数型)の値をリターンする関数と言う意味だ。
return 0 で呼び出し元に整数の0を返しているのは、処理が正常に終わったという情報を伝えるためだ。0以外の数字を返してももちろん良いが、普通は正常終了を整数で表現するなら0を使う場合が多い(と思う)。
この場合、呼び出し元となるのは例えばWindowやLinuxのコマンドプロンプトからこのhello worldプログラムを実行すればそれらの環境に0が返る。
あるいは、C言語の中にforkと言う関数があり、プログラムを実行中に別のプログラムを起動する事が出来る。その別プログラムで処理が正常に終わったのかどうかなどの判定にこのreturnの値が使われる場合もある。
でも、Cを始めたばかりの人は今のうちはmain関数のreturnで何を返すかなどは深く考えなくても良いだろう。何か必要になった時点で考えれば良い。
次へ進もう。
mainの右にある丸カッコ内は関数の引数だ。
二つの引数がある。
一つはint型のargc。
これは分かるわ。int型(=整数型)の変数 argcだな。
二番目が問題の char *argv[] だ。
C言語を学習し始めた人の多くは、ワテも含めて、もうこの時点でビビるに違いない。
* って普通は掛け算の記号だろ?
それに argv[] って何や?
括弧の中が空ってどういう事よ?
JavaScript, PHPその他のプログラミング言語で配列を記述するなら argv[10] みたいに要素数を指定するはずだ。
要素数はゼロにしておいて、取りあえず配列を確保するための記述なのか?
さらにその頭にポインタを表す * が付いている。
でも心配ない、
あなたも **くらいではビビらなくなる。
昔のワテは、このあたりで挫折しそうになった記憶があるが、どうにか克服して今ではCやC++が使えるようになった(と思っている)。
今ではポインタの * が一個や二個くらい出て来ても動揺することは無くなった。
***ptr のように三つくらい出て来ても平気だ。
****ptr のように四つの * が付くプログラムも書いた事が有る。
*****ptr のように五つの * が必要になった事はワテの経験では、無いなあ。
このような多くのポインタが必要になる場面と言うのは、多次元配列を動的に確保する場合だ。
具体的には、malloc()関数で動的にメモリを確保して使う場面だ。これらについては、別の記事で紹介したい。
以下では、* と ** の場合までを理解する。
つまりポインタの記号*が一個や二個出て来てもビビらなくなるのだ。
それが出来ればC言語のポインタの5割くらいは理解したと思っても良いと思う(ワテの勝手な推測に基づく)。
int main(int argc, char *argv[])の解釈
さて、余談はさて置き、C言語の学習を始めた人が最初に遭遇する鬼門である
int main(int argc, char *argv[])
の部分のであるが、それらの意味を説明すると、
まず、C言語の実行プログラムではmainと言う名前の関数が必ず一個必要となる。
そのmain関数は二つの引数を取る。
argcはプログラムに与えられた引数の数、
argvはその引数文字列を保持する配列、
なのだ。
コマンドプロンプトを開いておいて、プログラムに三つの引数を与えて実行する場合に、例えばWindowsの場合なら、
C:\> プログラム.exe 引数1 引数2 引数3 [ENTER]
のようになるが、argv配列には与えられた引数の文字列が入るので、それをmain関数中で利用する事が可能になる。
なお、上記のK&Rの例では単にhello, worldを出力するだけの処理なので、もしそれらの引数が与えられたとしても関数内では利用していない。
なので最初の例のようにmain()と言う形で省略しても良いのだ。
あるいは、関数の引数も戻り値も存在しない事を明示的に示したいなら
void main(void)
と書いても良い。まあ、この辺りは理解し易いだろう。
ちなみに、
int main(int a, char *b[])
でも良い。
つまりmainと言う関数は引数を二つ取るという決まりがあるだけなので、引数の名前は自由に変えても良い。
まあ、でも、カーニハンさんとリッチーさんに敬意を表してK&Rの教科書に出てきたargc, argvを使うのが良いだろう。
また、引数が三つの形式も有る。
int main(int argc, char *argv[], char *envp[])
三番目の引数で実行環境の環境変数が取得出来るのだ。まあこの辺りはOSによって得られる情報が異なると思うので各自で調査して頂きたい。
さらに別の hello, world
いろんな本を見ていると、さらに別のhello, worldのサンプルを見た事がある人も多いと思う。
それがこれだ。
#include <stdio.h> int main(int argc, char **argv) { printf("hello, world\n"); return 0; }
*argv[] ですら良く分からんのに、それが勝手に **argvに変わり、
いきなりポインタ ** が2個も出てきたがな。
初めてこの記述を見たワテの感想は、
「 * が二個。全く理解できない。」
だ。
ポインタ1個でも分からないのに2個も出てきたら、もう訳分からんと言う人が殆どだろう。
ワテもこの辺りの正確な意味を理解するのに数年掛かった。
最初は分からなくてもあまり気にせずにCプログラムを書いてみる事が重要だ。
そのうちに分かってくると思う。
**の意味が全く分からなくてもプログラムに与えらえた引数を読み出すなら、以下のようにすれば良い。
int main(int argc, char *argv[]) // char **argv) でも良い { for (int i = 0; i < argc; i++) { printf("->%s<-\n", argv[i]); } return 0; }
例えばこのプログラムをコンパイルしてリンクして実行プログラムの名前が main.exe だとすると、コマンドプロンプトを表示しておいて、
main.exe 引数1 引数2 引数3 [ENTER]
のように実行すれば、forループとprintf文によってそれらが順番に出力出来る。
実行結果
->main.exe<- ->引数1<- ->引数2<- ->引数3<-
この場合、引数が3個でもargc=4となり、一個多い理由は “main.exe” というプログラムの名前自身もargvという配列に保管されるからだ。
さて、ポインタを理解するためにもう少し詳しく見てみよう。
続く
初学生がポインタを使いこなしているのか。
コメント