Try   HackMD

(2022年) CS50 week1

其實之前就已經修完 CS50 了,不過因應 2022 年將課堂作業的系統
c9.io 換到 github codespace + vscode 整合
打算來重溫一下裡面的作業,並暖身一下 C 語言的手感

由於已經有許多前輩分享課程與作業的心得
加上官網教材的投影片、重點筆記、教學影片都非常完整
故不再做詳細的紀錄,專注在作業 (problem sets) 上面

https://cs50.harvard.edu/x/2022/weeks/1/


作業: hello

很棒的 hello world 練習,順便檢驗課堂作業的系統設置是否正確運作

程式碼:

#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
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Mario(less)

(點擊展開) 符合 style50 風格的程式碼
#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");
    }
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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");
    }
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Mario(more)

(點擊展開) 符合 style50 風格的程式碼
#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");
    }
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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");
    }
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Cash

(點擊展開) 符合 style50 風格的程式碼
#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;
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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;
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


作業: Credit

(點擊展開) 符合 style50 風格的程式碼
#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;
        }
    }
}

(點擊展開) 個人覺得比較好讀的程式碼風格
#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;
}

執行

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

驗證

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →