米ハーバード大学のコンピューターサイエンス講座を受講し始めてから早いものでもう2週目。大学時代に闇雲に覚えさせられた色々な構文には様々な意味があった(当然!)ことが分かり、今回はきちんと脳に定着しそうな気がする。授業の進むスピードは比較的速く、高速「アハ体験」を連続してできている感覚がする。せっかくだから、学んだ内容とそれに対する僕の感想も添えて自分用のノートをまとめる代わりに記事を更新していこうと思う。動画の後半には、我らが任天堂ゲームの代表作、スーパーマリオブラザーズを使ってどうやってゲームは作られているのか簡単に触れており、最近のゲーム開発のプログラムがどう設計されているのか知れて面白かった。
CS50第2回目の講義「C言語」
C(正確性 × デザイン × スタイル)
まずは、プログラムを書く上での重要なこと3つ「正確性 × デザイン × スタイル」。大学時代と違い、かなり細かく改行や{}(括弧)の位置を指定するというのが正直な感想。ここまで統一した方が確かに気持ちが良い。
- Correctness(正確性), or whether our code works correctly, as intended
- Design(デザイン), or a subjective measure of how well-written our code is, based on how efficient it is and how elegant or logically readable it is, without unnecessary repetition
- Style(スタイル), or how aesthetically formatted our code is, in terms of consistent indentation and other placement of symbols. Differences in style don’t affect the correctness or meaning of our code, but affect how readable it is visually
CS50 IDE(開発環境)
この講義ではクラウド上に開発環境(CS50 IDE)提供してくれている。ちなみに、IDEは integrated development environment の略。CS50 IDEにアクセスすると以下のスクリーンショットの画面が現れ、上半分にソースコードを、下半分がターミナルになっている。

Compiling(コンパイル)
人間が書いたプログラム(ソースコード)を、コンピューターが読める言語に変換する作業をコンパイルというが、これも簡単にコマンドラインからできるようになっている。

Functions and arguments(関数と引数)
Functions とは、プログラムの中で使用できる小さなアクションや動詞のこと。Arguments は、Functions に対する input (インプット)を意味する。
CS50 専用の Library(ライブラリー)も用意されていて、get_string
は文字列を取得するための関数。
// ask the user for a string (or some sequence of text)
string answer = get_string("What's your name? ");
これを使った構文は次の通り。
#include <cs50.h>
#include <stdio.h>
int main(void)
{
string answer = get_string("What's your name? ");
printf("hello, %s", answer);
}
main, header files(メイン、ヘッダーファイル)
main
とは、int main (void)
の括弧の中身を指す。header files
は、プログラムの冒頭で宣言する .h
ファイルで、ライブラリーをこのプログラムで使用することを宣言している。例えば、#include <stdio.h>
は、standard input/output library であり、ここにはよく使用するprintf
関数が含まれている。
Tools(ツール、これすごい!)
プログラムを書いているとお世辞にも分かりやすいとは言えないコンパイルエラーメッセージに苦戦することがある。そのエラーメッセージが理解できず、プログラムのどこが間違っているのか特定できずに何時間も経っている、そんな経験は皆さんにもあるのではないだろうか?そこで、CS50 IDE環境では、help50
というコンパイルエラーメッセージを解析して分かりやすい英語に変換してくれるツールが用意されている。これはすごい助かる気がする!
help50 make hello
で結果を返してくれる。helloはコンパイルを実行したいプログラム名。

さらには、style50
というプログラムのスタイルをチェックしてくれるツールも用意されている!自己満で終わっていたプログラムのスタイルは、厳しく精査されることになる。これは助かる。昔教授に良く質問をしていたことを思い出した。style50 hello.c
で実行可能。

さらにさらに、check50
という正確性をテストするツールも用意されている!10年前にも欲しかった。check50 hello.c
で実行可能。課題を提出する前に簡単にチェックできるのは大変有り難い。この3つのツールは自習する上でかなり役に立つはずだ。

Commands(コマンド)
CS50 IDEは、クラウド上のバーチャルコンピュータなので、コマンドを実行することもできる。以下、授業中に紹介されたコマンド。
~/$ ls
hello* hello.c
//lists the contents
~/ $ ls
// executable file is expressed with *
~/ $ hello*
// remove a file
~/ $ rm hello
// move a file or rename a file
~/ $ mv hello.c goodbye.c
// create folders or directories
~/ $ mkdir lecture
// change directory
~/ $ cd lecture/
// in lecture directory
~/lecture/ $
// change to parent folder (single . refers to current directory)
~/ $ cd ..
// move the file to the folder above (parent directory)
~/ $ mv hello.c ..
// remove directory
~/ $ rmdir lecture/
// copy files and folders
~/ $ cp
Types, format codes(型宣言、Placeholder等)
- C言語で使用するデータ型の紹介:
bool
, a Boolean expression of eithertrue
orfalse
char
, a single ASCII character likea
or2
double
, a floating-point value with more digits than afloat
float
, a floating-point value, or real number with a decimal valueint
, integers up to a certain size, or number of bitslong
, integers with more bits, so they can count higher than anint
string
, a string of characters
- CS50 の library はデータ型取得するためのライブラリーを用意している:
get_char
get_double
get_float
get_int
get_long
get_string
printf
で使用する placeholders 各種:%c
for chars%f
for floats, doubles%i
for ints%li
for longs%s
for strings
Operators, limitations, truncation(演算子、限界、切り捨て)
- 四則演算を行うためのオペレーター:
+
足し算-
引き算*
掛け算/
割り算%
余り
- 足し算をするためのプログラムを作ってみると以下のようになる
- ヘッダーファイルで
get_int
を使用するためにCS50 libraryを読み込み、x
とy
に読み込み printf
で placeholder を使って型を指定する- 32 bitsの限度:int 型は約4 billionしか使えないかつプラスマイナスを考慮するとその半分の領域しかない
- ヘッダーファイルで
#include <cs50.h>
#include <stdio.h>
int main(void)
{
int x = get_int("x: ");
int y = get_int("y: ");
printf("%i\n", x + y);
}
それを解決するために long
型に変えることも可能
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long x = get_long("x: ");
long y = get_long("y: ");
printf("%li\n", x + y);
}
最後にもう一つ
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Get numbers from user
int x = get_int("x: ");
int y = get_int("y: ");
// Divide x by y
float z = x / y;
printf("%f\n", z);
}
- ’
x
をy
で割った値をz
に代入するというシンプルなプログラムだが、整数を整数で割った後に小数点が発生しているが、整数型を使用しているため小数点以下が切り落とされ0.000000
や1.000000
と表示されてしまう。 - これを直すためには割り算をする前にキャスト(変換)してあげれば良い。
float z = (float) x / (float) y;
Variables, syntactic sugar(変数、糖衣構文)
- 変数への初期化(値の設定)
int counter = 0;
、カウンターの作成(1ずつ増える)counter = counter + 1
その簡単な表記の仕方counter += 1;
やcounter++;
があり、これを糖衣構文と呼ぶ。 - 糖衣構文とは、プログラミング言語において、複雑でわかりにくい書き方と全く同じ意味になるものをよりシンプルでわかりやすい書き方で書くことができるもののことである。
Conditions(条件分岐)
もし X が Y だったら、Zを実行するといったプログラム。
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Prompt user for x
int x = get_int("x: ");
// Prompt user for y
int y = get_int("y: ");
// Compare x and y
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");
}
}
ユーザーに同意するかを問いかけ、その結果によって表示内容を変えるというプログラム
#include <cs50.h>
#include <stdio.h>
int main(void)
{
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(どちらかが True
正しい), &&
は、AND(両方とも True
正しい)
Boolean expressions, loops(ブーリアン演算、ループ)
while
は、〜する間という意味なので、以下のプログラムでは、ずっとプログラムを走り続けさせる(無限ループ)場合は、ブーリアン演算を使って True
とする
while (true)
{
printf("hello world\n")
}
ある一定回数プログラムを回す場合は、条件を与えてあげればいい
int i = 0;
while (i < 50)
{
printf("hello, world\n");
i++;
}
i
を0にセットし、50になるまでカウンターを使って制御している。
for (int i = 0; i < 50; i++)
{
printf("hello, world\n");
}
最もよく使われるのが for
文。
Abstraction(抽象化)
ここでは、プログラムを function を使って複雑になりがちなプログラムを軽減するために、効率的に書くことを習う。ただ、そこでの注意点がScope(スコープ)。型宣言の対象範囲に注意する必要がある。
#include <cs50.h>
#include <stdio.h>
int get_positive_int(void);
int main(void)
{
int i = get_positive_int();
printf("%i\n", i);
}
// Prompt user for positive integer
int get_positive_int(void)
{
int n;
do
{
n = get_int("Positive Integer: ");
}
while (n < 1);
return n;
}
この例では、get_positive_int(void)
の中で宣言している int n;
に注目して欲しい。do
文の前に宣言しているが、これは do
文の後にも使用しないといけないからである。do
文の中で宣言してしまうとその中でしか使えない。
Mario(スーパーマリオブラザーズ!)
「さて、このプログラムどうやって書く?」って「え、いきなり難しすぎないか?」と思ったが、実際は一部分のプログラム。

このはてな「?」をどうやってプログラムをするか、ということだった。昔はハードコード可能性はあるが、最近のゲームは動的に書いているらしい。

これをC言語で表すと次のようになる。
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 4; i++)
{
printf("?");
}
printf("\n");
}
仮に、ユーザーから「?」の長さを受け取るとすると、
#include <cs50.h>
#include <stdio.h>
int main(void)
{
// Get positive integer from user
int n;
do
{
n = get_int("Width: ");
}
while (n < 1);
// Print out that many question marks
for (int i = 0; i < n; i++)
{
printf("?");
}
printf("\n");
}
そして、今度は以下のブロックを作ることを考える。

C言語で記述すると、for
文の中に for
文を書くことで立体にすることができる。
#include <cs50.h>
#include <stdio.h>
int main(void)
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("#");
}
printf("\n");
}
}
Memory, imprecision, and overflow
コンピュータに積まれたメモリ(RAM)について、それは有限である。使用可能な領域を超えると、floating-point imprecisionという現象が起きる。
#include <cs50.h>
#include <stdio.h>
int main(void)
{
float x = get_float("x: ");
float y = get_float("y: ");
printf("%.50f\n", x / y);
}
x: 1
y: 10
0.10000000149011611938476562500000000000000000000000
結果は、数学的には正しくない。
仮に3ビットで111(8)に1を足すと1000(9)になる。よって、3ビットの領域では、1は枠外のため、000が残る。これが、integer overflow。
感想
第1回目の講義「C言語」の動画を見終えての感想は基本の復習は大事ということと、やはり何度も見直せるオンライン動画はどの学習にも向いている気がする。まだ基本だからそこまで動画を繰り返し見ることはないが、これからは増える気がしている。分からないところは何度も何度も見直せる、良い時代になったもんだ。
未希 諒
Related posts
About media
Ramps Blog は、ノマドによるノマドのためのブログです。日本、香港、シンガポール、タイ、台湾のノマド生活を通じて見えた景色、特に食、カルチャー、テクノロジー、ビジネス、アート、デザインなどについて発信しています。
Recent Posts
Twitter feed is not available at the moment.