Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags more
Archives
관리 메뉴

프랙티스만이 살길. 프랙티스만이 살길.

3. 배열 본문

Computer science/CS50

3. 배열

gaussian-goodman
  • make나 clang을 사용할 때, 4가지 단계를 거칩니다.
    • 전처리(Precompile)
      • 첫 번째 단계는 전처리인데, 전처리기에 의해 수행된다. # 으로 시작되는 C 소스 코드는 전처리기에게 실질적인 컴파일이 이루어지기 전에 무언가를 실행하라고 알려준다. 예를 들어, #include는 전처리기에게 다른 파일의 내용을 포함시키라고 알려줍니다. 프로그램의 소스 코드에 #include 와 같은 줄을 포함하면, 전처리기는 새로운 파일을 생성하는데 이 파일은 여전히 C 소스 코드 형태이며 stdio.h 파일의 내용이 #include 부분에 포함됩니다.
    • 컴파일(Compile)
      • 컴파일러라고 불리는 프로그램은 C 코드를 어셈블리어라는 저수준 프로그래밍 언어로 컴파일한다. 어셈블리는 C보다 연산의 종류가 훨씬 적지만, 여러 연산들이 함께 사용되면 C에서 할 수 있는 모든 것들을 수행할 수 있다. C 코드를 어셈블리 코드로 변환시켜줌으로써 컴파일러는 컴퓨터가 이해할 수 있는 언어와 최대한 가까운 프로그램으로 만들어 준다. 컴파일이라는 용어는 소스 코드에서 오브젝트 코드로 변환하는 전체 과정을 통틀어 일컫기도 하지만, 구체적으로 전처리한 소스 코드를 어셈블리 코드로 변환시키는 단계를 말하기도 한다.
    • 어셈블(Assemble)
      • 소스 코드가 어셈블리 코드로 변환되면, 다음 단계인 어셈블단계로 어셈블리 코드를 오브젝트 코드로 변환시키는 것이다. 컴퓨터의 중앙처리장치가 프로그램을 어떻게 수행해야 하는지 알 수 있는 명령어 형태인 연속된 0과 1들로 바꿔주는 작업이다. 이 변환작업은 어셈블러라는 프로그램이 수행한다. 소스 코드에서 오브젝트 코드로 컴파일 되어야 할 파일이 딱 한 개라면, 컴파일 작업은 여기서 끝이 납니다. 그러나 그렇지 않은 경우에는 링크라 불리는 단계가 추가됩니다.
    • 링크(Link)
      • 만약 프로그램이 (math.h나 cs50.h와 같은 라이브러리를 포함해) 여러 개의 파일로 이루어져 있어 하나의 오브젝트 파일로 합쳐져야 한다면 링크라는 컴파일의 마지막 단계가 필요합니다. 링커는 여러 개의 다른 오브젝트 코드 파일을 실행 가능한 하나의 오브젝트 코드 파일로 합쳐줍니다.
  • 버그와 디버깅
    • **버그(bug)**는 코드에 들어있는 오류이다. 버그로 인해 프로그램의 실행에 실패하거나 프로그래머가 원하는 대로 동작하지 않게 된다. **디버깅(debugging)**은 코드에 있는 버그를 식별하고 고치는 과정이다. 프로그래머는 디버거라고 불리는 프로그램을 사용하여 디버깅을 하게 된다.
    • 프로그램은 일반적으로 인간보다 훨씬 빠르게 연산을 수행하기 때문에 프로그램을 실행시켜보는 것만으로는 무엇이 잘못됐는지 찾아내기 어렵다. 디버거는 프로그램을 특정 행에서 멈출 수 있게 해주기 때문에 버그를 찾는데 도움이 된다. 프로그램이 멈추는 특정 지점을 중지점이라고 한다. 또한 프로그래머가 프로그램을 한번에 한 행씩 실행할 수 있게 해준다. 이로써 프로그래머는 프로그램이 내리는 모든 결정들을 단계별로 따라갈 수 있게 된다.
  • C에는 아래와 같은 여러 자료형이 있고, 각각의 자료형은 서로 다른 크기의 메모리를 차지합니다.
    • bool: 불리언, 1바이트
    • char: 문자, 1바이트
    • int: 정수, 4바이트
    • float: 실수, 4바이트
    • long: (더 큰) 정수, 8바이트
    • double: (더 큰) 실수, 8바이트
    • string: 문자열, ?바이트
  • 컴퓨터 안에는 아래 사진과 같은 RAM 이라고 하는 물리적 칩이 메모리 역할을 합니다. 쉽게 생각하면 아래 사진에서 여러 개의 노란색 사각형이 메모리를 의미하고, 작은 사각형 하나가 1바이트를 의미한다고 볼 수 있습니다.

  • char c1 = ‘H’; char c2 = ‘I’; char c3 = ‘!’; 를 수행할 때

메모리에는 다음과 같이 저장된다

실제로 메모리에 저장된건 H,I,!에 대응 하는 아스키 코드 넘버이다.

진짜 찐으로 저장된건 다음과 같다. 컴퓨터는 2진법만 이해하기 때문

이러한 방법을 통해 더 높은 수준의 정보를 다룰 수 있게하는걸 추상화라고 한다.

  • 배열
    • 점수의 개수가 많아진다면, 프로그램의 만은 부분을 수정해야한다. 이때 배열의 개념을 사용한다. 배열은 같은 자료형의 데이터를 메모리상에 연이어서 저장하고 이를 하나의 변수로 관리하기 위해 사용된다.
#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Scores
    int score1 = 72;
    int score2 = 73;
    int score3 = 33;

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

점수들의 평균을 출력하는 코드

int scores[3]; 이라는 코드는 int 자료형을 가지는 크기 3의 배열을 scores 라는 이름으로 생성하겠다는 의미입니다. 배열의 인덱스는 0부터 시작하기 때문에, scores의 인덱스는 0, 1, 2 세 개가 있습니다. 이 인덱스를 변수명 뒤 대괄호 [ ] 사이에 입력하여 배열의 원하는 위치에 원하는 값을 저장하고 불러올 수 있습니다.

#include <cs50.h>
#include <stdio.h>
int main(void)
{
    // Scores
    int scores[3];
    scores[0] = 72;
    scores[1] = 73;
    scores[2] = 33;

    // Print average
    printf("Average: %i\\n", (scores[0] + scores[1] + scores[2]) / 3);
}
  • 전역변수
    • 아래 코드에서 scores 배열의 크기를 정해주는 N이라는 변수를 새로 선언하였다. 만약 N이 고정된 값(상수)이라면 그 값을 선언할 때 const를 앞에 붙여서 전역 변수, 즉 코드 전반에 거쳐 바뀌지 않는 값임을 지정해줄 수 있다. 관례적으로 이런 전역 변수의 이름은 대문자로 표기한다.
#include <cs50.h>#include <stdio.h>const int N = 3;

int main(void)
{
    // 점수 배열 선언 및 값 저장
    int scores[N];
    scores[0] = 72;
    scores[1] = 73;
    scores[2] = 33;

    // 평균 점수 출력
    printf("Average: %i\\n", (scores[0] + scores[1] + scores[2]) / N);
}

위 코드에서 scores 배열의 크기를 정해주는 N이라는 변수를 새로 선언하였다. 만약 N이 고정된 값(상수)이라면 그 값을 선언할 때 const를 앞에 붙여서 전역 변수, 즉 코드 전반에 거쳐 바뀌지 않는 값임을 지정해줄 수 있다. 관례적으로 이런 전역 변수의 이름은 대문자로 표기한다.

  • 문자열(string)자료형 데이터
    • string은 사실 char의 데이터들의 배열이다.
    • string s = “HI!”; 과 같이 문자열 s가 정의되어 있다고 하자. s는 문자의 배열이기 때문에 메모리상에 아래 그림과 같이 저장되고, 인덱스로 각 문자에 접근할 수 있다. 여기서 가장 끝의 ‘\0’은 문자열의 끝을 나타내는 널 종단 문자입니다.단순히 모든 비트가 0인 1바이트를 의미한다.
     

  • main도 그 형태를 보면 하나의 함수임을 알 수 있다. main() 안에 void 라고 입력하는 대신 아래 코드와 같이 argc, argv 를 정의해보았다.
    • 첫번째 변수 argc는 main 함수가 받게 될 입력의 개수이다. 그리고 **argv[]**는 그 입력이 포함되어 있는 배열이다. 프로그램을 명령행에서 실행하므로, 입력은 문자열로 주어진다. 따라서 argv[]는 string 배열이 된다. **argv[0]**는 기본적으로 프로그램의 이름으로 저장된다.만약 하나의 입력이 더 주어진다면 argv[1]에 저장될 것이다.예를 들어 위 프로그램을 “arg.c”라는 이름으로 저장하고 컴파일 한 후 **“./argc”**로 실행해보면 “hello, world”라는 값이 출력된다.명령행 인자에 주어진 값이 프로그램 이름 하나밖에 없기 때문이다. 하지만 **“./argc David”**로 실행해보면 “hello, David”라는 값이 출력된다. 명령행 인자에 David라는 값이 추가로 입력되었고, 따라서 argc 는 2, argv[1] 은 “David”가 되기 때문이다.
    • main 함수의 출력값
      • main 함수는 0을 반환한다. 0은 문제가 없다는 뜻. 0이 아닌 값들을 반환 할 수 있는데, 그 값은 어떤 문제가 생기면 main이 반환하도록 정한 임의의 숫자이다. main 함수가 return 1;을 실행하게해 프로그램을 exit 할 수 있다.
#include <cs50.h> 
#include <stdio.h>
int main(int argc, string argv[])
{
    if (argc == 2)
    {
        printf("hello, %s\\n", argv[1]);
    }
    else
    {
        printf("hello, world\\n");
    }
}

 

'Computer science > CS50' 카테고리의 다른 글

5. 메모리 주소  (0) 2023.07.05
4. 알고리즘  (0) 2023.07.05
2. C언어  (0) 2023.07.05
1. 컴퓨팅 사고  (0) 2023.07.05
0. 들어가며  (0) 2023.07.05