[CS 50]アレイ整理コース


コンパイル

#include <stdio.h>

int main(void)
{
	printf("hello, world\n")
}
C言語で作成したファイルを実行するには、次のclangコマンドを使用して「コンパイル」する必要があります.
clang -o hello hello.c
このコマンドを入力すると、ファイルがコンパイルされ、コンピュータは0と1のファイルhelloを読み込みます.outを作成し、実行可能にします.
Cのmakeまたはclangを使用してプログラムを実行すると、次の4つのステップが実行されます.
  • 前処理
  • コンパイル
  • 組立
  • Linking
  • プリコンパイル


    コンパイルのプロセス全体は4つの段階に分けることができます.最初のステップは、プリプロセッサによって実行される前処理です.先頭のCソースコードでは、プリプロセッサが実際のコンパイルを行う前にいくつかの操作を実行することを通知します.
    たとえば、#includeは、前のプロセッサに他のファイルの内容が含まれていることを通知します.プログラムのソースコードに#includeと同じ行が含まれている場合、プリプロセッサは新しいファイルを作成します.このファイルは依然としてCソースコード形式であり、stdio.hファイルの内容は#includeセクションに含まれます.

    コンパイル


    フロントプロセッサが前処理のソースコードを生成した後、次はコンパイルです.コンパイラと呼ばれるプログラムはCコードをコンポーネントと呼ばれる低レベルのプログラミング言語にコンパイルする.
    コンポーネント内の演算はCよりはるかに少ないが、複数の演算を同時に使用すると、Cが実行できるすべての操作を実行することができる.Cコードをコンポーネントコードに変換することで,コンパイラはプログラムをコンピュータが理解できる言語にできるだけ近づけることができる.「コンパイル」という言葉は、ソースコードからオブジェクトコードに変換するプロセス全体を指しますが、特定の処理を施したソースコードをコンポーネントコードに変換するステップも指します.

    くみたて


    ソースコードがコンポーネントコードに変換された場合は、コンポーネントコードをオブジェクトコードに変換する、すなわち次のコンポーネントステップを示します.これは、コンピュータの中央プロセッサを連続的な0と1に変換する命令形式であり、プログラムをどのように実行するかを知る.この変換はアセンブリというプログラムによって実行されます.ソースコードにオブジェクトコードとしてコンパイルするファイルが1つしかない場合は、コンパイル操作はこれで終了します.ただし、そうでない場合は、リンクと呼ばれるステップが追加されます.

    リンク(Link)


    プログラムが複数のファイル(ライブラリincludeなど)で構成され、1つのオブジェクトファイルにマージする必要がある場合は、リンクと呼ばれる最後のステップをコンパイルする必要があります.ループは、複数の異なるオブジェクトコードファイルを実行可能なオブジェクトコードファイルにマージします.たとえば、コンパイル中にCS 50ライブラリにリンクされている場合、オブジェクトコードはGetInt()またはGetString()などの関数を実行する方法を知っています.
    この4つのステップは、最終実行可能ファイルを完了しました.

    配列(1)


    メモリ


    Cは複数のデータ型があり、各データ型は異なるサイズのメモリを占有する:
  • bool:ブール型、1バイト
  • char:文字、1バイト
  • int:整数、4バイト
  • float:実数、4バイト
  • long:(より大きい)整数、8バイト
  • double:(より大きい)実数、8バイト
  • string:文字列、?バイト
  • コンピュータのメモリは、次の図に示すように、RAMと呼ばれる物理チップです.
    簡単に言えば、以下の写真では、複数の黄色い矩形がメモリを表し、1つの小さな矩形が1バイトを表す.

    たとえば、文字タイプの変数を作成して値を入力すると、その値は上図の長方形に格納されます.

    整列


    3つのスコアを格納し、平均値を出力するプログラムを作成します.各スコアをハードコーディングできますが、スコアが多くなると、このプログラムは多くの部分を変更する必要があります.配列と呼ばれるデータ型を使用できます.
    配列は、同じデータ型のデータをメモリに格納し、変数として管理するために使用されます.
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Scores
        int scores[3];
        scores[0] = 72;
        scores[1] = 73;
        scores[2] = 33;
    
        // Print average
        printf("Average: %i\n", (scores[0] + scores[1] + scores[2]) / 3);
    }
    コード
  • int scores[3];は、scolesという名前の3サイズの整数配列が生成されることを示す.
  • 配列のインデックスはゼロから始まるため、scopsには0、1、2の3つのインデックスがあります.
  • このインデックスは、配列内の任意の場所に必要な値を格納およびロードするために、変数名の後のカッコ[]の間に入力できます.
  • しかしながら、上記のコードは、スコアが変更された場合にも多くの制限がある.

    配列(2)


    グローバル変数


    次のコードでは、スコア配列のサイズを決定するためにNという変数が新たに宣言されます.
    Nが固定値(定数)である場合、値を宣言するときにconstを前にして、グローバル変数、すなわちコード全体で変更されない値であることを指定できます.
    通常、これらのグローバル変数の名前は大文字で表されます.
    #include <cs50.h>
    #include <stdio.h>
    
    const int N = 3;
    
    int main(void)
    {
        // 점수 배열 선언 및 값 저장
        int scores[N];
        scores[0] = 72;
        scores[1] = 73;
        scores[2] = 33;
    
        // 평균 점수 출력
        printf("Average: %i\n", (scores[0] + scores[1] + scores[2]) / N);
    }

    動的宣言とストレージアレイ

    constという固定変数を使用すると、結果は常に固定されます.ループと関数を宣言することで、次のコードに示すように、よりダイナミックなプログラムを作成できます.
    #include <cs50.h>
    #include <stdio.h>
    
    float average(int length, int array[]);
    
    int main(void)
    {
        // 사용자로부터 점수의 갯수 입력
        int n = get_int("Scores:  ");
    
        // 점수 배열 선언 및 사용자로부터 값 입력
        int scores[n];
        for (int i = 0; i < n; i++)
        {
            scores[i] = get_int("Score %i: ", i + 1);
        }
    
        // 평균 출력
        printf("Average: %.1f\n", average(n, scores));
    }
    
    //평균을 계산하는 함수
    float average(int length, int array[])
    {
        int sum = 0;
        for (int i = 0; i < length; i++)
        {
            sum += array[i];
        }
        return (float) sum / (float) length;
    }
    ここで、ユーザは配列のサイズを直接入力し、各インデックスの値(配列のサイズと同じ)を動的に入力して保存します.さらにaverageという関数を宣言して平均値を求めます.
    平均関数はlengthとarray[]、すなわち配列の長さと配列を受け入れます.関数では、ループの長さはアレイの長さと等しく、値の和を求め、最後に平均値を返します.

    文字列と配列


    cでは、文字列型データは文字型データの配列である.
    文字列sは、string s = “HI!”;のように定義されていると仮定する.
    sは文字の配列であるため、メモリに格納する場合は下図のように、インデックスを介して各文字にアクセスすることができる.

    ここで最後尾の‘\0’は、文字列の末尾を表す空(NULL)の終了文字です.すべてのビットが「0」のバイトのみを指します.
    複数の文字列を同時に宣言する場合は、次のコードを参照してください.
    string names[4];
    
    names[0] = "EMMA";
    names[1] = "RODRIGO";
    names[2] = "BRIAN";
    names[3] = "DAVID";
    
    printf("%s\n", names[0]);
    printf("%c%c%c%c\n", names[0][0], names[0][1], names[0][2], names[0][3]);
    4つの名前は、文字列タイプnamesの配列に格納されます.
    最初のprintfは、namesの最初のインデックスの値、すなわち「EMMA」を出力する.
    2番目のprintfでは、フォーマット指定子が%sではなく%cに設定されていることがわかります.したがって、出力されるのは文字列ではありません.ここでは、names[0][1]などの2次元配列を介してアクセスできる各名前の2番目の文字を出力します.
    すなわち、names[0][1]は、namesの最初の値、すなわち「EMMA」文字列の2番目の値、すなわち「M」である.
    次の図では、namesは、実際のメモリに格納されている例とそのインデックスを表示します.

    リファレンス

  • 全員向けのコンピュータサイエンス(CS 50)2019-配列