본문 바로가기

Web Development/CS

[CS50] Week 1: 데이터 타입, 연산자, 조건문, 반복문, 커맨드라인(CLI), 1주차 과제

Problem set 1

(1) Hello, world

In a file called hello.c, in a folder called world, implement a program in C that prints hello, world\n, and that’s it!

 

(2) Hello, it's me

In a file called hello.c, in a folder called me, implement a program in C that prompts the user for their name and then says hello to that user. For instance, if the user’s name is Adele, your program should print hello, Adele\n!

#include <stdio.h>
#include <cs50.h>

int main(void) {
    string name = get_string("What's your name? ");
    printf("hello, %s\n", name);
}

 

(3) Mario (feeling more comfy version)

In a file called mario.c in a folder called mario-more, implement a program in C that recreates that pyramid, using hashes (#) for bricks, as in the below:

   #  #
  ##  ##
 ###  ###
####  ####

And let’s allow the user to decide just how tall the pyramids should be by first prompting them for a positive int between, say, 1 and 8, inclusive.

 

<내 코드>

#include <cs50.h>
#include <stdio.h>

void drawStars(int n);

int main(void)
{
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1 || height > 8);

    drawStars(height);
}

void drawStars(int n) {
    for (int i = 0; i < n; i++) {
        for (int j = n - 1; j > i; j--) {
            printf(" ");
        }
        for (int j = 0; j <= i; j++) {
            printf("#");
        }
        printf("  ");
        for (int j = 0; j <= i; j++) {
            printf("#");
        }
        printf("\n");
    }
}

 

처음에 제출하는데 CLI를 안쓰고 GUI를 써서 디렉토리를 수정해서 그런지 디렉토리 위치를 찾을 수 없는 에러가 엄청 떴다. 그래서 다시 CLI 사용해서 제출했더니 성공..

 

<linux commands>

 

(1) ls (List Directory Contents): 디렉토리 확인할 때

-Prototype: ls [options] [directory]

-Example: ls -l /home/user/Documents

 

(2) cd (Change Directory): 현재 디렉토리 변경

-Prototype: cd [directory]

-Example: cd /var/www/html

 

(3)pwd (Print Working Directory): 현재 디렉토리 프린트

-Prototype: pwd

-Example: pwd

 

(4)mkdir (Make Directory): 새 디렉토리 추가

-Prototype: mkdir [directory_name]

-Example: mkdir new_directory

 

(5)rm (Remove): 제거

-Prototype: rm [options] [file/directory]

-Example: rm -r old_directory

 

(6)cp (Copy): 복사 

-Prototype: cp [options] source destination

-Example: cp file.txt /backup/file_backup.txt

 

(7)mv (Move/Rename): 이동, 이름 변경

-Prototype: mv [options] source destination

-Example: mv file.txt /new_location/

 

(4) credit (feeling more comfy version)

A credit (or debit) card, of course, is a plastic card with which you can pay for goods and services. Printed on that card is a number that’s also stored in a database somewhere, so that when your card is used to buy something, the creditor knows whom to bill. There are a lot of people with credit cards in this world, so those numbers are pretty long: American Express uses 15-digit numbers, MasterCard uses 16-digit numbers, and Visa uses 13- and 16-digit numbers. And those are decimal numbers (0 through 9), not binary, which means, for instance, that American Express could print as many as 10^15 = 1,000,000,000,000,000 unique cards! (That’s, um, a quadrillion.)

Actually, that’s a bit of an exaggeration, because credit card numbers actually have some structure to them. All American Express numbers start with 34 or 37; most MasterCard numbers start with 51, 52, 53, 54, or 55 (they also have some other potential starting numbers which we won’t concern ourselves with for this problem); and all Visa numbers start with 4. But credit card numbers also have a “checksum” built into them, a mathematical relationship between at least one number and others. That checksum enables computers (or humans who like math) to detect typos (e.g., transpositions), if not fraudulent numbers, without having to query a database, which can be slow. Of course, a dishonest mathematician could certainly craft a fake number that nonetheless respects the mathematical constraint, so a database lookup is still necessary for more rigorous checks.

In a file called credit.c in a folder called credit, implement a program in C that checks the validity of a given credit card number.

 

더보기

Luhn’s Algorithm

 

So what’s the secret formula? Well, most cards use an algorithm invented by Hans Peter Luhn of IBM. According to Luhn’s algorithm, you can determine if a credit card number is (syntactically) valid as follows:

Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total modulo 10 is congruent to 0), the number is valid!
That’s kind of confusing, so let’s try an example with David’s Visa: 4003600000000014.

For the sake of discussion, let’s first underline every other digit, starting with the number’s second-to-last digit:
4003600000000014
Okay, let’s multiply each of the underlined digits by 2:
1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2
That gives us:
2 + 0 + 0 + 0 + 0 + 12 + 0 + 8
Now let’s add those products’ digits (i.e., not the products themselves) together:
2 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 8 = 13
Now let’s add that sum (13) to the sum of the digits that weren’t multiplied by 2 (starting from the end):
13 + 4 + 0 + 0 + 0 + 0 + 0 + 3 + 0 = 20
Yup, the last digit in that sum (20) is a 0, so David’s card is legit!
So, validating credit card numbers isn’t hard, but it does get a bit tedious by hand. Let’s write a program.

 

크레딧카드 넘버 유효성을 검사하는 문제

(1) checksum 알고리즘을 작성하여 결과가 10으로 나누어 떨어지는지

(2) 카드넘버의 자릿수가 각 카드사의 카드넘버 자릿수와 일치하는지

(3) 카드넘버가 각 카드사의 verifying 넘버로 시작하는지

 

이렇게 검사하면 맞는 결과가 나온다. 카드넘버 자릿수도 카드사마다 따로 검사해야하는지 몰라서 좀 헤맸음..

 

<내 코드>

#include <cs50.h>
#include <stdio.h>

int getSumOfDigits(long input);

int main(void)
{
    // get input
    long input = get_long("Number: ");

    // get sum of the digits
    int sum = getSumOfDigits(input);


    // count digit and get verifying number
    int digitCount = 0;
    int verNum = 0;
    while (input != 0) {
        input /= 10;
        if (input >= 10 && input <= 99) {
            verNum = input;
        }
        digitCount++;
    }

    //check the validity

    if (sum % 10 != 0) {
        printf("INVALID\n");
    }
    else if (digitCount == 15 && (verNum == 34 || verNum == 37)) {
        printf("AMEX\n");
    }
    else if (digitCount == 16 && (verNum >= 51 && verNum <= 55)) {
        printf("MASTERCARD\n");
    }
    else if ((digitCount == 13 || digitCount  == 16 ) && (verNum/10 == 4)) {
        printf("VISA\n");
    }
    else {
        printf("INVALID\n");
    }
}

int getSumOfDigits(long input)
{
    int i;
    int sum = 0;
    for (i = 0; input >= 10; i++)
    {
        if (i % 2 == 0)
        {
            sum += input % 10;
            input /= 10;
        }
        else
        {
            int tmp = 2 * (input % 10);
            if (tmp >= 10)
            {
                tmp = 1 + tmp % 10;
            }
            sum += tmp;
            input /= 10;
        }
    }

    if (i % 2 == 0)
    {
        sum += input % 10;
    }
    else
    {
        int tmp = 2 * (input % 10);
        if (tmp >= 10)
        {
            tmp = 1 + tmp % 10;
        }
        sum += tmp;
    }
    return sum;
}

 

<수정한 코드>

#include <cs50.h>
#include <stdio.h>

int getSumOfDigits(long input);
int getCardType(long input);

int main(void)
{
    // Get input
    long input = get_long("Number: ");

    int sum = getSumOfDigits(input);
    int cardType = getCardType(input);

    if (sum % 10 != 0)
    {
        printf("INVALID\n");
    }
    else
    {
        switch (cardType)
        {
            case 1:
                printf("AMEX\n");
                break;
            case 2:
                printf("MASTERCARD\n");
                break;
            case 3:
                printf("VISA\n");
                break;
            default:
                printf("INVALID\n");
        }
    }
    return 0;
}

int getSumOfDigits(long input)
{
    int i;
    int sum = 0;
    for (i = 0; input >= 10; i++)
    {
        if (i % 2 == 0)
        {
            sum += input % 10;
            input /= 10;
        }
        else
        {
            int tmp = 2 * (input % 10);
            if (tmp >= 10) { tmp = 1 + tmp % 10; }
            sum += tmp;
            input /= 10;
        }
    }

    if (i % 2 == 0) { sum += input % 10; }
    else
    {
        int tmp = 2 * (input % 10);
        if (tmp >= 10) { tmp = 1 + tmp % 10; }
        sum += tmp;
    }
    return sum;
}

int getCardType(long input)
{
    // Determine card type based on number length and starting digits
    int digitCount = 0;
    int startingDigits = input;

    while (input != 0)
    {
        input /= 10;
        if (input >= 10 && input <= 99)
        {
            startingDigits = input;
        }
        digitCount++;
    }

    if (digitCount == 15 && (startingDigits == 34 || startingDigits == 37))
    {
        return 1; // AMEX
    }
    else if (digitCount == 16 && (startingDigits >= 51 && startingDigits <= 55))
    {
        return 2; // MASTERCARD
    }
    else if ((digitCount == 13 || digitCount == 16) && (startingDigits / 10 == 4))
    {
        return 3; // VISA
    }
    else
    {
        return 0; // INVALID
    }
}

 

(1) 카드 타입 구하는 로직을 getCardType function으로 따로 분리

(2) verNum -> startingDigits 으로 변수이름 더 알기 쉽게 수정

(3) cardType에 따라 switch문을 작성해서 결과값 return + if 문에서 다루어지지 않는 케이스 핸들링