--- tags: CS50 --- # (2022年) CS50 week1 其實之前就已經修完 CS50 了,不過因應 2022 年將課堂作業的系統 從 c9.io 換到 github codespace + vscode 整合 打算來重溫一下裡面的作業,並暖身一下 C 語言的手感 由於已經有許多前輩分享課程與作業的心得 加上官網教材的投影片、重點筆記、教學影片都非常完整 故不再做詳細的紀錄,專注在作業 (problem sets) 上面 https://cs50.harvard.edu/x/2022/weeks/1/ --- ### 作業: [hello](https://cs50.harvard.edu/x/2022/psets/1/hello/) 很棒的 hello world 練習,順便檢驗課堂作業的系統設置是否正確運作 程式碼: ```c #include <stdio.h> /* 載入 lib: stdio.h (standard Input / output) */ #include <cs50.h> /* 載入 lib: cs50.h (才能使用 get_string) */ /** * 依據規格書的設計,必須要用 int 宣告 main * ref: * https://hackmd.io/@sysprog/c-standards#%E8%AE%80%E8%A6%8F%E6%A0%BC%E6%9B%B8%E5%8F%AF%E5%A4%A7%E5%B9%85%E7%9C%81%E5%8E%BB%E8%87%86%E6%B8%AC * https://blog.moli.rocks/2016/12/15/why-should-main-return-in-c/ */ int main() { string name = get_string("What's your name? "); printf("hello, %s\n", name); /* 預設 main 結束時會 return 0, 故不用再特地寫 */ // return 0 } ``` 執行 ![](https://hackmd.io/_uploads/BysZ-kjmo.png) 驗證 ![](https://hackmd.io/_uploads/rydR105Xi.png) --- ### 作業: [Mario(less)](https://cs50.harvard.edu/x/2022/psets/1/mario/less/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include <cs50.h> #include <stdio.h> int main() { // get int variable: height int height = get_int("Height: "); // height must be 1 ~ 8 if (height <= 0 | height > 8) { height = get_int("Height: "); } // head lopp: print each line (assembled content and \n in end) for (int i = 0; i < height; i++) { // loop for space for (int j = 1; j < height - i; j++) { printf(" "); } // loop for brick for (int k = 0; k <= i; k++) { printf("#"); } printf("\n"); } } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include <cs50.h> #include <stdio.h> int main() { // get int variable: height int height = get_int("Height: "); // height must be 1 ~ 8 if (height <= 0 | height > 8) height = get_int("Height: "); // head lopp: print each line (assembled content and \n in end) for (int i = 0; i < height; i++) { // loop for space for (int j = 1; j < height - i; j++) printf(" "); // loop for brick for (int k = 0; k <= i; k++) printf("#"); printf("\n"); } } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/Sk3AgkiXo.png) 驗證 ![](https://hackmd.io/_uploads/Hk5FxksQi.png) --- ### 作業: [Mario(more)](https://cs50.harvard.edu/x/2022/psets/1/mario/more/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include <cs50.h> #include <stdio.h> int main(void) { // get int variable: height int height = get_int("Height: "); // height must be 1 ~ 8 if (height <= 0 | height > 8) { height = get_int("Height: "); } // head lopp: print each line (assembled content and \n in end) for (int i = 0; i < height; i++) { // loop for left space for (int j = 1; j < height - i; j++) { printf(" "); } // loop for left brick for (int k = 0; k <= i; k++) { printf("#"); } printf(" "); // loop for right brick for (int k = 0; k <= i; k++) { printf("#"); } printf("\n"); } } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include <cs50.h> #include <stdio.h> int main(void) { // get int variable: height int height = get_int("Height: "); // height must be 1 ~ 8 if (height <= 0 | height > 8) height = get_int("Height: "); // head lopp: print each line (assembled content and \n in end) for (int i = 0; i < height; i++) { // loop for left space for (int j = 1; j < height - i; j++) printf(" "); // loop for left brick for (int k = 0; k <= i; k++) printf("#"); printf(" "); // loop for right brick for (int k = 0; k <= i; k++) printf("#"); printf("\n"); } } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/S1Mib1imo.png) 驗證 ![](https://hackmd.io/_uploads/Sy_LGJsQi.png) --- ### 作業: [Cash](https://cs50.harvard.edu/x/2022/psets/1/cash/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include <cs50.h> #include <stdio.h> /** * Forward Declarations * 先於開頭宣告 function,實際內容到後面才實作的技巧 */ int get_cents(void); int calculate_quarters(int cents); /* (25¢) */ int calculate_dimes(int cents); /* (10¢) */ int calculate_nickels(int cents); /* (5¢) */ int calculate_pennies(int cents); /* (1¢) */ int main(void) { // Ask how many cents the customer is owed int cents = get_cents(); if (cents == 0) { // If cents is 0, need not calculate return printf("0\n"); } // Calculate the number of quarters to give the customer int quarters = calculate_quarters(cents); cents = cents - quarters * 25; // Calculate the number of dimes to give the customer int dimes = calculate_dimes(cents); cents = cents - dimes * 10; // Calculate the number of nickels to give the customer int nickels = calculate_nickels(cents); cents = cents - nickels * 5; // Calculate the number of pennies to give the customer int pennies = calculate_pennies(cents); cents = cents - pennies * 1; // Sum coins int coins = quarters + dimes + nickels + pennies; // Print total number of coins to give the customer printf("%i\n", coins); } int get_cents(void) { int cents = get_int("Change owed: "); if (cents < 0) { cents = get_int("Change owed: "); } return cents; } int calculate_quarters(int cents) { if (cents < 25) { return 0; } else { return cents / 25; } } int calculate_dimes(int cents) { if (cents < 10) { return 0; } else { return cents / 10; } } int calculate_nickels(int cents) { if (cents < 5) { return 0; } else { return cents / 5; } } int calculate_pennies(int cents) { return cents; } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include <cs50.h> #include <stdio.h> /** * Forward Declarations * 先於開頭宣告 function,實際內容到後面才實作的技巧 */ int get_cents(void); int calculate_quarters(int cents); /* (25¢) */ int calculate_dimes(int cents); /* (10¢) */ int calculate_nickels(int cents); /* (5¢) */ int calculate_pennies(int cents); /* (1¢) */ int main(void) { // Ask how many cents the customer is owed int cents = get_cents(); // If cents is 0, need not calculate if (cents == 0) return printf("0\n"); // Calculate the number of quarters to give the customer int quarters = calculate_quarters(cents); cents = cents - quarters * 25; // Calculate the number of dimes to give the customer int dimes = calculate_dimes(cents); cents = cents - dimes * 10; // Calculate the number of nickels to give the customer int nickels = calculate_nickels(cents); cents = cecnts - nickels * 5; // Calculate the number of pennies to give the customer int pennies = calculate_pennies(cents); cents = cents - pennies * 1; // Sum coins int coins = quarters + dimes + nickels + pennies; // Print total number of coins to give the customer printf("%i\n", coins); } int get_cents(void) { // Must be positive integer int cents = get_int("Change owed: "); if (cents < 0) cents = get_int("Change owed: "); return cents; } int calculate_quarters(int cents) { if (cents < 25) return 0; return cents / 25; } int calculate_dimes(int cents) { if (cents < 10) return 0; return cents / 10; } int calculate_nickels(int cents) { if (cents < 5) return 0; return cents / 5; } int calculate_pennies(int cents) { return cents; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/SkKKp1s7o.png) 驗證 ![](https://hackmd.io/_uploads/BJYUp1iXj.png) --- ### 作業: [Credit](https://cs50.harvard.edu/x/2022/psets/1/credit/) :::spoiler (點擊展開) 符合 `style50` 風格的程式碼 ```c #include <cs50.h> #include <math.h> #include <stdio.h> // count length of card_number int numberLength(long card_num) { int i = 0; while (card_num >= 1) { card_num = card_num / 10; i++; } return i; } // get the first two of card_num int firstTwoNum(long card_num) { long num = card_num; while (num > 100) { num = round(num / 10); } return num; } // validate card number bool validateCardNumber(long card_number, int num_length) { long num = card_number; long base_digit = 1; int total = 0; // get each digit of card_number for (int i = 0; i < num_length; i++) { int digit = num / base_digit % 10; // if i is even if (i % 2 == 0) { total += digit; } // if i is odd if (i % 2 == 1) { int digit_num = digit * 2; if (digit_num < 9) { total += digit_num; } else { // digit_num only can be 10 ~ 18 , so just need find last digit int last_digit_num = digit_num % 10; total += 1; total += last_digit_num; } } // when loop finish, base_digit * 10 base_digit *= 10; } // valid card_number must be total % 10 == 0 bool is_valid = total % 10 == 0; return is_valid; } int main(void) { long card_number = get_long("Card Number: "); int num_length = numberLength(card_number); int first_two = firstTwoNum(card_number); bool valid_card_number = validateCardNumber(card_number, num_length); if (valid_card_number == false) { printf("INVALID\n"); } else { // classification card type // American Express: 15 digit, start with 34, 37 // MasterCard: 16 digit, start with 51, 52, 53, 54, 55 // Visa: 13 or 16 digit, start with 4 switch (num_length) { case 16: if (round(first_two / 10) == 4) { printf("VISA\n"); } else if ((first_two >= 51) & (first_two <= 55)) { printf("MASTERCARD\n"); } else { printf("INVALID\n"); } return 0; case 15: if (first_two == 34 | first_two == 37) { printf("AMEX\n"); } else { printf("INVALID\n"); } return 0; case 13: if (round(first_two / 10) == 4) { printf("VISA\n"); } else { printf("INVALID\n"); } return 0; default: printf("INVALID\n"); return 0; } } } ``` ::: -- :::spoiler (點擊展開) 個人覺得比較好讀的程式碼風格 ```c #include <cs50.h> #include <math.h> #include <stdio.h> /** * Forward Declarations * 先於開頭宣告 function,實際內容到後面才實作的技巧 */ int numberLength(long card_num) int firstTwoNum(long card_num) bool validateCardNumber(long card_number, int num_length) int main(void) { long card_number = get_long("Card Number: "); int num_length = numberLength(card_number); int first_two = firstTwoNum(card_number); bool valid_card_number = validateCardNumber(card_number, num_length); if (valid_card_number == false) return printf("INVALID\n"); // classification card type // American Express: 15 digit, start with 34, 37 // MasterCard: 16 digit, start with 51, 52, 53, 54, 55 // Visa: 13 or 16 digit, start with 4 switch (num_length) { case 16: if (round(first_two / 10) == 4) printf("VISA\n"); else if ((first_two >= 51) & (first_two <= 55)) printf("MASTERCARD\n"); else printf("INVALID\n"); return 0; case 15: if (first_two == 34 | first_two == 37) printf("AMEX\n"); else printf("INVALID\n"); return 0; case 13: if (round(first_two / 10) == 4) printf("VISA\n"); else printf("INVALID\n"); return 0; default: printf("INVALID\n"); return 0; } } // count length of card_number int numberLength(long card_num) { int i = 0; while (card_num >= 1) { card_num = card_num / 10; i++; } return i; } // get the first two of card_num int firstTwoNum(long card_num) { long num = card_num; while (num > 100) num = round(num / 10); return num; } // validate card number bool validateCardNumber(long card_number, int num_length) { long num = card_number; long base_digit = 1; int total = 0; // get each digit of card_number for (int i = 0; i < num_length; i++) { int digit = num / base_digit % 10; // if i is even if (i % 2 == 0) total += digit; // if i is odd if (i % 2 == 1) { int digit_num = digit * 2; if (digit_num < 9) total += digit_num; else { // digit_num only can be 10 ~ 18 , so just need find last digit int last_digit_num = digit_num % 10; total += 1; total += last_digit_num; } } // when loop finish, base_digit * 10 base_digit *= 10; } // valid card_number must be total % 10 == 0 bool is_valid = total % 10 == 0; return is_valid; } ``` ::: -- 執行 ![](https://hackmd.io/_uploads/HJJ_7xj7i.png) 驗證 ![](https://hackmd.io/_uploads/SJAsMxjQs.png)