Unix C プログラミング入門資料(高崎金久)   2.はじめてのCプログラミング 目次 1.C言語によるプログラミングの概要 2.文字列を出力するプログラム 3.プログラムの解説 4.文字列を入力するプログラム 5.対話的なプログラム ---------------------------------------------------------------------- 1.C言語によるプログラミングの概要 C言語によるプログラミングから実行までの手順は大筋で次のようになります. (1)エディターでC言語によるプログラム(ソースプログラムという)をつくる. (2)ソースプログラムをCコンパイラで処理する.コンパイラはソースプログラ ムを解析して,さまざまなチェックを行う.この段階でエラーを見つけると,その 旨を表示する(コンパイルエラー).エラーが出たら,(1)へもどってソースプ ログラムを書き直す.コンパイルエラーがなくなるまでこれを繰り返す. (3)コンパイルエラーがなければ,コンパイラはソースプログラムを機械語プロ グラムに変換してファイルに書き出す. (4)できた機械語プログラム(普通はコンパイラが気を利かせて実行可能モード にしてある)をテストする.具合がおかしければまた(1)にもどってソースプロ グラムからつくり直す.問題がなければでき上がり.通常のコマンドと同様シェル から呼び出せる. このように,インタープリタ系の言語のプログラミングと違って,C言語のプログ ラミングではいろいろな道具が関与します.この演習ではデバッガーの使い方に立 ち入る余裕はありませんので,おもな道具はエディターとコンパイラです.コンパ イラにはシステム固有のもの(cc)とGNUのCコンパイラ(gcc)の2種類が用意 されていますが,この演習では後者を使います. 具体的な手順はこのあと簡単な例で説明して行きます. 2.文字列を出力するプログラムの例 KRの本に最初に出てくるのは有名な「Hello, world!」のプログラムです.これは 実行すると画面に「Hello, world!」という文を表示するだけのプログラムです.こ こではもう少し凝って, *** *** * * * * * * * * * * * * * * * * * * * * o o * * ^ * * --- * * * * Hello! My name is Peter. という絵文字を表示するプログラムをつくってみましょう. 1)エディターでソースファイルをつくる エディターで次のような内容のファイルを作ります.ファイル名は「hello.c」と します.(最後の拡張子.c を忘れずにつけて下さい.)なお各行最初の「1:」な どは後でプログラムの解説をするときのため付けた行番号です.実際のプログラム に書き込んではいけません. 1:/* my first C program */ 2: 3:#include 4: 5:void main(void) 6:{ 7: printf(" \n"); 8: printf(" *** *** \n"); 9: printf(" * * * * \n"); 10: printf(" * * * * \n"); 11: printf(" * * * * \n"); 12: printf(" * * * * * \n"); 13: printf(" * * \n"); 14: printf(" * o o * \n"); 15: printf(" * ^ * \n"); 16: printf(" * --- * \n"); 17: printf(" * * * \n"); 18: printf(" \n"); 19: printf(" Hello! My name is Peter.\n"); 20:} セミコロン「;」を忘れてはいけません.C言語ではセミコロンはプログラムの文 の終わりを示します. 2)gcc でコンパイルする 端末ウィンドウにカーソルを移し,次のように入力して gcc を起動します. [gccの起動例] gcc hello.c -o hello コンパイルが始まり,ソースファイルにタイプミスなどがなければなにやらうまく 行ったらしい旨のメッセージ(全部英語)が表示されます.エラーがあれば,訳の わからないエラーメッセージ(全部英語)が表示されます. gcc に渡したパラメータの意味を説明しておきます.最初のhello.c はもちろんソ ースファイルです.コンパイラに渡すのはこのようにソースファイルです. 「-o hello」はコンパイルがうまく行ったらできた機械語プログラムのファイルに 「hello」という名前をつけよ,という指示です. [gcc のオプション] -o ファイル名  機械語プログラムファイルに名前をつける この指示がないときには a.out という名前の機械語プログラムができます. 3)実行してみる できた機械語プログラムファイルの保護モードは実行可能に設定されているはずで す.次のようにファイル名に「./」を付けてコマンドとして入力してみてください. [機械語プログラム名が「hello」の場合] ./hello [機械語プログラム名が「a.out」の場合] ./a.out 最初に示したようなメッセージが表示されるはずです.なお,環境設定を変更すれば 「./」を付けなくても実行できるように環境設定することもできますが,安全上問題 があります. 3.プログラムの解説 上のプログラムについて簡単に解説しておきます.もう少し先へ進まないと理解し にくい点も多いので,以下の説明によくわからない点があっても今はあまり気にす る必要はありません. 1行目はコメントです.C言語では /* */ で囲んだ部分がコメントとしてコンパ イラーには無視されます.コメントは複数行にわたっても構いません. 2行目と4行目は空行です.7行目の最初の数文字はスペース(あるいはタブ)で す.これらはプログラムを見やすくするために入れてあります.このように,C言 語ではプログラムの書き方がかなり自由です.ただし,3行目にあるような # は 1桁目に書かなけばなりません. 3行目はあとで printf という出力コマンド(正確には関数)を使うためのおまじ ないです.これはシステムに用意されている「stdio.h」というファイル(一種の Cプログラム)を読み込むことを指示するものです. 5行目以降がプログラムの本体で,ここでは main(メイン)という関数を定義して います.main 函数は処理の主要部分(メインルーチン)を記述したものです.処理 が複雑になれば細部(サブルーチン)を別の函数に記述するのですが,このプログ ラムは簡単なので main 函数だけから構成されています. 画面への出力を受け持っているのは printf(...) というコマンド(函数)です.こ の函数は書式付き出力函数と呼ばれるもので,C言語処理系のライブラリに用意さ れていて,プログラムの中からこのように呼び出して使うことができます.3行目 のおまじないはこのために必要なものです. 書式付き出力函数はさまざまな機能をもっていますが,ここではあらかじめ指定さ れた文字列を出力するという最も簡単な使い方をしています.KRの本の例 printf("Hello, world!\n"); は Hello, workld! という文字列を出力して改行する(最後の \n は改行を意味す る特殊文字列です)もので,我々の例はただこれを繰り返すだけです. なお,改行文字列は実際には何個でも挿入できます.また(Unix の上の)Cコン パイラはプログラム中の \ で終わる行を「行が続いている」と解釈します.この ことを利用すると,我々のプログラムの出力部分は次のようにprintf を1回だけ 呼び出す簡潔な形に書き直せます. [書き直した形] printf("\ \n\ *** *** \n\ * * * * \n\ * * * * \n\ * * * * \n\ * * * * * \n\ * * \n\ * o o * \n\ * ^ * \n\ * --- * \n\ * * * \n\ \n\ Hello! My name is Peter.\n"); 4.文字列を入力するプログラム 今度はキーボードからデータを入力してそれを出力に利用することを考えましょう. キーボードからの入力を処理するためには新たに 1)入力を行うコマンド(函数) 2)入力したデータ(文字列)を保存するための入れ物(変数) が必要になります.キーボードから文字列を入力するための函数はいくつかありま すが,ここでは「fgets」という函数を使うことにします.以前はこの函数よりも 簡単な「gets]という函数が用いられることがありましたが,gets には安全上の 問題(セキュリティホール)があり,今では用いられません. 次の簡単なプログラムで考え方を説明します. 1:#include 2: 3:void main(void) 4:{ 5: char buffer[60]; 6: printf("Please enter your name: "); 7: fgets(buffer,60,stdin); 8: printf("Thank you, %s. Wait a momement please.\n", buffer); 9:} プログラムの意味を説明します. 1行目:これは printf と gets をライブラリから呼び出すためのおまじないです. 5行目:これは「buffer」という名前の変数を宣言しています.「宣言」により, メモリーの上に実際にデータを格納する領域を確保され,そこに「名前」(上の例 では「buffer」)が付けられます.変数の宣言では変数「型」(type)も指定しな ければなりません.上の例では buffer という変数を長さ60の「文字型配列」と して宣言しています.詳しいことは後の章で説明します. *型の指定に用いる表現* char -- 文字型 [60] -- 長さ60の配列 6行目:入力を促すメッセージを出力しています.改行文字列「\n」がないことに 注意して下さい.こうすると「(please enter)」というメッセージの後にカーソル が止まり,入力待ちの状態になります. 7行目:fgets を呼び出して,キーボードから文字列を入力し,変数buffer に格納 ます.読み込む文字列の長さ(バイト数)と入力先のファイル(正確にはファイル ストリーム)も指定します. * fgets の使い方 fgets(string, n, input); string: 文字列変数 n: 読み込む長さ(バイト), input: 読み込み先(ファイルなど) 上のプログラムでは読み込みバイト数 n を変数bufferの長さ60に,また,入力先を 「stdin」(標準入力, つまりキーボード)にして使っています. 8行目:printf を用いてメッセージを表示しています.ここで printf の新しい 使い方に注意してください.ここでは変数 buffer に格納されたデータを他の文字 列(今の場合 "Hello, ...\n")の中に埋め込んでいます.埋め込む位置と埋め込む データの表示形式を指示するのが "%s" という文字列です.これは「変換仕様」と 呼ばれるものの一種で,渡したデータを文字列として表示することを指示するもの です. *文字列変換仕様による文字列の埋め込み* printf("...%s...", string); /* string は文字型配列 */ 変換仕様には他にもさまざまなものがあります(後の章で説明します). 5.対話的なプログラム 文字列の入出力によって対話的な処理を行うことができます.次のプログラム例は そのような処理の典型的なパターンを示すものです.ここでは複数の変数を用意し て「初期化」し,そこに入力データを格納しています. 1:#include 2: 3:void main(void) 4:{ 5: char tel[16],fax[16],email[60]; 6: char cat[] = "\ 7: * * \n\ 8: * * * * * \n\ 9: * o o *\n\ 10: * ^ *\n\ 11: * --- * \n\ 12: * * * \n"; 13: 14: printf("%s", cat); 15: printf("Enter your telephne and fax numbers and e-mail address please.\n"); 16: printf(" Telephone: "); fgets(tel,16,stdin); 17: printf(" Fax: "); fgets(fax,16,stdin); 18: printf(" E-mail: "); fgets(email,60,stdin); 19: printf("%s", cat); 20: printf("Thank you. The following are the input data.\n"); 21: printf(" Tel:%s Fax:%s E-mail:%s\n\n", tel,fax,email); 22:} 5行目:ここで3つの文字型配列変数 tel, fax, email を宣言しています.この ように,基本的な型(この場合は char)が同じものは(長さの違う配列であって も)一度にまとめて宣言することができます. なお,変数名の「email」を「e-mail」というようにしてはいけません.変数の名 前に使えるのは英数字とアンダースコア「_」だけです.(「e_mail」は許されま す.)それ以外の文字(たとえば「-」はプログラムのなかで特別な意味をもって いるので変数名に使えません.また,tel1, tel2 のように英字と数字を混ぜても 構いませんが,数字から始まる変数名は許されません. 6行目ー12行目:これも文字型配列の宣言なのですが,宣言と同時に指定したデ ータを格納(初期化という)する例となっています.もう少しわかりやすい例 char hello[] = "Hello, world!\n"; を考えましょう.ここでは hello という文字型配列が "Hello, world\n" という 文字列を格納した状態で用意されます.このとき配列の長さを省略していますが, こうするとコンパイラが文字列の長さを数えてそれに合う長さの配列を用意してく れます.上のプログラムの例では,「\」文字で終わる行は続いているものと解釈 されることを思い出せば,6行目の最後の引用符から12行目の最後の引用符まで が一つの長い文字列で,それで cat という配列変数を初期化しているわけです. これくらい長くなれば自分で数えるのは非現実的でしょう. *文字型配列変数の初期化の一般形* char variable[] = string; /* string は具体的な文字列 */ 14行目ー21行目:printf と gets で入出力を行っています.特に,21行目 は複数個の変数から変換仕様によってデータを挿入する例になっています. *複数個の文字型配列から文字列を挿入する* printf("...%s...%s...", string1, string2, ...);