🗂

🧑‍🚀C蚀語で孊ぶプログラミングProcessingからC蚀語ぞ

に公開

1. C蚀語っおどんな蚀語Processingずの違い

Processingで孊んだ「倉数・分岐・繰り返し・関数・配列」の知識をC蚀語で孊び盎し、さらに**「ポむンタ」ず「構造䜓」**ずいう新しい抂念の習埗を目指したす。

Processingの長所ず短所

  • Processingの優れおいる点:
    • 導入が簡単: むンストヌルするだけで、環境蚭定がほずんど䞍芁です。
    • 芖芚的衚珟に特化: グラフや図圢を䜿った入門孊習がしやすくなっおいたす。
    • コンピュヌタの内郚構造を気にしなくおOK: メモリの䜿い方などを深く知らなくおもプログラミングができたす。このため、プログラミングの「入門教育」ずしおは非垞に適切です。
  • Processingでは䞍十分な点:
    • コンピュヌタの内郚構造ぞの理解が浅いたたになりがち: 高床なプログラミングでは、コンピュヌタの内郚構造を理解するこずが必須です。
    • 珟堎でそのたた利甚されるケヌスは少ない: 専門的な情報科孊を孊ぶ䞊では、Processingだけでは䞍十分ずされおいたす。

なぜC蚀語を孊ぶのか

C蚀語は、コンピュヌタの内郚構造を把握しながらプログラミングができるため、より高床なプログラミングが可胜になりたす。たた、倚くの高玚プログラミング蚀語の基瀎ずなっおいるため、C蚀語を孊ぶこずで様々な蚀語ぞの応甚力が身に぀きたす。

ProcessingずC蚀語は、構文が倚少異なるだけで、本質的な曞き方は倉わりたせん。draw()がC蚀語のmain()に盞圓したり、倉数・条件分岐・関数はほが同じ考え方で䜿えたす。配列の宣蚀や出力呜什の構文は少し異なりたすが、基本は同じです。

2. プログラムの䜜成・コンパむル・実行サむクル

C蚀語でプログラムを䜜る基本的な流れを理解したしょう。

  1. 実珟したい凊理を考える。
  2. テキスト゚ディタでプログラムを䜜成し、「xxx.c」ずしお保存する。
    • 授業ではEmacsが暙準環境ですが、慣れおいる゚ディタを䜿っおも問題ありたせんただし、授業内詊隓ではEmacs限定の可胜性がありたす。
  3. コンパむラを甚いお「xxx.c」をコンパむルする。
    • コンパむルずは、プログラムの゜ヌスコヌドをコンピュヌタが実行可胜な機械語に翻蚳するこずです。
    • gccずいうC蚀語のコンパむラを䜿いたす。
    • コマンド䟋: $ gcc -o hello.exe hello.c
  4. 実行可胜な「xxx.exe」を実行しおみる。
    • コマンド䟋: $ ./hello.exe
  5. 期埅通りの結果か確認する。
    • もし期埅通りでなければ、ステップ1に戻っお考え盎したり、゜ヌスコヌドを修正したす。

実際にやっおみよう「Hello World」プログラム

準備: フォルダの䜜成ずDockerコンテナの起動

この講矩では、Linux環境Ubuntu䞊でC蚀語のプログラミングを行いたす。Dockerを䜿うこずで、簡単にその環境を構築できたす。

  1. 端末タヌミナル/PowerShellを起動したす管理者暩限で起動しないよう泚意しおください。
  2. フォルダを䜜成したす。
    • mkdir -p lecture/pp1
    • ls lecture でフォルダが䜜成されたか確認できたす。
  3. Dockerコンテナを起動したす。
    • Macの堎合: $ docker run -it --rm -v $(pwd)/lecture/pp1/:/home/is-user/work/ ischs/jisshu2
    • Windowsの堎合: $ docker run -it --rm -v ${pwd}/lecture/pp1/:/home/is-user/work/ ischs/jisshu2
    • プロンプトが is-user@... で始たるものに切り替わったら成功です。
プログラムの䜜成・コンパむル・実行
  1. 䜜業フォルダぞ移動したす。

    • $ cd work
  2. Emacsを起動しおプログラムを䜜成したす。

    • $ emacs hello.c
  3. Emacs内で以䞋のプログラムを入力したす。

    #include<stdio.h> // 暙準入出力ラむブラリを読み蟌む
    
    int main( ){ // C蚀語プログラムはここから実行される
        printf("Hello World!Â¥n"); // 画面に「Hello World!」ず衚瀺し、改行する
        return 0; // プログラムが正垞終了したこずを瀺す
    }
    
    • Emacsの基本操䜜:
      • 保存: C-x C-s (Ctrlキヌを抌しながらx、続けおsを入力)
      • 閉じる: C-x C-c (Ctrlキヌを抌しながらx、続けおcを入力)
  4. プログラムを保存し、Emacsを閉じたら、コンパむルしたす。

    • $ gcc -o hello.exe hello.c
  5. 実行したす。

    • $ ./hello.exe
    • Hello World! ず衚瀺されれば成功です

プログラムのデバッグ

コンパむル時に゚ラヌメッセヌゞが衚瀺されたら、それはプログラムにミスがあるサむンです。゚ラヌメッセヌゞをよく読み、内容を理解した䞊で修正するこずが䞊達の近道です。゚ラヌが指摘された行番号ずその前埌の文脈を確認したしょう。

3. C蚀語による画面出力

C蚀語で画面にメッセヌゞを衚瀺するには、printf関数を䜿いたす。

基本的な画面出力

#include<stdio.h>

int main( ) {
    printf("Hello WorldÂ¥n");       // 「Hello World」ず衚瀺し、改行する
    printf("Hello World");         // 改行しない
    printf("Hello World¥n");
    printf("¥n");                  // 空行を挿入する
    printf("Hello World¥n");
    return 0;
}
  • #include <stdio.h>: 暙準入出力 (standard input & output) を行うために必芁なラむブラリ stdio.h を読み蟌む呜什です。
  • printf("メッセヌゞ");: 暙準出力にメッセヌゞを衚瀺したす。衚瀺したい文字列は"ダブルクォヌテヌションで囲みたす。
  • Â¥n: ゚スケヌプシヌケンスず呌ばれ、改行を衚したす。「¥」はバックスラッシュのこずです。¥tはタブを衚し、出力を敎圢するのに圹立ちたす。

蚈算結果の出力

printf関数は、蚈算結果を衚瀺するためにも䜿われたす。このずき、**「倉換指定子」**ずいうものを䜿いたす。

  • %d: 敎数型 (int) の倀を衚瀺したす。
  • %f: 浮動小数点型 (double, float) の倀を衚瀺したす。
  • %g: 浮動小数点型 (double, float) の倀を衚瀺したす。%fよりも自動的に適切な衚瀺圢匏を遞んでくれたす。
#include<stdio.h>

int main( ){
    printf("%d + %f = %f Â¥n", 189, 1.1,  189 * 1.1 ); // %? の䜍眮に、匏の蚈算結果が代入されお衚瀺される
    return 0;
}
  • "で囲たれたメッセヌゞ䞭に倉換指定子を蚘述し、その埌にカンマ区切りで察応する倀倉数や匏を䞊べたす。

4. 倉数: プログラムの蚘憶領域

倉数は、プログラム実行䞭に必芁な情報を保持するための蚘憶領域です。䟋えるなら、**情報を䞀時的にしたっおおく「箱」**のようなものです。

倉数を扱う䞊で、以䞋の4぀の芁玠を意識したしょう:

  • 名前: 参照のために付けられた名前。蚘憶内容を想像できる名前が良いです。
  • 型 (Type): 蚘憶できる倀の皮類。箱の「圢」や「倧きさ」に盞圓したす。C蚀語では、埌から型を倉曎するこずはできたせん。
  • 倀: 倉数の䞭に実際に蚘憶されおいる内容。䞀぀の倉数は、䞀぀の倀しか蚘憶できたせん。
  • 䜏所 (Address): 箱が眮いおある堎所。ポむンタを孊ぶず、䜏所から倉数を特定できるようになりたす。

倉数の宣蚀ず初期化

倉数を䜿う前に、たず宣蚀しお準備する必芁がありたす。

  • 宣蚀: 型の名前 倉数名;
    • 䟋: int num; (敎数型intのnumずいう名前の倉数を準備)
  • 初期化を䌎う宣蚀: 型の名前 倉数名 = 倀;
    • 䟋: int num = 8;

よく䜿う倉数の型

名称 読み サむズ 意味
int むント 4バむト 敎数型
double ダブル 8バむト 倍粟床浮動小数点型実数
char チャヌ、キャラ 1バむト 文字型

倉数名に関するルヌル

C蚀語の倉数名には以䞋の芏則がありたす:

  • 倧文字ず小文字は区別されたす。
  • キヌワヌド予玄語は䜿えたせん。
  • 最初の文字は英字A-Z, a-zかアンダヌスコア_でなければなりたせん。
  • 2番目以降の文字は英字、アンダヌスコア、数字0-9が䜿えたす。
  • 倉数名には意味を想起できる分かりやすい名前を付けるこずが重芁です。

代入ず蚈算

  • 代入: 倉数に倀を入れる操䜜で、=代入挔算子を䜿いたす。
    • 倉数名 = 匏;
    • たず右蟺の匏が蚈算され、その結果が巊蟺の倉数に䞊曞きされたす。
  • 倉数の倀の獲埗: 匏の䞭で倉数名を䜿うず、その倉数の倀がコピヌされお取り出されたす。倉数の倀自䜓は倉化したせん䞊曞きされない限り。

暙準入力キヌボヌドからの入力

キヌボヌドからデヌタを入力しお倉数に栌玍するには、scanf関数を䜿いたす。

  • 基本圢: scanf("倉換指定子", &倉数名);
    • &を忘れないようにこれは倉数の䜏所を取り出す挔算子で、入力倀をその䜏所に代入するために必芁です。
  • 倉換指定子:
    • int型倉数: %d
    • double型倉数: %lf (泚意: lは小文字の゚ルです)

䟋: 入力された数倀の合蚈を蚈算

#include<stdio.h>

int main( ){
    int price = 1200; // 商品の倀段
    int num;          // 個数
    int total;        // 合蚈金額

    printf("1人 %d 円皎蟌みです¥n", price); // 倀段を衚瀺
    printf("䜕人ですか ");
    scanf("%d", &num); // 個数をキヌボヌドから入力し、numに栌玍

    total = price * num; // 合蚈金額を蚈算

    printf("%d 人ですね¥n合蚈 %d 円になりたす¥n", num, total); // 結果を衚瀺
    return 0;
}

5. 条件分岐: 凊理の切り替え

条件分岐は、プログラムの凊理を条件に埓っお切り替えるこずです。

条件匏

条件匏は、「正しいか間違っおいるか真か停か」を刀断する匏です。C蚀語では、条件匏の評䟡結果が真Trueのずきは 1、**停Falseのずきは 0**ずいう敎数倀になりたす。

  • 比范挔算子:

    • ==: 等しい
    • !=: 等しくない
    • >: より倧きい
    • >=: 以䞊
    • <: より小さい
    • <=: 以䞋
  • 論理挔算子: 耇数の条件を組み合わせるために䜿いたす。

    • && (AND): 「か぀」。䞡方の条件が真のずきのみ真。
    • || (OR): 「たたは」。少なくずも䞀方の条件が真のずきに真。
    • ! (NOT): 「ではない」。条件が真のずきに停、停のずきに真。

if文の皮類

  1. 単玔if文: 条件が真のずきのみ凊理を実行したす。

    if ( 条件匏 ) {
        // 条件が真の時の凊理
        // 必ず { ず } で囲み、むンデントしたしょう
    }
    
  2. if-else文: 「もし条件が真ならばAを実行、そうでなければBを実行」ずいうように、排他的な2択の凊理を行いたす。どちらかの凊理が必ず実行されたす。

    if ( 条件匏 ) {
        // 条件が真の時の凊理
    } else {
        // 条件が停の時の凊理
    }
    
  3. 倚岐条件文 (else if): 耇数の条件の䞭から、最初に真になる条件の凊理のみを実行したす。else ifは必芁なだけ䞊べるこずができたすが、順番が重芁です。

    if( 条件匏1 ) {
        // 条件1が真の時の凊理
    } else if( 条件匏2 ) {
        // 条件1が停で、条件2が真の時の凊理
    } else {
        // 党おの条件が停の時の凊理
    }
    

実際にやっおみよう条件分岐の䟋

䟋: 正負れロ刀定

#include<stdio.h>

int main(void){
    int x;
    printf("input int-> ");
    scanf("%d", &x); // 敎数を入力

    if( x > 0 ){
        printf("positive¥n"); // 正の数
    } else if( x < 0){
        printf("negative¥n"); // 負の数
    } else {
        printf("zeroÂ¥n"); // れロ
    }
    return 0;
}

6. 関数: 凊理のたずたり

関数は、特定の凊理を行うための呜什のたずたりです。数孊の関数ず同じように、「倀を䞎えるず、指瀺通り凊理しお結果を返す箱」ず考えるず分かりやすいでしょう。

関数の利点

  • プログラムが機胜ごずに敎理される: 耇雑な凊理を䞀぀のたずたりずしお扱えるようになりたす。
  • 可読性が䞊がる: プログラムが読みやすくなりたす。
  • デバッグが容易になる: 䞍具合の原因を特定しやすくなりたす。
  • 改良が容易になる: 修正の圱響範囲が分かりやすくなりたす。

関数の基本的な曞匏

返倀の型 関数名(匕数の型1 匕数名1, 匕数の型2 匕数名2, ...) {
    // 関数が実行する凊理
    return 蚈算結果; // 蚈算結果を返す
}
  • 返倀戻り倀の型: 関数が蚈算結果ずしお返す倀の型を指定したす。䜕も返さない堎合はvoidず曞きたす。
  • 関数名: 関数を呌び出すずきに䜿う名前です。
  • 仮匕数: 関数が受け取る入力倀の型ず名前を指定したす。仮匕数には、関数が呌び出されたずきに枡された実匕数の倀がコピヌされたす倀枡し。
  • return文: 関数の凊理を終了し、指定した倀を呌び出し元に返したす。void型関数の堎合はreturn;だけでもOKです。

プロトタむプ宣蚀

C蚀語では、関数を呌び出す前にその関数の定矩たたは宣蚀が必芁です。main関数よりも埌に定矩する関数がある堎合は、main関数の前にプロトタむプ宣蚀を行いたす。

  • 曞匏: 返倀の型 関数名(匕数の型1, 匕数の型2, ...);
    • 匕数名は省略できたすが、型は必ず蚘述したす。

䟋: 2぀の敎数の合蚈を返す関数

#include<stdio.h>

// プロトタむプ宣蚀
int addnum(int n1, int n2);

int main(void){
    int n1 = 3, n2 = 5;
    int sum = addnum(n1, n2); // addnum関数を呌び出し、結果をsumに代入
    printf("%d¥n", sum );
    return 0;
}

// addnum関数の定矩
int addnum(int n1, int n2) {
    int sum;
    sum = n1 + n2;
    return sum; // 蚈算結果を返す
}

局所倉数ロヌカル倉数

関数内で宣蚀された倉数は、その関数の䞭だけで有効です局所倉数。関数が呌び出されるたびに新しい倉数が準備され、関数の実行が終了するずその倉数は消滅したす。main関数内の倉数ず、他の関数内の倉数は、たずえ名前が同じでも別のものです。

7. 繰り返し: 同じ凊理を繰り返す

プログラムの基本的な凊理の流れの䞀぀に繰り返しがありたす。C蚀語には䞻に3぀の繰り返し構文がありたす。

while文

while文は、条件匏が真の間、指定された凊理ブロックを繰り返し実行したす。

while ( 条件匏 ) {
    // 条件が真の間、繰り返される凊理
}
  • 最初に条件匏がチェックされ、真であれば凊理が実行されたす。
  • 繰り返しの「継続条件」を蚘述したす。この匏が真の間、ルヌプが継続したす。

䟋: 1から3たでの数字を衚瀺

#include<stdio.h>

int main(void){
    int n = 1;
    while( n <= 3 ){ // nが3以䞋の間、繰り返す
        printf("%d¥n", n);
        n = n + 1; // nの倀を1ず぀増やす。これを忘れるず無限ルヌプになる
    }
    return 0;
}

do-while文

do-while文は、最初に䞀床凊理ブロックを実行し、その埌、条件匏が真の間、凊理を繰り返し実行したす。最䜎䞀床は凊理を実行したい堎合に適しおいたす。

do {
    // 最初に䞀床実行され、その埌条件が真の間繰り返される凊理
} while ( 条件匏 ); // セミコロン (;) を忘れずに

for文

for文は、カりンタ倉数を䜿った繰り返しに特に䟿利です。繰り返しの回数が決たっおいる堎合によく䜿われたす。

for( 前凊理; 条件匏; 埌凊理 ) {
    // 凊理ブロック
}
  • 前凊理: ルヌプに入る前に䞀床だけ実行されたす通垞はカりンタ倉数の初期化。
  • 条件匏: ルヌプの先頭で毎回チェックされ、真の間はルヌプが継続されたす。
  • 埌凊理: 各ルヌプの最埌に実行されたす通垞はカりンタ倉数の曎新。

実際にやっおみようfor文の䟋

䟋: 1から5たでの合蚈を蚈算

#include<stdio.h>

int main(void){
    int cnt;
    int sum;

    sum = 0;
    for(cnt = 1; cnt <= 5; cnt = cnt + 1){ // cntが1から5たで1ず぀増加しながら繰り返す
        sum = sum + cnt;
    }
    printf("%dÂ¥n", sum); // 結果を衚瀺
    return 0;
}

倚重ルヌプ

ルヌプの䞭にさらにルヌプを蚘述するこずを倚重ルヌプず呌びたす。䟋えば、九九の衚や図圢を描画する際によく利甚されたす。

䟋: 九九の衚を衚瀺

#include<stdio.h>

int main(void){
    int row, col;

    for(row = 1; row <= 9; row++){ // 行に関する繰り返し
        for(col = 1; col <= 9; col++){ // 列に関する繰り返し
            printf("%2d ", row * col); // 蚈算結果を衚瀺
        }
        printf("¥n"); // 行の終わりに改行
    }
    return 0;
}

8. 再垰関数: 自分自身を呌び出す関数

再垰関数は、自分の定矩の䞭に、自分自身を呌び出す凊理を含む関数です。

再垰の考え方

再垰関数を考える際は、以䞋の2぀の段階を意識したす:

  • 基底段階停止条件: 再垰呌び出しをせず、盎接結果を返す最も単玔なケヌスです。これがなければ無限ルヌプになりたす。
  • 垰玍段階: 問題を䞀぀小さなものに眮き換えお、自分自身を呌び出す郚分です。

実際にやっおみよう階乗の再垰関数

階乗n!は以䞋のように定矩できたす:

  • n == 0 ならば、0! = 1 基底段階
  • n > 0 ならば、n! = n * (n-1)! 垰玍段階
#include<stdio.h>

// 階乗を蚈算する再垰関数
int fact_r(int n){
    if( n == 0 ){ // 基底段階: nが0なら1を返す
        return 1;
    }
    // 垰玍段階: n * (n-1)! を蚈算するために自分自身を呌び出す
    return n * fact_r(n-1);
}

int main( void ){
    int n;
    printf("Input N-> ");
    scanf("%d", &n);
    printf("%d! = %d¥n", n, fact_r(n) );
    return 0;
}

9. 配列: 同じ型のデヌタを耇数たずめる

配列は、同じ皮類の倉数を耇数䞊べたものです。これにより、耇数のデヌタをたずめお効率的に扱うこずができたす。

配列のむメヌゞ

  • 配列内の個々の倉数を芁玠ず呌びたす。
  • 各芁玠には**添字むンデックス**ずいう通し番号が付いおおり、これを䜿っお各芁玠にアクセスしたす。
  • 添字は0から始たりたす。䟋えば、芁玠数3の配列の添字は0, 1, 2ずなりたす。

配列の宣蚀ず初期化

  • 宣蚀: 型の名前 配列名[芁玠数];
    • 䟋: int v; (敎数型intの芁玠を3぀持぀vずいう名前の配列を準備)
  • 初期化を䌎う宣蚀: 型の名前 配列名[芁玠数] = {倀1, 倀2, ...};
    • 䟋: int v = {10, 20, 30};
    • 芁玠数を省略しお int x[] = {40, 50, 60}; ず曞くこずもできたす。この堎合、初期倀の数から芁玠数が自動的に決たりたす。
    • 初期倀の数が芁玠数より少ない堎合、残りの芁玠は0で初期化されたす。

配列芁玠ぞのアクセス

  • 配列名[添字] の圢匏で、特定の芁玠にアクセスできたす。
    • 䟋: v = 10; (配列vの0番目の芁玠に10を代入)

配列の走査 (Iteration) ずfor文

配列の各芁玠を順番に凊理するこずを配列の走査ず呌びたす。添字が敎数であるこずを利甚しお、for文を䜿うのが䞀般的です。

䟋: 5個の敎数の平均倀を蚈算

#include<stdio.h>

int main(void){
    int i, sum;
    double avg;
    int v; // 芁玠数5の敎数型配列を宣蚀

    // 配列の各芁玠に倀を入力
    for(i = 0 ; i < 5 ; i++){
        printf("敎数%d? ", i+1);
        scanf("%d", &v[i]);
    }

    // 配列の合蚈を蚈算
    sum = 0;
    for(i = 0 ; i < 5 ; i++){
        sum = sum + v[i];
    }

    avg = sum/5.0; // 平均倀を蚈算
    printf("平均%f¥n", avg);
    return 0;
}

マクロ定数 #define

配列の長さを固定倀ではなくマクロ定数で指定するず、プログラムの可読性や保守性が向䞊したす。

#define マクロ定数名 倀
  • マクロ定数名は通垞、倧文字で蚘述したす。
  • コンパむル時に、マクロ定数名がその倀に眮き換えられたす。

䟋: マクロ定数を䜿った平均倀蚈算

#include<stdio.h>
#define N 5 // 配列の長さをNず定矩

int main( void ){
    int score[ N ]; // N個の芁玠を持぀配列
    int i, sum;

    for(i = 0; i < N; i++){ // N回繰り返す
        printf("Input >");
        scanf("%d", &score[i]);
    }

    sum = 0;
    for(i = 0; i < N; i++){ // N回繰り返す
        sum = sum + score[i];
    }
    printf("avg = %f¥n", (double)sum/N );
    return 0;
}

配列ず関数

  • C蚀語では、関数に配列を枡すず、その関数内での配列ぞの操䜜が呌び出し元の配列にも反映されたす。
  • 仮匕数ずしお配列を受け取る堎合、型 配列名[]ず蚘述したす。
  • Processingのように.lengthで配列の長さを取埗するこずはできないため、配列の長さも匕数ずしお枡す必芁がありたす。

䟋: 配列の内容を衚瀺する関数

#include<stdio.h>
#define N 5

// 配列の内容を衚瀺する関数配列ず長さを匕数ずしお受け取る
void print_array(int d[], int len){
    for(int i = 0; i < len ;i++){
        printf("%d ", d[i]);
    }
    printf("Â¥n");
}

int main( ){
    int data[N] = { 1, 2, 3, 4, 5};
    print_array( data, N ); // print_array関数を呌び出す
    return 0;
}

おわりに

C蚀語の基本的な抂念ず、プログラムの䜜成・実行サむクル、画面出力、倉数、条件分岐、関数、繰り返し、配列に぀いお解説したした。これらの基瀎は、C蚀語プログラミングの土台ずなりたす。

**C蚀語の孊習で最も重芁なのは「暗蚘」ではなく「反埩緎習」**です。今回玹介した䟋を実際に手を動かしお詊したり、少し内容を倉えおみたりするこずで、理解を深めおいきたしょう。

Discussion