ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CS50 2019 (6)배열
    CS50 2021. 8. 9. 20:33

    ===

    www.boostcourse.org/cs112

     

    모두를 위한 컴퓨터 과학 (CS50 2019)

    부스트코스 무료 강의

    www.boostcourse.org

    1.컴퓨팅사고

    2.C언어

    3.배열

    4.알고리즘

    5.메모리

    6.자료구조

     

    =====================

    4)배열(1)

    들어가기전에 :

    우리가

    특정 자료형의 변수를 선언하면 이는 메모리상 어딘가에 특정 크기만큼의 자리를 차지하게 됩니다.

    만약 비슷한 종류의 값을 모아서 저장하고 싶다면 어떻게 해야할까요?

    메모리상에서 여러 값을 연이어서 저장하고 사용하는 법과 그 이점을 알아보겠습니다.

     

    C의 새로운 기능들을 활용해서 문제를 더 잘 해결하고 더 잘 디자인된 코드를 짤 수 있을지 알아봅시다

    먼저 배열이라는 방법을 보죠

     

    C에는 여러 종류의 자료형이 있다

     

    char 1 byte

    int 4 bytes

    float 4 bytes

    long 8 bytes

    double 8 bytes

    string ? bytes

     

    컴퓨터 메모리에 있는 모든 변수들은 이와 같은 자료형을 갖고 있습니다.

     

    메모리의 검은 칩들은 일정 크기의 바이트를 의미함 소프트웨어 구동 시 정보가 저장되는 곳

    이 칩을 여러 바이트들의 묶음이라고 생각할 수 있음.

    만약 1GB면 10억 바이트인데 첫칸은 첫 바이트고... 이렇게 생각해도 마지막칸은 10억번째 바이트라고 생각할 수도 있다

    0, 1, 2, 3, 4, 5, 6, 7...

     

    ===

    지금은 RAM이 어떻게 동작하는지 전혀 알 필요가 없다

    램이 여기있고 각 바이트에 숫자를 붙인다고 생각하는 정도면 됨

     

    만약 char, 즉 문자를 포함한 프로그램을 작성한다고 하면

    char는 1바이트였고,

    c라고 하는 char를 저장하기 위해서는 컴퓨터 메모리 안의 이 수많은 작은 칸들 중 하나를 요청해야 하는것.

     

    int는 4바이트여서 숫자를 저장한다면 4바이트를 할당해야 하는것.

    double이나 long은 8바이트

     

    그럼 각 작은 네모 칸 안에는 뭐가 있을까?

    칸마다 8비트가 있다 = 8개의 작은 트랜지스터나 8개의 작은 전구

    무엇이든 간에 어떤 방식으로든 0과 1을 표현하고 있다.

     

    ===

    생각해보세요, 여러분이 작성한 프로그램에서 컴퓨터는 어떻게 정보를 저장하나요?

    hi.c

    #include <stdio.h>

     

    int main(void)

    {

        char c1 = 'H';

        char c2 = 'I';

        char c3 = '!';

        printf("%c %c %c\n", c1, c2, c3); 

    }

     

    *C에서 char를 입력할 때는 ' ' 작은따옴표가 필요합니다(1byte를 차지하는 단일문자)

    (string은 " ") : C도 그 둘을 구분해야 하기 때문에 다르게 써야한다

     

    char는 %c

     

    사실 H, I, !는 char

    즉 문자.

    그 안에 있는 ASCII character는 2진법이었다

    그럼 그 중간 단계에는? 숫자였음. integer 정수였어

    ▽char - 정수 - 2진법 이라는 말인것 같군

     

    ASCII와 유니코드로 문자를 숫자로 변환한것

    ▽그러므로 문자와 숫자 왔다갔다 할 수 있다는 말을 하고 싶은 것 같음

     

    그럼 숫자는 printf에 어떤 형식 지정자를 사용하나요? %i integer

     

    그 값들을 실제로 보고 싶다면

    int main(void)

    {

        char c1 = 'H';

        char c2 = 'I';

        char c3 = '!';

        printf("%i %i %i\n", (int) c1, (int) c2, (int) c3); 

    }

    컴퓨터에게 c1은 char이지만 정수처럼 여겨달라고 하는것 변수 앞에 (int)를 적으면 됨 : casting, 형변환

    하나의 자료형을 다른 종류로 바꾸는 행위

    근데 clang은 똑똑해서 (int)안적어도 %i만 해도 자체적으로 바꿔줌

    ▽아 원래 바꿔줬어야 되는건데, 캐스팅을 하고 출력을 해야하는건데 그냥 똑똑한 컴파일러가 알아서 해주는거였구나

     

    ===

    컴퓨터 메모리 안에서 무슨 일이 벌어지고 있는지 이해하면 조금씩 손 볼 수 있게 된다

    만약 c1, c2, c3 3개의 변수를 가진 프로그램이 있다면 컴퓨터가 할 일은 

     

    1.

    각 변수 H, I, ! 를 한칸 한칸에 넣는것

    2.

    그리고 각 칸에 해당하는 변수명(c1, c2, c3)을 저장함.

    3.

    하지만 실제 그 위치에 저장된 건 H, I, !(▽char)

    4.

    물론 이들은 char가 아님. 엄밀히 말하면 숫자, 즉 메모리 안에 저장된 건 사실 72, 73, 33인것

    5.

    또 사실 2진법으로 표현됨 즉 정말 저장된 형태는 

    =>실제로 저장된 형태

     

    하지만 여기서도 우리는 보통은 신경쓰지 않아도 되는 기초적인(▽로우레벨?) 수준의 내용을 다루고 있음.

    우리는 첫 시간에 배운 추상화라는 개념 덕분에 이런 복잡한 것들은 다 무시하고 더 높은 수준의 정보를 다룰 수 있음

    그게 10진수든 ASCII문자든, 사실은 이런 일들이 일어난다는 정도로만 알아주시면 되겠습니다

     

    질문) 변수 3개를 정수로 선언하고 72, 73, 33을 저장한 뒤 %c로도 출력할 수 있나요?

    네, 근데 ASCII코드를 외워야겠죠. 프로그래머들은 단지 일종의 대응 관계가 있다는 사실 정도만 알고 있다

     

    ===

    이제 정말 배열

    scores.c

    이제 3개의 문자 대신 3개의 정수를 써보자

    #include <cs50.h>

    #include <stdio.h>

     

    int main(void)

    {

        int score1 = 72;

        int score2 = 73;

        int score3 = 33;

     

        printf("Average : %i\n", (score1+score2+score3)/3);

    }

    컴파일(make) > 실행

     

    근데 이게 최선의 디자인은 아님, 개선할 여지가 있다

     

    숫자와 점수를 다루고 있는데 만약 다루는 학생이 많다면?

    과제가 많다면?

    평균이 59.5면 반올림됨!

    또 int score이렇게 계속 반복이 됨

     

    ===

    C에서 하나 이상의 값들이 있고 서로 연관되어 있다고 할 때, 여러 점수들을 가진 변수에 적절한 이름은 뭘까요?

    score의 복수형인 scores가 되겠죠

     

    그럼 그건 어떻게 만들까요? 안타깝게도 int scores라고 입력하면 어떤 점수를 값으로 가질지를 결정해야함

     

    C에서는 여러 개의 값을 가진 하나의 변수를 만들고 싶을 때 배열 이라고 하는 걸 사용합니다

    --이렇게 직관적으로 와닿게 설명을 해주는게 너무 좋다

    배열은 값들의 리스트로, 모두 같은 자료형 여러 값들이 같은 이름의 변수에 저장

     

    대괄호를 사용해서 원하는 점수의 개수를 적고 세미콜론을 붙이면 됨

     = 컴퓨터에게 정수 3개를 위한 메모리를 달라고 하는 것

    int scores[3];

    세개의 값을 하나의 변수에 저장하기 위한 공간을 의미함

     

    밑에도 바꿔야함

    각 점수들을 배열에 넣을건데 배열의 이름을 적고 []를 이용해서 해당하는 위치에

     

    int scores[3];

    score[0] = 72;

    score[1] = 73;

    score[2] = 33;

    0부터 세어줘야 함. 선언할 땐 크기고 이건 세는걸 뭐부터 시작하는지고 = 배열의 첫번째 위치는 0

    밑에 printf안에 내용도 변수 이름 고쳐줌

     

    =====================

    5)배열(2)

    이 하버드 선생님 질문마다 베리굿 퀘스천 이 말을 빼먹질 않네 대리즈 굿 퀘스천

     

    여전히 디자인은 개선해야함.

    그리고 프로그램이 더 동적(dynamic)이었으면 좋겠다 = 입력을 받았으면 좋겠다 이 의미네

     

    가령 나눗셈을 할 때, 배열 개수 3 과 나눌 때의 3이 같아야 하는데 1년 뒤에 코드 보면 그게 같아야 한다는 사실을 절대 알 수 없다. : 같은 값이 강제돼야 하는 경우 ! 그 숫자를 내가 손으로 써버리면 안됨

     : 코드상의 조건이 아니라 그냥 그때 내가 내 손으로 쓰는 게 되면 사소해보여도 이는 수많은 버그들의 원인이 된다. 

    -> C에서는 n이라는 정수를 생성해서 값으로 3을 지정하고 그곳들에 넣으면 됨

    또 C에는 다른 언어들 처럼 또다른 기능이 있는데어떤 변수에 특정 값을 지정할 때 그 값을 바꾸고 싶지 않다면 (▽실수로 바뀌는 일도 방지하고 싶다면)코드 상단에, int n이 아니라 const int N = 3; 이라고 적는다. 대문자로 적는건 관습

    그러면 저기에 들어간 코드에 들어간 n들도 N으로 바꿔줘야겠지

     

    상수 ! 라고 하는 것 const로

    해당 변수를 상수(contant)로 지정하면 clang 컴파일러는 여러분이나 다른 사람들이 실수로 그 값을 바꾸지 않도록 해줍니다.

     

    그럼 이제 N을 어디에 사용하든 언제나 같은 값(▽코드중간에 N에 뭘 넣었다든지 그러면 에러가 난다 이런거거겠지?)

     

    이런 함수 바깥에서 선언하는 변수를 전역 변수 라고 함. 

    엉성해보이지만 상수는 예외다.(▽전역변수는 엉성해보이지만 상수엔 써도 된다는건가) 

    상수는 여러분이 한 번 값을 지정해놓고 까먹고 난 뒤, 몇 주 몇 달 뒤에 찾아와서 과제 수가 4개나 5개로 바뀌었다면 코드를 컴파일링 하기 전 값을 수정하기에 편리함. 코드가 맨 위에 있으니 코드를 막 살펴볼 필요가 없다. 코드 상단에 적고, const라고 선언하고, 변수명은 대문자로 적는 그냥 관습임

     

    ===

    코드개선 최종은 이렇게(전역변수랑 const는 그냥 설명만 한건가봐)

    #include <cs50.h>
    #include <stdio.h>
    
    float average(int length, int array[]);
    
    int main(void)
    {
        // 사용자로부터 점수의 갯수 입력
        int n = get_int("Scores:  ");
    
        // 점수 배열 선언 및 사용자로부터 값 입력
        int scores[n];
        for (int i = 0; i < n; i++)
        {
            scores[i] = get_int("Score %i: ", i + 1);
        }
    
        // 평균 출력
        printf("Average: %.1f\n", average(n, scores));
    }
    
    //평균을 계산하는 함수
    float average(int length, int array[])
    {
        int sum = 0;
        for (int i = 0; i < length; i++)
        {
            sum += array[i];
        }
        return (float) sum / (float) length;
    }

    *for문에서 0부터, i < n 이면 n번 반복이다.

    *%i %c 이런건 문자열안에 변수를 넣을 때 쓰는 것  자바에서 " " + " " 이런거 했던 것 안하고

    소수점도 개선  *소수점을 쓸 땐 double이나 float

    간단하게 float을 서서 average라는 함수를 만들것

     

    average()에선 점수가 들어가는 배열의 길이와, 그 배열 자체도 받아야함  --그전에 선언을 해서 들어오니까? 일단 함수의 선언에서 표시돼줘야하는건 자료형이니까

    *배열이라는건 []표시로 아는 것

    float average(int length, int array[])

    자바나 파이썬을 하신 분들은 왜 (average)함수에 배열의 길이를 넣어줘야 하는지 궁금할 수도 있습니다

    C의 배열은 스스로의 길이를 기억하지 않습니다. 즉 다른 언어에서는 몰라도 C에서는 이 과정이 필요한거죠

    ▽그래서 for문에서 length를 써줘야 하니까 따로 받았구나

    ▽근데 기억을 하면 뭐 어떻게 된다는거야? 그래도 length같은 함수로 다시 세야되지않나? 그 함수가 C언어에는 없다고?

     

     

    저기 average왼쪽에 float은 반환값을 의미, 함수가 사용자에게 돌려주는 값

    함수가 float값을 반환하니 printf안에서 ("Average: %f\n"); 하면 됨

    float avg = average(n, scores); 하고

    printf("Average: %f", avg); 해도 되지만 좋은 디자인의 관점에서 보면 불필요한 줄이 한줄 더 생긴것

     

    함수가 아래있으면 위에다 일단 선언해주고

    (main이 위에 있는게 보통 좋고(보기편함), 함수들을 계속 위에다 올려서 쓰기 싫어서 하는것)

    (복붙이 허용되는 유일한 순간이라는데 항상 반복되는 걸 해결하라는거겠지)

    선언은 중괄호 없이 세미콜론만

    당장 함수를 정의하진 않겠지만 존재 자체는 미리 알려주는

     

    return sum / length; 할 때 몇가지 부정확한 부분이 있다.

    C에선 정수를 정수로 나누면 정수가 나옴, integer는 소수점 뒤의 숫자들을 저장할 수 없다.

     -> 가장 간단한 건 형변환 return (float) sum / (float) length;

    float / float 이니 결과적으로 float을 반환하게 됨

     

    int를 float이나 다른걸로 나누면? : 보통 더 강력한 자료형으로 나오게됨. 그래서 사실은 저기서도 둘다 float으로 바꿀 필요는 없음. 이해를 돕기 위해 그랬음.

     

    " " 안에 %.1f 형식코드는 숫자를 나타낼 때 소수점 뒤 한 자리까지만 보여줌

    만약 99.49 인데 %1.f 하면 반올림 하게됨

     

    코드가 여러줄일 때 수학에서처럼 가장 안의 { } 부터 풀면 됨 그 값을 알아낸 다음 바깥으로 나가면 된다

     

Designed by Tistory.