--- tags: CS50 --- # (2022年) CS50 week5 其實之前就已經修完 CS50 了,不過因應 2022 年將課堂作業的系統 從 c9.io 換到 github codespace + vscode 整合 打算來重溫一下裡面的作業,並暖身一下 C 語言的手感 由於已經有許多前輩分享課程與作業的心得 加上官網教材的投影片、重點筆記、教學影片都非常完整 故不再做詳細的紀錄,專注在作業 (Lab, Problem sets) 上面 https://cs50.harvard.edu/x/2022/weeks/5/ --- ### Lab5: [Inheritance](https://cs50.harvard.edu/x/2022/labs/5/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c // Simulate genetic inheritance of blood type #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> // Each person has two parents and two alleles typedef struct person { struct person *parents[2]; char alleles[2]; } person; const int GENERATIONS = 3; const int INDENT_LENGTH = 4; person *create_family(int generations); void print_family(person *p, int generation); void free_family(person *p); char random_allele(); int main(void) { // Seed random number generator srand(time(0)); // Create a new family with three generations person *p = create_family(GENERATIONS); // Print family tree of blood types print_family(p, 0); // Free memory free_family(p); } // Create a new individual with `generations` person *create_family(int generations) { // Allocate memory for new person person *p = malloc(sizeof(person)); if (p == NULL) { return NULL; } // Generation with parent data if (generations > 1) { // Recursively create blood type histories for parents p->parents[0] = create_family(generations - 1); p->parents[1] = create_family(generations - 1); // Randomly assign child alleles based on parents p->alleles[0] = p->parents[0]->alleles[rand() % 2]; p->alleles[1] = p->parents[1]->alleles[rand() % 2]; } // Generation without parent data else { // Set parent pointers to NULL p->parents[0] = NULL; p->parents[1] = NULL; // Randomly assign alleles p->alleles[0] = random_allele(); p->alleles[1] = random_allele(); } // Return newly created person return p; } // Free `p` and all ancestors of `p`. void free_family(person *p) { // Handle base case if (p == NULL) { return; } // Free parents free_family(p->parents[0]); free_family(p->parents[1]); // Free child free(p); } // Print each family member and their alleles. void print_family(person *p, int generation) { // Handle base case if (p == NULL) { return; } // Print indentation for (int i = 0; i < generation * INDENT_LENGTH; i++) { printf(" "); } // Print person if (generation == 0) { printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } else if (generation == 1) { printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } else { for (int i = 0; i < generation - 2; i++) { printf("Great-"); } printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } // Print parents of current generation print_family(p->parents[0], generation + 1); print_family(p->parents[1], generation + 1); } // Randomly chooses a blood type allele. char random_allele() { int r = rand() % 3; if (r == 0) { return 'A'; } else if (r == 1) { return 'B'; } else { return 'O'; } } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c // Simulate genetic inheritance of blood type #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> // Each person has two parents and two alleles typedef struct person { struct person *parents[2]; char alleles[2]; } person; const int GENERATIONS = 3; const int INDENT_LENGTH = 4; person *create_family(int generations); void print_family(person *p, int generation); void free_family(person *p); char random_allele(); int main(void) { // Seed random number generator srand(time(0)); // Create a new family with three generations person *p = create_family(GENERATIONS); // Print family tree of blood types print_family(p, 0); // Free memory free_family(p); } // Create a new individual with `generations` person *create_family(int generations) { // Allocate memory for new person person *p = malloc(sizeof(person)); if (p == NULL) return NULL; // Generation with parent data if (generations > 1) { // Recursively create blood type histories for parents p->parents[0] = create_family(generations - 1); p->parents[1] = create_family(generations - 1); // Randomly assign child alleles based on parents p->alleles[0] = p->parents[0]->alleles[rand() % 2]; p->alleles[1] = p->parents[1]->alleles[rand() % 2]; } // Generation without parent data else { // Set parent pointers to NULL p->parents[0] = NULL; p->parents[1] = NULL; // Randomly assign alleles p->alleles[0] = random_allele(); p->alleles[1] = random_allele(); } // Return newly created person return p; } // Free `p` and all ancestors of `p`. void free_family(person *p) { // Handle base case if (p == NULL) return; // Free parents free_family(p->parents[0]); free_family(p->parents[1]); // Free child free(p); } // Print each family member and their alleles. void print_family(person *p, int generation) { // Handle base case if (p == NULL) return; // Print indentation for (int i = 0; i < generation * INDENT_LENGTH; i++) printf(" "); // Print person if (generation == 0) printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); else if (generation == 1) printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); else { for (int i = 0; i < generation - 2; i++) printf("Great-"); printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } // Print parents of current generation print_family(p->parents[0], generation + 1); print_family(p->parents[1], generation + 1); } // Randomly chooses a blood type allele. char random_allele() { int r = rand() % 3; if (r == 0) return 'A'; else if (r == 1) return 'B'; else return 'O'; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/rJjKbmhXi.png) 驗證 ![](https://hackmd.io/_uploads/rkCDZQ3Qi.png) --- ### 作業: [Speller](https://cs50.harvard.edu/x/2022/psets/5/speller/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c // Implements a dictionary's functionality #include <stdbool.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <cs50.h> #include "dictionary.h" // Represents a node in a hash table typedef struct node { char word[LENGTH + 1]; struct node *next; } node; // Number of buckets in hash table const unsigned int N = 676; // 26 * 26 (aa to zz) int words_size = 0; // Hash table node *table[N]; // Returns true if word is in dictionary, else false bool check(const char *word) { // get index by hashed int dictionary_index = hash(word); // get first node of table[dictionary_index] node *cursor = table[dictionary_index]; while (cursor != NULL) { // compare lowered string if (strcasecmp(cursor->word, word) == 0) { return true; } // if not found => next node else { cursor = cursor->next; } } return false; } // Hashes word to a number unsigned int hash(const char *word) { // let its ASCII number to multiply // then % N (676) // means result will be 0 ~ 675 return (tolower(word[0]) * tolower(word[1])) % N; } // Loads dictionary into memory, returning true if successful, else false bool load(const char *dictionary) { // load file data FILE *file = fopen(dictionary, "r"); if (file == NULL) { return false; } // define basic variable: word char word[LENGTH + 1]; // create hash table // scan each string and record value to variable: word // EOF means end of file while (fscanf(file, "%s", word) != EOF) { // create a memory block for dn (dictionary node) node *dn = malloc(sizeof(node)); if (dn == NULL) { return false; } strcpy(dn->word, word); // copy word value to (*db).word dn->next = NULL; // default is NULL // get index by hashed int dictionary_index = hash(word); // set hash table if (table[dictionary_index] == NULL) { // first node of table[dictionary_index] table[dictionary_index] = dn; } else { // swap node's linked: // old: table[dictionary_index] // new: dn // set (*new).next is old (from NULL) // set current table[dictionary_index] is dn dn->next = table[dictionary_index]; table[dictionary_index] = dn; } // final: plus words_size words_size++; } // when finish, close fopen fclose(file); return true; } // Returns number of words in dictionary if loaded, else 0 if not yet loaded unsigned int size(void) { // counted in function: load() return words_size; } // Unloads dictionary from memory, returning true if successful, else false bool unload(void) { for (int i = 0; i < N; i++) { node *cursor = table[i]; node *current_node = table[i]; // do recursion for free all memory of nodes while (cursor != NULL) { // replace cursor to next node cursor = cursor->next; // relase memory and set next node of should release free(current_node); current_node = cursor; } } return true; } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c // Implements a dictionary's functionality #include <stdbool.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <strings.h> #include <stdio.h> #include <cs50.h> #include "dictionary.h" // Represents a node in a hash table typedef struct node { char word[LENGTH + 1]; struct node *next; } node; // Number of buckets in hash table const unsigned int N = 676; // 26 * 26 (aa to zz) int words_size = 0; // Hash table node *table[N]; // Returns true if word is in dictionary, else false bool check(const char *word) { // get index by hashed int dictionary_index = hash(word); // get first node of table[dictionary_index] node *cursor = table[dictionary_index]; while (cursor != NULL) { // compare lowered string if (strcasecmp(cursor->word, word) == 0) return true; // if not found => next node else cursor = cursor->next; } return false; } // Hashes word to a number unsigned int hash(const char *word) { // let its ASCII number to multiply // then % N (676) // means result will be 0 ~ 675 return (tolower(word[0]) * tolower(word[1])) % N; } // Loads dictionary into memory, returning true if successful, else false bool load(const char *dictionary) { // load file data FILE *file = fopen(dictionary, "r"); if (file == NULL) return false; // define basic variable: word char word[LENGTH + 1]; // create hash table // scan each string and record value to variable: word // EOF means end of file while (fscanf(file, "%s", word) != EOF) { // create a memory block for dn (dictionary node) node *dn = malloc(sizeof(node)); if (dn == NULL) return false; strcpy(dn->word, word); // copy word value to (*db).word dn->next = NULL; // default is NULL // get index by hashed int dictionary_index = hash(word); // set hash table if (table[dictionary_index] == NULL) { // first node of table[dictionary_index] table[dictionary_index] = dn; } else { // swap node's linked: // old: table[dictionary_index] // new: dn // set (*new).next is old (from NULL) // set current table[dictionary_index] is dn dn->next = table[dictionary_index]; table[dictionary_index] = dn; } // final: plus words_size words_size++; } // when finish, close fopen fclose(file); return true; } // Returns number of words in dictionary if loaded, else 0 if not yet loaded unsigned int size(void) { // counted in function: load() return words_size; } // Unloads dictionary from memory, returning true if successful, else false bool unload(void) { for (int i = 0; i < N; i++) { node *cursor = table[i]; node *current_node = table[i]; // do recursion for free all memory of nodes while (cursor != NULL) { // replace cursor to next node cursor = cursor->next; // relase memory and set next node of should release free(current_node); current_node = cursor; } } return true; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/rkVCOX3Xj.png) .... ![](https://hackmd.io/_uploads/rJiKOQhQj.png) 驗證 ![](https://hackmd.io/_uploads/B1S6vX27j.png)