Week 1 C

ようこそ!

  • 前回のセッションでは、ビジュアルプログラミング言語であるScratchについて学びました。

  • 実際、Scratchで紹介された重要なプログラミングの概念はすべて、他のプログラミング言語のプログラミングを学ぶ際にも活用されます。Scratchにある関数、条件分岐、ループ、変数は、あらゆるプログラミング言語で見られる基本的な構成要素です。

  • マシンはバイナリしか理解できないことを思い出してください。人間は人間が読める命令のリストである「ソースコード」を書きますが、マシンは今や私たちが「マシン語」と呼べるものしか理解できません。このマシン語は、望ましい効果を生み出す0と1のパターンです。

  • 「コンパイラ」と呼ばれる非常に特別なソフトウェアを使用することで、ソースコードをマシン語に変換できることがわかりました。今日は、プログラミング言語Cのソースコードをマシン語に変換できるコンパイラをご紹介します。

  • 今日は、プログラミング方法を学ぶだけでなく、良いコードを書く方法についても学びます。

CS50のためのVisual Studio Code

  • このコースで使用されるテキストエディタは「Visual Studio Code」(通称VS Code)であり、cs50.devとして親しまれています。同じURLからアクセスできます。

  • VS Codeを使用する最も重要な理由の1つは、コースに必要なすべてのソフトウェアがあらかじめロードされていることです。このコースとその中の説明は、VS Codeを念頭に置いて設計されています。

  • 自分のコンピュータにコースに必要なソフトウェアを手動でインストールするのは、非常に面倒で大変な作業です。このコースの課題には常にVS Codeを使用するのが最善です。

  • VS Codeは cs50.dev で開くことができます。

コンパイラはいくつかの領域に分けることができます:

左側にファイルを探すことができる「ファイルエクスプローラー」があることに注目してください。さらに、中央にはプログラムを編集できる「テキストエディタ」と呼ばれる領域があります。最後に、「CLI(コマンドラインインターフェース)」、あるいは「コマンドライン」、「ターミナルウィンドウ」と呼ばれる、クラウド上のコンピュータにコマンドを送信できる領域があります。

  • ターミナルウィンドウで使用する可能性のある一般的なコマンドライン引数(コマンド)には、以下のものがあります:

cd:カレントディレクトリ(フォルダ)の変更

cp:ファイルやディレクトリのコピー

ls:ディレクトリ内のファイル一覧の表示

mkdir:ディレクトリの作成

mv:ファイルやディレクトリの移動(名前の変更)

rm:ファイルの削除

rmdir:ディレクトリの削除

  • 最もよく使われるのは ls で、現在のディレクトリ内のすべてのファイルを一覧表示します。ターミナルウィンドウに ls と入力して enter を押してみてください。現在のフォルダ内のすべてのファイルが表示されます。

  • このIDEは必要なすべてのソフトウェアが事前設定されているため、このコースのすべての課題を完了するために使用する必要があります。

Hello World

最初のプログラムを記述、コンパイル、実行するために、3つのコマンドを使用します:

code hello.c

make hello

./hello

最初のコマンド code hello.c はファイルを作成し、このプログラムの命令を入力できるようにします。2番目のコマンド make hello は、Cの命令からファイルを「コンパイル」し、hello という名前の実行ファイルを作成します。最後のコマンド ./hello は、hello というプログラムを実行します。

ターミナルウィンドウに code hello.c と入力することで、最初のCプログラムを作成できます。ファイル名全体を意図的に小文字にし、.c 拡張子を含めていることに注意してください。次に、表示されるテキストエディタで次のようにコードを書きます。

// A program that says hello to the world

#include

int main(void)
{
    printf("hello, world\n");
}

上記のすべての文字には目的があることに注意してください。間違って入力すると、プログラムは実行されません。printf はテキストの一行を出力できる関数です。引用符とセミコロンの位置に注目してください。さらに、\nhello, world という単語の後に改行を作成することに注目してください。

  • ターミナルウィンドウに戻り、make hello を実行してコードをコンパイルします。.c を省略していることに注意してください。makehello.c ファイルを探し、それを hello というプログラムに変換するコンパイラです。このコマンドの実行でエラーが発生しなかった場合は、先に進むことができます。エラーが出た場合は、コードを再確認して上記と一致していることを確認してください。

  • ここで ./hello と入力すると、プログラムが実行され、hello, world と表示されます。

  • 次に、左側のファイルエクスプローラーを開きます。hello.c というファイルと、hello という別のファイルの両方が存在することに気づくでしょう。hello.c はコンパイラによって読み取ることができ、コードが保存されている場所です。hello は実行可能なファイルで、実行することはできますが、コンパイラで読み取ることはできません。

ScratchからCへ

  • Scratchでは、「言う(say)」ブロックを使用して画面にテキストを表示しました。実際、Cにはこれとまったく同じことを行う printf という関数があります。

コードがすでにこの関数を呼び出していることに注目してください:

printf("hello, world\n");

printf 関数が呼び出されていることに注目してください。printf に渡される引数は hello, world\n です。コードの文(ステートメント)は ; で閉じられます。

コードのエラーはよくあることです。次のようにコードを修正してみてください:

// \n is missing

#include

int main(void)
{
    printf("hello, world");
}

\n がなくなっていることに注目してください。

  • ターミナルウィンドウで make hello を実行します。ターミナルウィンドウで ./hello と入力すると、プログラムはどのように変化しましたか?この \ 文字は「エスケープ文字」と呼ばれ、\n が改行を作成するための特別な命令であることをコンパイラに伝えます。

他にも使用できるエスケープ文字があります:

\n  新しい行を作成する(改行)
\r  行の先頭に戻る
\"  二重引用符を表示する
\'  単一引用符を表示する
\\  バックスラッシュを表示する

プログラムを次のように元に戻します:

// A program that says hello to the world

#include

int main(void)
{
    printf("hello, world\n");
}

セミコロンと \n が復元されていることに注目してください。

ヘッダーファイルとCS50マニュアルページ

  • コードの冒頭にあるステートメント #include <stdio.h> は、stdio.h という「ライブラリ」(ヘッダーファイル)の機能を使用したいことをコンパイラに伝える非常に特別なコマンドです。これにより、他の多くのことの中でも、printf 関数を利用できるようになります。

  • 「ライブラリ」とは、誰かによって作成されたコードの集合体です。ライブラリは、過去に他の人が書いた、自分のコードで利用できるあらかじめ書かれたコードや関数の集まりです。

  • このライブラリのすべての機能については、マニュアルページ(Manual Pages)で読むことができます。マニュアルページは、さまざまなコマンドが何を行い、どのように機能するかをよりよく理解するための手段を提供します。

CS50には cs50.h という独自のライブラリがあることがわかります。Cを使い始める際に「補助輪」として提供される多数の関数が含まれています。

get_char
get_double
get_float
get_int
get_long
get_string
  • このライブラリをプログラムで使用してみましょう。

こんにちは、あなた

  • Scratchでは、ユーザーに「お名前は?」と尋ね、その名前を添えて「hello」と言うことができたことを思い出してください。

Cでも同じことができます。次のようにコードを修正します。

// get_string and printf with incorrect placeholder

#include

int main(void)
{
    string answer = get_string("What's your name? ");
    printf("hello, answer\n");
}

get_string 関数は、ユーザーから文字列(string)を取得するために使用されます。次に、変数 answerprintf 関数に渡されます。

  • ターミナルウィンドウで再び make hello を実行すると、多数のエラーが表示されることに注目してください。

エラーを見ると、stringget_string がコンパイラに認識されていません。cs50.h というライブラリを追加して、コンパイラにこれらの機能を教える必要があります。また、answer が意図したとおりに提供されていないことにも気づきます。次のようにコードを修正します。

// get_string and printf with %s

#include
#include

int main(void)
{
    string answer = get_string("What's your name? ");
    printf("hello, %s\n", answer);
}

get_string 関数は、ユーザーから文字列を取得するために使用されます。次に、変数 answerprintf 関数に渡されます。%s は、string を受け取る準備をするよう printf 関数に伝えます。

  • ここで、ターミナルウィンドウで再び make hello を実行すると、./hello と入力してプログラムを実行できます。プログラムは名前を尋ね、意図したとおりに名前を付けて挨拶するようになります。

answer は私たちが「変数(variable)」と呼ぶ特別な保持場所です。answerstring 型であり、その中に任意の文字列を保持できます。intboolchar など、他にも多くのデータ型(data types)があります。

%s は「フォーマットコード(書式指定子)」と呼ばれるプレースホルダーで、string を受け取る準備をするよう printf 関数に伝えます。answer%s に渡される string です。

printf では多くのフォーマットコードを使用できます。このコースで使用する可能性のあるもののリスト(一部)を以下に示します:

%c
%f
%i
%li
%s

%sstring 変数に使用されます。%iint(整数)変数に使用されます。これについての詳細は マニュアルページ で確認できます。

これらのフォーマットコードは、Cで使用可能な多くのデータ型に対応しています:

bool
char
float
int
long
string
...

このコースを通じて、Cで使用可能な多くのデータ型を使用していきます。

条件分岐

  • Scratchで使用したもう一つの構成要素は「条件分岐」でした。例えば、xがyより大きい場合に一つのことを行いたい場合があります。さらに、その条件が満たされない場合に別のことを行いたい場合もあります。

  • Scratchの例をいくつか見てみましょう。

Cでは、次のように2つの値を比較できます。

// Conditionals that are mutually exclusive

if (x  y)
{
    printf("x is less than y\n");
}
else
{
    printf("x is not less than y\n");
}

x < y の場合に一つの結果が生じることに注目してください。xy より小さくない場合は、別の結果が生じます。

同様に、3つの考えられる結果を計画することもできます。

// Conditional that isn't necessary

if (x  y)
{
    printf("x is less than y\n");
}
else if (x > y)
{
    printf("x is greater than y\n");
}
else if (x == y)
{
    printf("x is equal to y\n");
}

これらのコード行すべてが必要なわけではないことに注目してください。上記の不要な計算をどのように排除できるでしょうか?

ご想像の通り、次のようにコードを改善できます。

// Compare integers

if (x  y)
{
    printf("x is less than y\n");
}
else if (x > y)
{
    printf("x is greater than y\n");
}
else
{
    printf("x is equal to y\n");
}

最後のステートメントが else に置き換えられていることに注目してください。

演算子

「演算子(Operators)」とは、コンパイラでサポートされている数学的演算を指します。Cでは、これらの数学演算子には以下が含まれます:

+:加算

-:減算

*:乗算

/:除算

%:剰余(余り)

このコースでは、これらすべての演算子を使用します。

変数

Cでは、次のように int(整数)に値を代入できます。

int counter = 0;

int 型の counter という変数に値 0 が代入されていることに注目してください。

Cでは、次のように counter に1を加算するようにプログラムすることもできます。

counter = counter + 1;

counter の値に 1 が加算されることに注目してください。

これは次のように表すこともできます:

counter += 1;

さらに次のように簡略化できます:

counter++;

++ が1を加算するために使用されていることに注目してください。

次のように counter から1を引くこともできます。

counter--;

counter の値から 1 が取り除かれることに注目してください。

compare.c

  • 変数に値を代入する方法についてのこの新しい知識を使用して、最初の条件文をプログラムできます。

ターミナルウィンドウに code compare.c と入力し、次のようにコードを書きます。

// Conditional, Boolean expression, relational operator

#include
#include

int main(void)
{
    // Prompt user for integers
    int x = get_int("What's x? ");
    int y = get_int("What's y? ");

    // Compare integers
    if (x  y)
    {
        printf("x is less than y\n");
    }
}

int(整数)型の xy という2つの変数を作成していることに注目してください。これらの値は get_int 関数を使用して取得されます。

  • ターミナルウィンドウで make compare を実行し、続いて ./compare を実行してコードを実行できます。エラーメッセージが表示された場合は、コードに間違いがないか確認してください。

「フローチャート」は、コンピュータプログラムがどのように機能するかを調べる方法です。このようなチャートを使用して、コードの効率性を調べることができます。

  • 上記のコードのフローチャートを見ると、いくつかの不備に気づくことができます。

次のようにコーディングすることで、プログラムを改善できます。

// Conditionals

#include
#include

int main(void)
{
    // Prompt user for integers
    int x = get_int("What's x? ");
    int y = get_int("What's y? ");

    // Compare integers
    if (x  y)
    {
        printf("x is less than y\n");
    }
    else if (x > y)
    {
        printf("x is greater than y\n");
    }
    else
    {
        printf("x is equal to y\n");
    }
}

考えられるすべての結果が考慮されていることに注目してください。

  • プログラムを再作成して再実行し、テストすることができます。

  • フローチャートでこのプログラムを調べると、コード設計の決定の効率性を確認できます。

agree.c

  • char と呼ばれる別のデータ型を考慮して、ターミナルウィンドウに code agree.c と入力して新しいプログラムを開始できます。

  • string が一連の文字であるのに対し、char は単一の文字です。

テキストエディタで、次のようにコードを書きます。

// Comparing against lowercase char

#include
#include

int main(void)
{
    // Prompt user to agree
    char c = get_char("Do you agree? ");

    // Check whether agreed
    if (c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'n')
    {
        printf("Not agreed.\n");
    }
}

単一の文字には単一引用符(’)が使用されていることに注目してください。さらに、== は何かが他の何かと「等しい」ことを確認するものであり、単一の等号(=)はCにおいて非常に異なる機能(代入)を持つことに注意してください。

  • ターミナルウィンドウに make agree と入力し、続いて ./agree と入力してコードをテストできます。

大文字と小文字の入力も許可するようにできます。

// Comparing against lowercase and uppercase char

#include
#include

int main(void)
{
    // Prompt user to agree
    char c = get_char("Do you agree? ");

    // Check whether agreed
    if (c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'Y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'n')
    {
        printf("Not agreed.\n");
    }
    else if (c == 'N')
    {
        printf("Not agreed.\n");
    }
}

追加のオプションが提供されていることに注目してください。しかし、これは効率的なコードではありません。

次のようにコードを改善できます。

// Logical operators

#include
#include

int main(void)
{
    // Prompt user to agree
    char c = get_char("Do you agree? ");

    // Check whether agreed
    if (c == 'Y' || c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'N' || c == 'n')
    {
        printf("Not agreed.\n");
    }
}

|| が事実上「または(or)」を意味することに注目してください。

ループと meow.c

  • Scratchのループ構成要素をCプログラムでも利用できます。

ターミナルウィンドウに code meow.c と入力し、次のようにコードを書きます。

// Opportunity for better design

#include

int main(void)
{
    printf("meow\n");
    printf("meow\n");
    printf("meow\n");
}

これは意図したとおりに機能しますが、より良い設計にする余地があることに注目してください。コードが何度も繰り返されています。

次のようにコードを修正することで、プログラムを改善できます。

// Better design

#include

int main(void)
{
    int i = 3;
    while (i > 0)
    {
        printf("meow\n");
        i--;
    }
}

i という int を作成し、値 3 を代入していることに注目してください。次に、i > 0 である限り実行される while ループを作成します。その後、ループが実行されます。ループが実行されるたびに、i-- ステートメントを使用して i から 1 が減算されます。

同様に、次のようにコードを修正して、一種のカウントアップを実装できます。

// Print values of i

#include

int main(void)
{
    int i = 1;
    while (i  3)
    {
        printf("meow\n");
        i++;
    }
}

カウンター i1 から開始されていることに注目してください。ループが実行されるたびに、カウンターが 1 ずつ増加します。カウンターが 3 を超えると、ループは停止します。

一般的に、コンピュータサイエンスではゼロから数えます。次のようにコードを修正するのが最善です。

// Better design

#include

int main(void)
{
    int i = 0;
    while (i  3)
    {
        printf("meow\n");
        i++;
    }
}

ゼロから数えるようになったことに注目してください。

  • ループのためのもう一つのツールは for ループです。

for ループを使用して、meow.c プログラムの設計をさらに改善できます。次のようにコードを修正します。

// Better design

#include

int main(void)
{
    for (int i = 0; i  3; i++)
    {
        printf("meow\n");
    }
}

for ループには3つの引数が含まれていることに注目してください。最初の引数 int i = 0 は、カウンターをゼロから開始します。2番目の引数 i < 3 は、チェックされている条件です。最後に、引数 i++ は、ループが実行されるたびに1ずつ増加するようにループに伝えます。

次のコードを使用して、永久にループさせることもできます。

// Infinite loop

#include
#include

int main(void)
{
    while (true)
    {
        printf("meow\n");
    }
}

true は常に真であることに注目してください。したがって、コードは常に実行されます。このコードを実行すると、ターミナルウィンドウの制御ができなくなります。キーボードの control-C を押すことで、無限ループから抜け出すことができます。

関数

後で詳しく説明しますが、次のようにCで独自の関数を作成できます。

void meow(void)
{
    printf("meow\n");
}

最初の void は、関数が値を返さないことを意味します。括弧内の (void) は、関数に値が提供されないことを意味します。

この関数は、次のようにメイン関数(main function)で使用できます。

// Abstraction

#include

void meow(void);

int main(void)
{
    for (int i = 0; i  3; i++)
    {
        meow();
    }
}

// Meow once
void meow(void)
{
    printf("meow\n");
}

meow() という命令で meow 関数が呼び出されていることに注目してください。これが可能なのは、meow 関数がコードの下部で定義されており、関数の「プロトタイプ(prototype)」がコードの上部に void meow(void) として提供されているためです。

meow 関数をさらに入力を受け付けるように修正できます。

// Abstraction with parameterization

#include

void meow(int n);

int main(void)
{
    meow(3);
}

// Meow some number of times
void meow(int n)
{
    for (int i = 0; i  n; i++)
    {
        printf("meow\n");
    }
}

プロトタイプが void meow(int n) に変更され、meow が入力として int を受け入れることを示していることに注目してください。

さらに、ユーザー入力を取得することもできます。

// User input

#include
#include

void meow(int n);

int main(void)
{
    int n;
    do
    {
        n = get_int("Number: ");
    }
    while (n  1);
    meow(n);
}

// Meow some number of times
void meow(int n)
{
    for (int i = 0; i  n; i++)
    {
        printf("meow\n");
    }
}

get_int がユーザーから数値を取得するために使用されていることに注目してください。nmeow に渡されます。

ユーザーから提供された入力が正しいことを確認するテストを行うこともできます。

// Return value

#include
#include

int get_positive_int(void);
void meow(int n);

int main(void)
{
    int n = get_positive_int();
    meow(n);
}

// Get number of meows
int get_positive_int(void)
{
    int n;
    do
    {
        n = get_int("Number: ");
    }
    while (n  1);
    return n;
}

// Meow some number of times
void meow(int n)
{
    for (int i = 0; i  n; i++)
    {
        printf("meow\n");
    }
}

get_positive_int という新しい関数が、n < 1 である間ユーザーに整数を求めていることに注目してください。正の整数を取得した後、この関数は return n によって値を main 関数に返します。

正確性、設計、スタイル

  • コードは3つの軸で評価できます。

  • 第一に、「正確性(correctness)」とは「コードは意図したとおりに動作するか?」を指します。コードの正確性は check50 で確認できます。

  • 第二に、「設計(design)」とは「コードはどの程度うまく設計されているか?」を指します。コードの設計は design50 を使用して評価できます。

  • 最後に、「スタイル(style)」とは「コードは審美的に美しく、一貫性があるか?」を指します。コードのスタイルは style50 で評価できます。

Mario

  • 今日話し合ったすべてのことは、新進気鋭のコンピュータ科学者としてのあなたの仕事のさまざまな構成要素に焦点を当ててきました。

  • 以下は、一般的にこのクラスの問題セットに取り組むための方向性を定めるのに役立ちます。コンピュータサイエンス関連の問題にどのようにアプローチすればよいでしょうか?

ゲーム「スーパーマリオブラザーズ」のビジュアルをエミュレートしたいと想像してください。写真にある4つのハテナブロックを考えて、これら4つの水平なブロックを大まかに表すコードをどのように作成できるでしょうか?

ターミナルウィンドウに code mario.c と入力し、次のようにコードを書きます。

// Prints a row of 4 question marks with a loop

#include

int main(void)
{
    for (int i = 0; i  4; i++)
    {
        printf("?");
    }
    printf("\n");
}

ループを使用してここで4つの疑問符がどのように印刷されるかに注目してください。

同様に、この同じロジックを適用して3つの垂直ブロックを作成できます。

これを実現するには、次のようにコードを修正します。

// Prints a column of 3 bricks with a loop

#include

int main(void)
{
    for (int i = 0; i  3; i++)
    {
        printf("#\n");
    }
}

ループを使用して3つの垂直なレンガがどのように印刷されるかに注目してください。

これらのアイデアを組み合わせて、3×3のブロックのグループを作成したい場合はどうすればよいでしょうか?

同じアイデアを組み合わせて、上記のロジックに従うことができます。次のようにコードを修正します。

// Prints a 3-by-3 grid of bricks with nested loops

#include

int main(void)
{
    for (int i = 0; i  3; i++)
    {
        for (int j = 0; j  3; j++)
        {
            printf("#");
        }
        printf("\n");
    }
}

一方のループがもう一方のループの中にある(ネストされている)ことに注目してください。最初のループは、どの垂直行が印刷されるかを定義します。各行について、3つの列が印刷されます。各行の後、新しい行(改行)が印刷されます。

ブロックの数を「定数(constant)」、つまり変更不可にしたい場合はどうすればよいでしょうか?次のようにコードを修正します。

// Prints a 3-by-3 grid of bricks with nested loops using a constant

#include

int main(void)
{
    const int n = 3;
    for (int i = 0; i  n; i++)
    {
        for (int j = 0; j  n; j++)
        {
            printf("#");
        }
        printf("\n");
    }
}

n が定数になったことに注目してください。これは決して変更できません。

この講義の前半で示したように、機能を関数へと「抽象化」することができます。次のコードを考えてみましょう。

// Helper function

#include

void print_row(int width);

int main(void)
{
    const int n = 3;
    for (int i = 0; i  n; i++)
    {
        print_row(n);
    }
}

void print_row(int width)
{
    for (int i = 0; i  width; i++)
    {
        printf("#");
    }
    printf("\n");
}

行の印刷が新しい関数を通じてどのように達成されるかに注目してください。

コメント

  • 「コメント」はコンピュータプログラムの基本的な部分であり、自分自身や、あなたのコードに関してあなたと協力している可能性のある他の人に対して、説明的な備考を残します。

  • このコースで作成するすべてのコードには、しっかりとしたコメントを含める必要があります。

  • 通常、各コメントは数語以上で、読者が特定のコードブロックで何が起きているかを理解する機会を提供します。さらに、そのようなコメントは、後でコードを修正する必要があるときの備忘録としても役立ちます。

コメントには、コード内に // を配置し、その後にコメントを記述します。次のようにコードを修正して、コメントを統合します。

// Helper function

#include

void print_row(int width);

int main(void)
{
    const int n = 3;

    // Print n rows
    for (int i = 0; i  n; i++)
    {
        print_row(n);
    }
}

void print_row(int width)
{
    for (int i = 0; i  width; i++)
    {
        printf("#");
    }
    printf("\n");
}

各コメントが // で始まっていることに注目してください。

演算子についてさらに詳しく

Cで計算機を実装できます。ターミナルで code calculator.c と入力し、次のようにコードを書きます。

// Addition with int

#include
#include

int main(void)
{
    // Prompt user for x
    int x = get_int("x: ");

    // Prompt user for y
    int y = get_int("y: ");

    // Add numbers
    int z = x + y;

    // Perform addition
    printf("%i\n", z);
}

get_int 関数を使用してユーザーから整数を2回取得していることに注目してください。一方の整数は x という int 変数に格納されます。もう一方は y という int 変数に格納されます。合計は z に格納されます。次に、printf 関数が %i シンボルで指定された z の値を出力します。

数値を2倍にすることもできます。

// int

#include
#include

int main(void)
{
    int dollars = 1;
    while (true)
    {
        char c = get_char("Here's $%i. Double it and give to next person? ", dollars);
        if (c == 'y')
        {
            dollars *= 2;
        }
        else
        {
            break;
        }
    }
    printf("Here's $%i.\n", dollars);
}

このプログラムを実行すると、dollars にいくつかの不具合と思われるエラーが現れます。なぜでしょうか?

  • Cの短所の一つは、メモリ管理が容易である反面、その管理に注意が必要なことです。Cはメモリの使用方法を高度に制御できますが、プログラマはメモリ管理の潜在的な落とし穴を非常に意識しなければなりません。

  • 「型」とは、変数に格納できる可能なデータを指します。例えば、chara2 のような単一の文字を収容するように設計されています。

  • 型は非常に重要です。なぜなら、各型には特定の制限があるからです。例えば、メモリの制限により、int の最大値は 4294967295 になることがあります。int をこれより大きくカウントしようとすると、「整数オーバーフロー(integer overflow)」が発生し、誤った値がこの変数に格納されます。

  • ビット数によって、どれだけ高く、あるいは低く数えられるかが制限されます。

  • これは悲劇的な現実世界の影響を及ぼす可能性があります。

これを long というデータ型を使用することで修正できます。

// long

#include
#include

int main(void)
{
    long dollars = 1;
    while (true)
    {
        char c = get_char("Here's $%li. Double it and give to next person? ", dollars);
        if (c == 'y')
        {
            dollars *= 2;
        }
        else
        {
            break;
        }
    }
    printf("Here's $%li.\n", dollars);
}

このコードを実行すると、非常に高額なドルの金額を扱えるようになることに注目してください。

このコースで接する可能性のある型には、以下のものがあります:

bool:真(true)または偽(false)のいずれかを表すブール式

char:aや2のような単一の文字

double:floatよりも桁数が多い浮動小数点値

float:浮動小数点値、または小数点を持つ実数

int:特定のサイズまたはビット数までの整数

long:より多くのビットを持つ整数(intよりも高く数えられる)

string:文字の列(文字列)

切り捨て

データ型を使用するときに発生する可能性のある別の問題には、「切り捨て(truncation)」があります。

// Division with ints, demonstrating truncation

#include
#include

int main(void)
{
    // Prompt user for x
    int x = get_int("x: ");

    // Prompt user for y
    int y = get_int("y: ");

    // Divide x by y
    printf("%i\n", x / y);
}

Cにおいて、整数を整数で割ると、結果は常に整数になります。したがって、上記のコードでは、小数点以下の数字が切り捨てられて(捨てられて)しまうことがよくあります。

これは float を採用することで解決できます。

// Floats

#include
#include

int main(void)
{
    // Prompt user for x
    float x = get_float("x: ");

    // Prompt user for y
    float y = get_float("y: ");

    // Divide x by y
    printf("%.50f\n", x / y);
}

これが問題の一部を解決することに注目してください。しかし、プログラムによって提供される回答に不正確さが生じることに気づくかもしれません。

「浮動小数点演算の精度不足(Floating point imprecision)」は、コンピュータがいかに正確に数値を計算できるかに限界があることを示しています。

  • コーディングの際は、コード内の問題を避けるために、使用している変数の型に特別な注意を払ってください。

  • 型に関連したエラーによって発生する可能性のある災害の例をいくつか検討しました。

まとめ

このレッスンでは、Scratchで学んだ構成要素をCプログラミング言語に適用する方法を学びました。学んだことは…

  • Cで最初のプログラムを作成する方法。

  • コマンドラインの使用方法。

  • Cにネイティブに備わっている定義済みの関数について。

  • 変数、条件分岐、ループの使用方法。

  • コードを簡素化し改善するために独自の関数を作成する方法。

  • 正確性、設計、スタイルの3つの軸でコードを評価する方法。

  • コードにコメントを統合する方法。

  • 型と演算子を活用する方法と、その選択がもたらす意味について。

それでは、また次回!