🎓

現役エンジニアが CS50 をさらっと見た感想

2024/11/28に公開

経緯と背景

  • 大学で CS を学んでいない状態でエンジニアになった人です
  • 恥は全方向に晒していくスタイル
  • now in android を読みながら、「やってることはわかる!なるほど!ただ、こういう書き方ってそもそもどうやったら思いつくんや?」と思った[1]
  • 日頃から新しい技術へのキャッチアップが遅い、効率が悪いと感じていて
  • いつか外資やメガベンに挑戦するかもしれない!と思って始めた leetcode の進捗も芳しくない
  • モヤモヤを晴らすため興味本位で入っていた Android の Discord コミュニティで「kotlin coroutine のリファレンス読めるけど、これ実装に落とす時の発想ってどこから湧くの?あと、リファレンスをもっと早く読みたいんだけどどうしたらいいかね?」と聞いてみた[2]
  • 自分語りとお気持ち表明は置いといて、CS50 みてから、C か C++ やってみなよと言われた[3]
  • とはいえこれまで揉まれてきたし CS50くらいは片手間で全部見れるわ!と意気込んで見てみました
  • あと、あえて[4] 全ての Lecture をこの記事にまとめてます

目的

  • C, C++ を学ぶための一歩目にすること
    • データ構造、アルゴリズムを体に染み込ませること
  • C を学んだことで学習速度や技術のキャッチアップ速度が加速していくことを体験する
  • 急がば回れを知ること?
    • discord でアドバイスくれてフレンド申請してくれたアメリカ人エンジニアに言われた

結論・全部見て思ったこと

  • 新しい学びが沢山あったわけではないが、良い復習になった
  • 案の定、後半に行くにつれて目的と内容が合致しないのでダレた
  • 非エンジニアやエンジニアを目指す人がメモリとプログラムの関係性を理解したり、アルゴリズムやデータ構造がなぜ存在するのか?を理解する一歩目にはうってつけだと思った
    • とはいえ難しいとは思う
    • でも現状、数年間の間で見てきたどんな説明よりもわかりやすいことに違いはない
  • エンジニアの発想の再学習ができた
    • プロダクトで問題を解決するためには「やりたいことのために使う道具でできること」をできうる限り知る必要があって、それを「自分の手に馴染むまで使ってみなければいけない」を再確認した

CS50x 2024 - Lecture 0 - Scratch

感想

  • めっちゃ面白い、自分が学生時代にこんな授業なら絶対受けてみたいと思えるものだった
  • 日本で受けたどの授業よりも面白い
  • お金がなせる技なんだろうけど

講義の内容

  • 2進数の導入
    • 5本の指があれば 32 まで数えられるよねとかそういう話し
    • ボランティア出して楽しくやるのいいね
  • ASCII Code
    • A ~ Z, a ~ z のような文字や ! を含む文字は全て数字で管理されているんだよって話
    • たとえば A は 65
    • man ascii ってコマンド打てば terminal で見れるよ
  • Unicode
    • ASCII Code のスーパーセット
      • ASCII Code が含んでいない絵文字なんかは Unicode が管理しているよ
      • 2進数法海を前提として、16進数、1バイトの話が一部あった
    • rgb の話
      • 一色あたり 1バイトで表現するよって話
      • つまり、1ピクセルあたり3バイトの情報量があるよって話
      • ピクセルの数が増えれば増えるほどより発色の良いディスプレイになるねって話
  • アルゴリズム
    • バイナリーサーチに繋がる話
      • 実際に電話帳破りながらやるのわかりやすいね
      • 時間計算量の話し
  • ちょっとプログラムの話
  • Scratch の話し
    • これで遊べるのはアドバンテージだよなあ

CS50x 2024 - Lecture 1 - C

感想

  • 全体を通して初回の Scrach の内容と被るような説明をしてくれている
  • 初学者なら非常に理解がしやすく、かつ記憶に残りやすい教え方だよなと思った

講義の内容

  • Machine Code

    • C言語で hello, world を出力するプログラムと Scrach でやった内容を一対一でどの機能がどの記述に該当しているかを説明
    • 高級言語(C言語)の説明とコンパイルの説明
  • Function の説明

    • input を処理して output を出す原則の復習
  • VSCode

  • Hello, World

    • コンパイルコマンドの説明
      • cc とか gcc ではなくて、CS50 用の拡張機能があるからそれを落とすと make コマンドでコンパイルしてくれるよ
    • 文法の基本的な説明
    • 文字列リテラルを表示するにはバックスラッシュをつけようね
  • CS50 Library

    • 便利なライブラリを作ってくれているんだね
    • https://manual.cs50.io/
    • get_string 関数とかの説明
  • Format Codes

  • Hello, world

    • syntax highlight の説明とか
    • 標準入力を受け取って標準出力するプログラムを作成
    • string は C にない型だが CS50 ライブラリで使えるようにしてる
  • Types

    • 型の紹介
  • Conditionals

    • if-else で無駄な計算をさせないようにしようねって話し
  • Variables

    • インクリメント、ディクリメンとの説明
  • compare.c

    • (mermaid でフロー書くんだ)
      • また if-else で無駄なフローを増やさないようにしようねという話し
  • agree.c

    • Char の使い方、シングルクオートなど
    • if-else の ||, && の使い方
  • Loops

    • while
      • 基本的な文法とインクリメントするかディクリメントするかなど
      • 無限ループの説明
    • for
      • 基本的な文法の説明
      • C 言語特有のメソッド定義した場合は main 関数より先に書くか、関数名を先に定義するか?の話
    • do-while
      • 基本的な文法の説明
  • Functions

    • 変数のスコープの話
      • ローカル変数の説明
  • Function Composition

    • main関数に int つけてるけど return してなくない?
      • デフォルトで 0 かえしてるよ
  • Linux

    • 基本的なコマンドの説明
  • Mario

    • Loops や関数の復習
    • 2重ループはあえてここで見せているんだろうな
  • Integer Overflow

    • たとえば 3ビットで数をカウントするカウンターがあったとして、8を超えると「1000」になってしまって 0 になっちゃうぞって話し
    • 32 bit なら 20億くらいまで負の数を考慮して扱える
    • 64 bit なら 2^64/2 の範囲の数を負の数を考慮して扱えるね
  • Truncation

    • int 同士の除算は int 同士で計算されてしまうので、float(32bit) または double(64bit) にキャストしようね
  • floating-point imprecision

    • float にキャストしても 10/3 の計算結果は完全な循環小数にならないから注意
    • double にキャストしても完全にはならないので浮動小数点には注意しようね
      • あんまり実務でここにぶつかったことないんだよな
  • Y2K

    • 1900 年代のみ考慮して 2bit で年を扱ったらえらいことになってしまったね
    • 2000 年が 1900 年になっちゃうね問題
  • Video Games

    • パックマン
      • レベルの概念に4bit の数字を使っていたのでカンストしたら 0 に戻っちゃった
    • ドンキーコング
      • ステージの時間ロジックに使っていた数字がこれまた 4bit だったので 255 を超えた瞬間にバグった
    • ボーイング787
      • 248日間連続して給油された機体がそれ以降給油されると全てのシステムが起動停止する?問題

英語で読んでるので所々ミスってるかもしれないけど、大体言っていることはこんな感じでした。

CS50x 2024 - Lecture 2 - Arrays

感想

  • わかりやすすぎだろこれ

講義の内容

  • Story Time
  • Compiling
    • コンパイルの説明
    • source code --> copiler --> machine code
    • make コマンドは実際は以下のシェルスクリプト
    • clang -o hellw hello.c -lcs50
    • -l が リンクを意味しており、これで cs50 に接続できているので get_string が参照できる
    • clang を実行するときに起こること4つ
      • preprocessing
        • include があったとき、対象のファイルのコードをコピペしている
        • 実際、include <stdio.h> は以下のようなプロトタイプと同等であると思って良い
          • int printf(string format, ...); と書いているのと同じだと思って良い
      • compiling
        • アセンブリ言語に翻訳する過程
        • まだマシンコードではない
      • assembling
        • 0,1 へ変換する
      • linking
        • 3つの異なるファイルがコンパイルに関係しているため、これらを統合する必要がある
        • 3つ(hello.c, stdio.h, cs50)の 0,1 コードの集合体全てをリンクしたファイルを作成する必要がある
    • reverse engineering
  • Debugging
    • print debug
    • デバッガの説明
      • ステップ実行とかの話だね
    • ラバーダックね、猫に話しかける方が好き
  • Memory
    • bool: 1byte
    • int: 4byte
    • long: 8byte
    • float: 4byte
    • double: 8byte
    • char: 1byte
    • string: ?byte (mutableなので)
  • scores.c
    • 計算式に一つでも浮動小数点を表す数が含まれていれば計算結果は float になる
    • グリッドでメモリを表すのが視覚的に非常にわかりやすい、これ紙でやってた
    • 変数の数がめっちゃ増えたらどうするの?書きまくるの?を伏線にして Array へ話を繋げていく
  • Array
    • int scores[3] int * 3 つ分のメモリ領域を確保してくれる
    • つまり 12byte分の領域を確保してくれる
    • scores[0] = 10 のように初期化する
  • Strings
    • どうやって strings の最後の文字を検知するか?
      • End of String == \0 が最後の要素として存在するから
    • 実際に EOF を出力すると、0 が出力される
    • EOF == NUL でもある、文字列の終わりを意味する
      • ASCII Code だと 0 に該当する
  • String length
  • uppercase
    • A, a の組は 32 離れているので、この演算をすればロワーケースをアッパーケースへ
    • アッパーケースをロワーケースへ変更できる
    • ctype.h を使えば、toupper, tolower 使えるね
  • command line arguments
    • コマンドライン引数を出力しただけやな
  • Cowsay
  • Exit Status
  • cryptography

CS50x 2024 - Lecture 3 - Algorithms

感想

  • leetcode のグラフ問題は初見で詰んだので、何かヒントが得られたら嬉しいなってお気持ちで見る
  • ソートアルゴリズムの話だけだった

講義の内容

  • Algorithms
    • 計算量の話
    • バイナリーサーチっぽい話
  • Linear Search
    • メモリの話
      • メモリは巨大な一列ロッカーだよね、の話
    • バイナリーサーチ
      • ソートして、2分割して探そうね
  • Binary Search
  • Running Time
    • 対数グラフの話
    • 時間計算量もそうだけど、空間計算量も考慮しないとね
    • ビッグオー記法
    • シータ記法とかもあるんだよね
  • search.c
    • string は整数の比較方法とは異なるので、string.h をインポートして、strcmp 関数を使う必要がある
    • Java は equal 関数、kotlin は == 演算子で比較できるね
  • phonebook.c
  • Struct
    • なるほどねえ、phonebook で伏線を作って型の話へ持っていくんだねえ
    • お名前とお電話番号を分けるのは不自然だね、それらを統合するにはどうする?って話から型へ話を持っていく
    • typedef struct
      {
          string name;
          string number;
      }
      person;
      
      int main(void)
      {
          person people[3];
      
          people[0].name = ...;
          people[1].number = ...;
      }
      
  • sorting
    • 選択ソート
      • n(n-1)/ 2 --> O(N^2)
    • バブルソート
      • n^2 - 2n + 1 --> O(N^2)
  • recursion
    • 再帰関数
    • 最初に終了条件
    • iteration.c
      • 終了条件を書かないとダメだよねって話し
    • recursion で google 検索するとずっと以下の表示出る話しはおもろい
  • マージソート
    • 分割統治 & 再帰関数
    • マージロジックのイメージが正確にできてないんだよな
    • 完全二分木の計算量の話
    • ここまで強烈に見せられるとマージソートが最強!という感想を持たざるを得ない
    • が、ソートアルゴリズムの計算量は input にかなり依存してしまうということも覚えておかないといけない

CS50x 2024 - Lecture 4 - Memory

感想

  • メモリの挙動を意識して書いてきたことがあんまりないので楽しみ
  • 応用情報を受けたときにキタミ式で少しやったくらい
  • C は難しいから...で Python から入ったけど、どう考えても C からやるべき、そしてこの講義を見ればそれができる

講義の内容

  • HexDecimal

    • 16進数のお話し
  • Memory

    • 0x: 16進数表記だよって意味
  • Pointers

    • 8バイト
    • ポインターの概念説明にメールボックスを用いているのは、ハーバードでもそうなんだってなった
  • Strings

    • "" を使うことで string 配列の最後に \0 を入れている
    • char の配列に含まれる要素は1バイトずつ連なるメモリに保存されている
    • では、char の配列を代入した変数は何を意味している?
      • 先頭の文字のメモリを表している
      • そのため、while ループなどの中でインクリメントすれば任意の文字にアクセスできる
      • まあこういうことだ
    • what is "string" actually?
      • char *s = "Hi!"
      • わっかりやす!!!!!
  • Poitner Arithmetic

    • ポインタ演算、ここでは加算して HI! を出力できる
  • String comparison

    • 整数比較のはなし
      • 普通に比較できる
      • メモリ上のイメージはこう
    • string を比較してみると?
      • うまくいかないね、なんでだろう
      • こう書き直すと理解がしやすくなる
      • メモリ上はこうなので
      • strcpm 関数を使って以下のように書いてあげれば良い
      • 実際は、 while ループで両方のポインタ変数をインクリメントして文字列同士を比較していくっていう処理が strcmp 関数の中身だと思うけどね
      •   int strCmp(const char* s1, const char* s2)
          {
              while(*s1 && (*s1 == *s2))
              {
                  s1++;
                  s2++;
              }
              return *(const unsigned char*)s1 - *(const unsigned char*)s2;
          }
        
        • 0, 自然数、負の整数の3つの状態を返却する
      • 等値性と等価性の話
        • int main(void)
          {
              string s = get_string("s: ");
              string t = s;
          
              t[0] = toupper(t[0];
              printf("%s\n", s);
              printf("%s\n", t);
          }
          
        • 出力が両方とも Hi! になってしまうね
  • Copying

    • それは t = s で t には s の先頭のメモリが入っているからで、t への変更は s への変更になってしまうからだね
      • メモリ上のイメージはこれ
    • malloc
      • malloc
        • memory allocate の略
        •  int main(void)
           {
              char *s = get_string("s: ");
              char *t = malloc(strlen(s) + 1);
          
              for (int i = 0; n = strlen(s); i <= n; i++ {
                   t[i] = s[i];
              }
          
              if (strlen(t) > 0)
              {
                  t[0] = toupper(t[0]);
              }
          
              t[0] = toupper(t[0];
              printf("%s\n", s);
              printf("%s\n", t);
            }
          
        • これで s: hi!, t: Hi! が出力されるようになった、やったね!
        • mallco の処理内容を可視化すると、↑の t の変数が指す最初のポインタと必要バイト数の塊(チャンク) を取得しに行っていることがわかる
        • 当然、メモリを取得できない可能性もあり、その場合は Null を返すのでエラーハンドリングする必要がある
        •  int main(void)
           {
              char *s = get_string("s: ");
              if (s == NULL) return 1;
          
              char *t = malloc(strlen(s) + 1);
              if ( t == NULL) return 1;
          
              for (int i = 0; n = strlen(s); i <= n; i++ {
                   t[i] = s[i];
              }
          
              if (strlen(t) > 0)
              {
                  t[0] = toupper(t[0]);
              }
          
              printf("%s\n", s);
              printf("%s\n", t);
          
              /// free してないからコピペしないでね
            }
          
      • free
        • malloc で確保したメモリを解放する関数
        •   int main(void)
            {
               char *s = get_string("s: ");
               if (s == NULL) return 1;
           
               char *t = malloc(strlen(s) + 1);
               if ( t == NULL) return 1;
          
               for (int i = 0; n = strlen(s); i <= n; i++ {
                    t[i] = s[i];
               }
          
               if (strlen(t) > 0)
               {
                   t[0] = toupper(t[0]);
               }
          
               printf("%s\n", s);
               printf("%s\n", t);
          
               free(t);
               return(0);
             }
          
      • NULL とは?
        • 単なるアドレスのことで 0 を意味する
      • 補足
        • 散々使ってきている get_string 関数も内部的には malloc を使っていて、input される文字をメモリ上に保存する処理をしているよ
        • C のポインタで非常に引っかかる点が以下なの
        • s は文字列の先頭アドレス、つまり 0x123 みたいな値を指していて
        • *s はそのアドレスに格納されている値を指している
        • じゃあ、この処理はなんやねん
          • for (int i = 0; n = strlen(s); i <= n; i++ {
                t[i] = s[i];
            }
            
          • アドレスのコピーしてますやん
          • でも実際は、こういうこと s[i] == *(s + i)なのでセーフなのです
  • valgrind

    • プログラム解析ツールって感じだなこれは
    • index out of range みたいになる場合はその内容をはいてくれるし
    • malloc で動的に確保したメモリを解放していなければ free してないぞって教えてくれる
  • Garbege Values

    • ポインタを再度説明する章だね
  • swap.c

    • swap function
    • グラスの例え面白いね
    • これで temp を表すのわかりやすいねえ
    • スタックの話
    • 慣れるまで時間かかるよって話だけど直感的に理解できるね
  • Overflow

    • stack overflow
    • heap overflow
  • scanf

    • 整数を scanf する場合は int が4バイトであることがわかっているので問題ない
    • が、文字列を扱う場合は、char のサイズを明示的に与える必要がある
    • get_string の挙動について説明
      • while(true) で malloc し続けているっぽい
      • Enter が終了条件で取っている感じだな
  • File I/O

    • ファイルへの書き込みサンプル
    • ファイルをコマンドライン引数で与えて操作
    • 画像ファイルのコピーすら BYTE を扱って一ピクセルごとに別のファイルに書き込んでいけばできまっせ
  • 最後までユーモアが尽きないのが良い!

CS50x 2024 - Lecture 5 - Data Structures

感想

  • 説明された全てのデータ構造に LinkedList が絡んでいる
  • このあとはプロコンの参考書を読んで実装方法を理解するフェーズへ行かないと

講義の内容

  • Stack and Queue
    • Queue
      • FIFO
      • enqueue
      • dequeue
      • 待ち行列
    • Stack
      • LIFO
      • メールボックス
      • push
      • pop
  • Resizing Arrays
    • LinkedList の話になりそうだな
    • struct Node {
          int value;            
          struct Node *next;
        };
      
  • Linked List
    • やっぱりね
    • コンピュータのメモリをキャンバスのように使おう
    • チャンクからチャンクへリンクを繋げれば、メモリの構造を無視して連続したデータを扱うことができる
    • ちょっと矢印がずれているけど気にしない
    • typeder struct {
          int number;
          struct node *next;
      } node;
      
      int main() {
          struct Node *head = malloc(sizeof(struct Node));
          struct Node *second = malloc(sizeof(struct Node));
          struct Node *third = malloc(sizeof(struct Node));
      
          // ノードに値を設定
          head->value = 1;
          head->next = second;
      
          second->value = 2;
          second->next = third;
      
          third->value = 3;
          third->next = NULL;
      
          // リストを巡回して値を表示
          struct Node *current = head;
          while (current != NULL) {
              printf("%d -> ", current->value);
              current = current->next;
          }
          printf("NULL\n");
      
          // メモリを解放
          free(head);
          free(second);
          free(third);
      
          return 0;
      }
      
    • 動画のコードとは少し違うけど、Linked List is これ!みたいなやつはこう書ける
  • Trees
    • 行きがけ、中間、帰りがけみたいな走査方法は応用情報でやった
    • binary search tree
      • 二分木
      • 中央値をrootにしないとね
      • 要素の追加、削除、木のバランスをとるような操作を身につける必要があるね
  • dictionaries
    • key, value
  • hashing and hash tables
    • なるほど、Linked List を二次元配列みたいに見ているのが hash tables ってことね
    • 今まで学んだデータ構造の組み合わせにすぎないね
    • 辞書を作るなら 26通りのアルファベット LinkedList を 1個用意し、26文字のアルファベットに一対一で26通りのアルファベット LinkedList を割り当てることになるか。。メモリ消費が尋常じゃないな
    • 後、共通の接頭辞を使っている時にどうするのか?
    • でも探索が O(n)、挿入、削除が O(1) で済むのがでかい
    • どういう実装になるのか?がまだよく理解できてないな。。。

CS50x 2024 - Lecture 6 - Python

感想

  • 初めてプログラムに触れた時から C をやっておけばよかった。。。
  • でも挫折していた可能性あるからなあ。。。うーん。。。。
  • 眺めるだけで十分だった

講義の内容

  • Python
    • インタプリタ言語だよ
  • Spellar
  • Filter
  • Face regognition
  • Functions
  • Types
    • double, long が存在しない
  • Calculator
    • 標準入力の扱いがシンプル
  • Conditionals
  • Compare
    • or means ||
    • and means &&
  • OOP
  • Loops
  • meow
  • transaction
    • 浮動小数点問題は依然としてある
    • int のオーバーフローはない
  • exceptions
    • C は exception が帰ってくることはないが、Python であれば ValueError などを返してくれる
  • Mario
  • Lists
    • for 文でも else が書けるのはびつくり
    • if で繰り返しもできるんだ、びつくり
  • Dictionaries
  • sys
    • コマンドライン引数を取れる
    • main 関数がないのに実行できるの違和感しかない
  • pip
    • ライブラリインストールコマンド
    • pycharm とか使ってればいらないのかな

CS50x 2024 - Artificial Intelligence

感想

  • 眺めるだけで十分

講義の内容

  • Introduction
  • Image Generation
  • chatGpt
  • Prompt Engineering
  • cs50.ai
  • generative ai
  • decision trees

CS50x 2024 - Lecture 7 - SQL

感想

  • 眺めるだけで十分かな
  • モバイルアプリだと DB をがっつり使っているものを扱ったことがない

CS50x 2024 - Lecture 8 - HTML, CSS, JavaScript

感想

  • 眺めるだけで十分かな

講義の内容

  • TCP/IP
    • IP
      • int.int.int.int
      • 32 bit
      • iPv4 --> iPv6 へ
    • TCP
      • port number
        • HTTP: 80
        • HTTPS: 443
      • プロトコル
  • DNS
    • domain name system server
  • DHCP
    • role: 質問に答えること
  • HTTP
    • domain name
    • GET, POST
  • Inspect
    • 403: Forbidden
    • 404: Not found
    • etc..
  • Status Code
  • HTML
    • マークアップだよん
    • あんま見なくていいや
  • Haveard Pep Squad Prank
    • ふーん
  • CSS
    • これもあんま見なくていいや
    • <style>にはラムダ式ぽいものがあるんやな
  • BootStrap
    • css ライブラリみたいなやつだよね
  • js
    • ここで見ているものは Android の view とほぼ同じなり
  • autocomplete
    • あー、はいはいはい
  • Geolocation
    • 位置情報

CS50x 2024 - Lecture 9 - Flask

感想

  • Python で Web アプリ作るやつなので見なくて良い

CS50x 2024 - Cybersecurity

感想

  • 眺めるだけで十分だった
  • 応用情報を秋に受けたのでその内容とほぼ被った
脚注
    • 具体的には、network Monitor、端末の通信状態を監視して SnackBar を出す処理
    • やってることは全部わかるんだよ、Cold Flow で状態を公開して NiaApp で監視(collectAsStateWithLifecycle)してオフライン状態になったら SnackBar を出すんだよね
    • んで、di してるから interface を作ってあげていて、外からは1つの変数があるだけっていう状態を作っていますと
    • ほんで、実際の実装は ConnectivityManagerNetworkMonitor でやってて、そこで callbackflow を使ったりしてるんだけど
    • ここで「この方針思いつかんくね?」となり、更に 「callbackflow を読んで理解するのも遅くね?」となったわけ
    ↩︎
    • 職場の同僚に聞いたらいいじゃん!って思うかもしれないんだけど
    • 「こんなことも知らねえのかよ」って態度を露骨に出されちゃうんで聞きたくない...
    • Discord では割とアクティブなのでよかったら絡んでくださいませ
    ↩︎
    • C は 42Tokyo ってとこに一時期通ってて、苦しんで覚えるC を徹夜でまとめたことがある
    • ポインタの概念もギリ覚えてるが少し怪しい
    ↩︎
    • 小分けにするのが面倒くさいし、小分けにするとどうせやらないから
    ↩︎

Discussion