とらりもんHOME  Index  Search  Changes  Login

とらりもん - C言語プログラミングの体験 Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

<[[C言語入門]]に戻る>

!!最初のプログラム

 まず、C言語プログラミングを体験してみよう。Linuxでコンソールを立ち上げ、以下のプログラム(ソースコード)を、viエディターで入力・編集し、test.cというファイル名で保存せよ.

  # include <stdio.h>
  int main()
  {
  printf("Hello!\n");
  }

注: これは、Hello!と表示するだけのつまらぬプログラムである。C言語のソースコードは, .cという拡張子を持ったファイル名で作る。

注: システムによっては、下から2行目のprintfの文で, Hello!とnの間の記号が、「日本円」(Yに横棒2つ)として表示されたり、バックスラッシュ(左上から右下に延びる直線)として表示されるが、これらは計算機の中では同じ文字であり、どちらでもよい。いずれもキーボードの右上(back spaceのとなり)にあるキーを(shiftを押さずに)押せばよい。

* '''質問''': 打ち込みましたが, それぞれの意味がわかりません。includeとかintとか何なんですか?
* '''答''': 今はとりあえず, 意味はわからなくてよろしい。まず「C言語ってこういうものか」という体験をゲットし, その後で少しずつ理解していきましょう。

 保存までが終ったらこのソースコードをコンパイルしよう。それにはシェルのコマンドラインで次のコマンドを打てばよい($より後の部分を打ち込めばよい):
  コマンド01 $ gcc test.c

* '''質問''': gccってなんですか?
* '''答''': C言語のソースコードをバイナリーコード(実行可能なファイル)に変換するコマンドです。一般に, どんな言語でもソースコードをバイナリーコードに変換する機能をコンパイラーといいます。gccはC言語のコンパイラー(のひとつ)というわけです。

* '''質問''': なんか↓こんなエラーが出ました!
プログラム 'gcc' はまだインストールされていません。 次のように入力することでインストールできます:
sudo apt install gcc
* '''答''': エラーメッセージどおり, あなたのマシンにはgccが入っていないようです。エラーメッセージどおり, $ sudo apt-get install gccと打って下さい(インターネットに繋がっている必要があります)。そうすればgccがインストールされるでしょう。そうしたら, やりなおしてみよう。ていうか, エラーメッセージを読もうね。

ソースコードにミスがあると、上記のgccコマンドを実行するとエラーが出たりする。その場合は、エラーメッセージに現れる行番号を手がかりに、ソースコードを修正し、再度、上記のコマンドでコンパイルする。ミスがなくなると、メッセージなしにコンパイルが終了する。

 コマンド01が, エラーが出ずに終了したら, 出来たファイルを確認しよう。次のコマンドを打って欲しい:

  コマンド02 $ ls -lt | head

すると, 以下のように現れるだろう:

  -rwxrwxr-x 1 nasahara nasahara 8600 10月 26 06:43 a.out*
  -rw-rw-r--  1 nasahara nasahara 55 10月 26 06:42 test.c
  ....
 このコマンド02 ($ ls -lt | head)は, プログラミングで非常に有用である。これは, ファイルを新しい順に(lsの-tオプション), 作成日時やファイルサイズまで含めて(lsの-lオプション), その上位いくつかだけを表示する(headコマンド), というものである。これによって, test.cというファイルとa.outというファイルが新しくできていることがわかるし, a.outはtest.cよりも新しい, ということがわかる。

* '''質問''': 普通にlsとかls -lで確認するんじゃダメですか?
* '''答''': ダメではないけど, もし同じ場所にたくさんファイルがあったら, lsやls -lでは, 探しにくいでしょ? それに「今作ったばかりのファイル」を確認するようにすれば, 「作ったはずなのにできてない!」とか「作ったつもりのない変なファイルができてる!」などの想定外の事態に早く気づけ, トラブルの発見や解決が効率的になります。-lをつけて詳細を表示するのは, 作成日時やファイルサイズも大切な情報だからです(後でわかります)。

 このように, プログラミングではできたファイル(最新のファイル)をこまめにチェックすることが重要である。そうやって「何をしたらどうなって何ができたか」を頭の中でトレースしていくのだ。

 さて, a.outはコマンド01で作られたファイルである。gccというコマンド(コンパイラー)は, 結果(バイナリーコード)をa.outという名前のファイルにするのだ。

* '''質問''': a.outって, どういう意味ですか?
* '''答''': 私は知りません。とりあえずそういう名前でできるということを受け入れればOK。

 では, このa.outを次のコマンドで実行してみよう。
  コマンド03 $ ./a.out
すると, 以下が画面に現れるだろう。
  Hello!

* '''質問''': コマンド03の「./」ってなんですか?
* '''答''': 実行可能ファイルを実行するときは, そのパスを与えねばなりません。./は「カレントディレクトリ」ですから, 「./a.out」で「カレントディレクトリにあるa.outというファイルを実行せよ」という意味(相対パス)になります。
* '''質問''': 単に「$ a.out」じゃダメなんですか?
* '''答''': やってみてください。エラーが出ます。コマンドサーチパスに「./」が入ってないからです。詳しくはLinuxの入門書を読んでください。

!!うまくいかない場合は?
 ここまでで何かうまくいかなかった場合は, 多くの場合, どこかで打ち間違いをしている。例えばよくあるのが, ソースコードの最初の行
  # include <stdio.h>
で, 英語のstudio (スタジオ)を連想して
  # include <studio.h>
と打ってしまう間違い。stdioというのは「スタジオ」ではないのだ!

* '''質問''': ならstdioって何を意味するんですか?
* '''答''': standard input outputの略です。Linuxの入門書で学んだ「標準入出力」です。そんなの知らん!という人は, この先ヤバイので, Linuxの入門書を勉強しなおしましょう。

 間違いがどうしても見つからない場合は, 上のプログラムを君のプログラムにそっくりコピペしてみよう。それでうまくいけば, やはりソースコードのどこかで打ち間違いをしている。そこがどこなのかを調べていこう。コピペでもうまくいかなければ, それはソースコード以外の部分, 例えばコンパイルや実行のコマンドで打ち間違えているとか, そもそもgccがちゃんと君の計算機に入っていない, などの可能性がある。

注: コピペは本来, 教育上はあまり良くない。面倒でも, ひとつずつソースコードを打ち込んでいこう。コピペは楽だけど, 頭に残らないのだ。

!!プログラムと戯れる

 いったん動くものができたら, それをもとにいろいろ改造してみる(戯れる)ことが, プログラミングの上達の秘訣である。といっても, 初心者は何をすればいいのかわからないものである。そこで, 以下の課題をやってみよう。上のソースコードを改造して,

* '''課題1-1''' Hello!でなく, Good bye!と表示させてみよ。

* '''課題1-2''' Hello!に続いて, Good bye!と表示させてみよ。(ヒント: printfをもう1行, どこかに追加すればよい)

* '''課題1-3''' printf("Hello!\n");の, \nを削除して, printf("Hello!"); としてみよ。

注: 同じようなコマンドを何回も実行することになるので, シェルの履歴機能(キーボードの↑や↓で、過去に打ったのコマンドを呼び出して再利用する機能)を活用するとよい。

この3つの課題で, printfが文章を表示させる命令であり, \nは改行を表す, ということがわかっただろうか?

* '''質問''': そんなの言われなくてもわかりますよ(笑)。
* '''答''': いいですね。そうやって学んでいくのです。わざわざ「課題」として出されなくても, 自分で「ここをいじったらどうなるだろう?」とか, 「こうしたらもっと楽しいんじゃね?」と考えながら, プログラムと戯れるのです。そうするほうが, 「文章を表示するのはprintfですよ」「\nは改行を意味しますよ」などと教えてもらうよりも楽しいし頭に残るし応用も効きます。

ではもうちょっと戯れてみよう。次の課題をやって欲しい:

* '''課題1-4''' printf("Hello!\n");の, 最後にあるセミコロン(;)を削除して, printf("Hello!\n")としてみよ。

この課題1-4ではコンパイル時にエラーが出るだろう。そのエラーメッセージをよく読もう:
test.c: In function ‘main’:
test.c:5:1: error: expected ‘;’ before ‘}’ token
  }
  ^
わかりにくいメッセージだが, 強いて訳すと, 「test.cのmainというfunctionの中, 5行目の1文字目に, }という記号の前に;があるはずでは?」という意味である。つまり, ;を削ったことに関してエラーが出たのである。ここからわかるように, C言語では;を削ってはダメなようだ。

* '''質問''': こういうの嫌いです。英語のエラーメッセージって, わかりにくくてとっつきにくいです。
* '''答''': わかります。そこをちょっと我慢して, 読んで考えるようにしましょう。エラーメッセージでググってみるのもよくやる解決法です。


 ここでついでに, コマンド02と同じコマンドを再び打ってみよう:
  コマンド04 $ ls -lt | head
-rw-rw-r--  1 nishida nishida      54 10月 26 06:50 test.c
-rwxrwxr-x  1 nishida nishida    8600 10月 26 06:47 a.out*

これをコマンド02の結果と比べて欲しい。以下の違いに気付くだろうか?
* a.outがtest.cの下に現れた。
* test.cのファイルサイズが55だったのが54に変わっている。

* '''課題1-5''' これらの違いがなぜ生じたのか, 考えてみよ。

この課題は, そんなに難しくないだろう。課題1-4でセミコロンを削除したために, そのセミコロン1文字ぶん、ファイルが小さくなったのである。また, その変更のあとのコンパイルが失敗したため(エラーが出た!), a.outは作りなおされず, ちょっと前に作られた古いa.outが残っていたのだ。それがコマンド04で, test.cよりも下に(test.cよりも古いファイルとして)現れたのだ。

では, 課題1-4で起きたエラーを修正して, その後に次の課題をやって欲しい:

* '''課題1-6''' コマンド01のかわりに以下のコマンドを打ってみよ:
  コマンド05 $ gcc test.c -o test
そしてできたファイルをコマンド02で確認し, 何が起きたのかを解釈せよ。

 もうわかっただろう。'''いちいち「これをこうすうるとこうなります」みたいな説明を読むより, 自分でやってみて考えるほうが速い''', ということが。

!!C言語のソースコードの基本

 先ほど打ち込んだソースコード↓の細部を少し説明しておこう。左端の数字は行番号であり, もともとのソースコードには無いものだが, ここでは説明のために追加する。

  1. # include <stdio.h>
  2. int main()
  3. {
  4. printf("Hello!\n");
  5. }

* 1行目は, 「このプログラムでは標準入出力を使わせてください」という意味。普通のプログラムは, 何かしら入力や出力(この場合はHello!と表示)をするので, この# include <stdio.h>はほとんどのプログラムのソースコードの頭に入っている, お約束というか枕詞のようなものである。C言語のソースコードを書こうと思ったら, まずエディタを開いて# include <stdio.h>と打って, さてどうしようか, と考える感じ。

* 2行目もC言語のお約束。mainは「このプログラムの本体」という意味である(詳しく言うと, C言語のソースコードは「関数」(function)というものの集まりで構成されるが, その中で本体になる関数をmain()と言うのだが, 今はそんなこと気にしないでよい)。mainの次に()をつける理由は後でわかるので今はスルーで大丈夫。mainの前のintにも意味があるが, 今は形式的なお約束だと思っておこう。

* 3行目の{と5行目の}は対である。これらはmain()の内容を記述する範囲を表す。一般に, C言語では, {と}で挟まれた部分をひとつの固まりとして扱う。初心者はよく{と}の対応関係がずれて(例えば最後の}を付け忘れて)エラーにハマるものである。


!!もうちょっと複雑なプログラム

ではもうちょっと複雑なプログラムを体験してみよう。以下のプログラム(ソースコード)を、viエディターで入力・編集し、add.cというファイル名で保存せよ.

  /* add.c */
  /* 2017/02/18 K. Nasahara */
  # include <stdio.h>
  main()
  {
  int x, y, z;
  printf("What is x? ");
  scanf("%d", &x);
  printf("What is y? ");
  scanf("%d", &y);
  z=x+y; 
  printf("x+y= %d\n", z);
  }

 これは、2つの整数をユーザーが入力すると、その和を計算して表示するプログラムである。入力が終ったら、次のコマンドでコンパイルしよう:

(コマンド05) $ gcc add.c -o add

上の課題1-6で学んだように, gccは, -o以下に生成したいバイナリコードのファイル名を指定できる(そうするとa.outの代わりに, そのファイル名でバイナリーコードができる)。ここではaddという名前にしておく。

 コンパイルが無事に(エラーが出ずに)終了したら, $ ls -lt | head で, できたてのバイナリーコード(addというファイル)を確認しよう。それが確認できたら, 実行してみよう:

(コマンド06) $ ./add

すると、

What is x?

と聞かれるので、キーボードから、適当な整数(たとえば2)を入れてリターンキーを押す。するとまた

What is y?

と聞かれるので、同様に適当な数を入れる(たとえば8)。すると、

x+y= 10

のように、足し算の結果が表示される。

 もしうまく行かなかったら!!? ... 意に反して、プログラムがうまく走らず、止まらなくなってしまった場合は、慌てないでCTRLキー(キーボードの左下)を押しながらCのキーを押してみよう。プログラムの実行が途中で強制的に中断されてプロンプトに戻る。

 いま体験したプログラムを行番号と解説付きで再掲すると以下のようになる:

    1. /* add.c */                  // コメント
    2. /* 2017/02/18 K. Nasahara */ // コメント
    3. # include <stdio.h>          // ライブラリのヘッダーファイルの読み込み
    4.                              // 空白行。あってもなくても良い。
    5. main()                       // プログラムの本体のはじまり
    6. {                           // 14行目の}と対になって、プログラムの範囲を囲む。
    7. int x, y, z;                 // 変数x, y, zの宣言。
    8. printf("What is x? ");       // メッセージをコンソールに表示。
    9. scanf("%d", &x);             // ユーザーから変数xに値を入れてもらう。
   10. printf("What is y? ");      // メッセージをコンソールに表示。
   11. scanf("%d", &y);            // ユーザーから変数yに値を入れてもらう。
   12. z=x+y;                     // 足し算を計算し、その結果を変数zに格納する。
   13. printf("x+y= %d\n", z);     // メッセージといっしょに、変数zをコンソールに表示。
   14. }                           // プログラムの終り。

1〜2行目: /*と*/で囲まれた部分や、//で始まる部分は、人のためのコメントであり, そうなっている部分を計算機は無視する。ソースコードの頭には作成日と作製者名を入れる習慣をつけよう。以後の課題では、ここに相当する箇所を今日の日付と諸君の名前に置き換えること。

* '''質問''': コメントってことは, 書かなくても動くのですね?
* '''答''': はい, 動きます。1〜2行めを削除してコンパイル, 実行してみてください。問題なく動くでしょ?

* '''質問''': ほんとだ。なら, なぜいちいち日付と名前を書くのですか? 面倒です。
* '''答''': 真剣にプログラミングをするようになると, 骨身に染みてわかります。たくさんプログラムを書いてると, 自分が書いたものでも思い出せなくなります。日付はそれを思い出すための大事な手がかりです。また, プログラムは人にあげたり人からもらったりすることがよくあります。そういうときに作者の名前は必要です。

3行目: 先に述べた, お約束の1行である。

4行目: 空白行。空白の行が適当にソースコードに入っていても問題ない。

5行目: mainというのは、プログラムの本体部分の関数(先ほど述べた)。

6,14行目: 関数は必ず"{"で始まって、"}"で終る(先ほど述べた)。

7-13行目: プログラムの核心部。'''命令の最後は必らずセミコロン(;)で終わるのが規則'''。

7行目: x, y, zという3つの変数を宣言する。変数は宣言しないと使えない。intは(4(4バイトの)整数型の変数という意味。このように変数には整数型変数以外にもいろんなタイプがある「型」という概念がある。いずれ後で詳しく説明する

8, 10行目: コンソールにメッセージを表示する。

9, 11行目: キーボードから値を読み込む。&は変数の位置(アドレス;住所)を指定する記号。これをつけないと、きちんと変数xやyに値が入らない。

12行目: 足し算の結果を変数zに代入する。C言語ではイコール(=)記号は「等しい」という意味よりもむしろ「代入する」という機能を表す。

13行目: メッセージといっしょに、変数zをコンソールに表示する。%dは、変数の中身を表示するときの書式を表す。ここでは「10進法(decimal)整数として表せ」という意味。9行目や11行目と違って、表示のときは変数に&は不要。\nは改行の記号。


'''課題1-7'''. 上のプログラムを改造し、2つの整数のかけ算を表示するプログラムを作れ。

'''課題1-8'''. 上のプログラムを改造し、3つの整数の足し算を表示するプログラムを作れ。


!!プログラミング習得の秘訣

 既に述べたが, プログラミングの上達の秘訣は、「戯れ」である。何かを習ったら、それを利用したプログラムを戯れに作ってみる。わからなくてもいろいろ改造して試す。そういうことを繰り返し、体験的にプログラムのコツをつかんでいくこと。

 C言語には非常に多くの文法規則や機能があるが、それらを全て習得する必要はない。むしろ、少数の機能やコマンドを駆使して、自分にとって必要なプログラムを書けるようになることが大切である。ちょうど、英語の習得には多くの文法や単語をマスターするよりも、少数の単語を駆使して実践的にコミュニケーションすることが大切なのと同じである。

<[[C言語入門]]に戻る>