본문 바로가기

NOTES/CS50

[CS50] Chapter 3. 배열

 

최초작성일: 2023-02-04

부스트코스 <모두를 위한 컴퓨터 과학 (CS50 2019)> 강의 수강

3. 배열

1. 컴파일링

  • 컴파일링의 네 단계를 설명할 수 있다.
  • 컴파일링, 어셈블링, 링킹

전처리 단계(preprocessing, precompile)

  • #으로 시작되는 C 소스 코드는 실질적인 컴파일이 이루어지기 전 실행할 것을 알려줌
  • 참조하라고 써놓은 파일(라이브러리)을 해당 파일의 실제 파일로 대체

컴파일링(compiling)

  • 소스 코드를 머신 코드로 바꾸는 단계
  • 소스 코드가 어셈블리 코드로 바뀜
  • 어셈블리어는 저수준 프로그래밍 언어
  • 컴퓨터가 이해할 수 있는 언어와 최대한 가까운 프로그램으로

어셈블링(assembling)

  • 어셈블리 코드를 0과 1로 이루어진 머신 코드(기계어, 오브젝트 코드)로 만듦

링킹(linking)

  • 여러 파일을 컴파일하기 위해 우리가 명령을 여러 번 내릴 필요는 없음
  • 모든 0과 1들을 하나의 큰 파일로 합침
  • 여러 개의 다른 오브젝트 코드 파일을 실행 가능한 하나의 오브젝트 코드 파일로 합쳐줌

2. 디버깅

  • 디버깅하는 여러 방법을 설명할 수 있다.

버그와 디버깅

버그(bug)

코드에 들어있는 오류

  • 의도하지 않은 프로그램 내 실수

디버깅(debugging)

코드에 있는 버그를 식별하고 고치는 과정

  • 디버거를 이용하면 프로그램을 특정 행(중지점, breakpoint)에서 멈출 수 있게 해주어 버그를 찾는 데 도움을 줌
  • 프로그래머는 멈춰진 지점에서 무슨 일이 일어났는지 볼 수있음
  • 프로그램을 한 번에 한 행씩 실행할 수 있게 해 줌
러버덕 디버깅
  • 자신의 코드를 다른 이에게 설명해보면 어디가 잘못되었는지 찾게 되는 경우가 있다

3. 코드의 디자인

  • 코드의 정확성과 디자인을 관리하는 방법을 설명할 수 있다.

코드 디자인의 중요성

  • 코드 작성 시에는 자신과 다른 사람들이 읽기 쉽게, 유지보수하기 쉽게 작성해야
  • 공백 수나 줄바꿈 등은 코드의 실행에 직접적으로 영향을 주지는 않지만 코드를 작성하는 사람들이 코드를 읽고 이해하는 데 영향을 줌
  • 불필요한 오해를 없애고 코드를 이해하는 데 드는 비용을 최소화하기 위해 스타일 가이드를 준수해야

4. 배열 (1)

  • 배열을 정의하고 사용하는 방법을 설명할 수 있다.
  • 배열

C의 자료형

data type memory
bool 1 byte
char 1 byte
int 4 bytes
float 4 bytes
long 8 bytes
double 8 bytes
string ? bytes
  • C에서 char자료형을 입력하려면 작은따옴표, string자료형을 입력하려면 큰따옴표 사용

배열이 필요한 이유

  • 서로 연관있는, 반복적인 데이터를 저장할 때 각 변수를 하나 하나 입력하면
    • 수정이 어려움
    • 보기도 어려움
    • 같은 코드를 반복해서 적어야 함
  • 하나 이상의 값들이 있고 서로 연관되어 있을 때 -> 배열로 저장

C의 배열

  • 여러 개의 값을 가진 하나의 변수를 만들 때 배열 사용
  • 모두 같은 자료형의 값들이 같은 이름의 변수에 저장됨
int main(void)
{
    int scores[3];
    scores[0] = 72;
    scores[1] = 73;
    scores[2] = 33;

    printf("Average: %i\n", (scores[0] + scores[1] + scores[3]) / 3)
}
  • 그러나 위와 같은 코드는 여전히 점수 개수가 바뀌는 상황에서 제약이 많음
  • 나중에 배열의 길이(3)와 평균을 구할 때 나누는 수(3)가 같아야 한다는 걸 모르고 바꿔버릴 수 있음

5. 배열 (2)

  • 배열을 정의하고 사용하는 방법을 설명할 수 있다.
  • 배열, 전역 변수

전역 변수

코드 전반에 걸쳐 바뀌지 않는 값

  • 함수 바깥에서 선언하는 변수
  • 코드 최상단에 const라고 선언하고 변수명은 대문자로 적음(관례)
  • 누군가 실수로 그 값을 바꾸지 않도록 해 줌
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[3]) / N)
}
  • 여전히 배열의 인덱스마다 점수를 지정해줘야 함

C의 배열2

  • 좀 더 동적인 프로그램 작성
#include <cs50.h>
#include <stdio.h>

float average(int length, int array[]);

int main(void)
{
    int n = get_int("Number of 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; // float으로 여기도록.
}
  • C의 배열은 스스로의 길이를 기억하지 않음.
  • 배열의 길이를 넣어줘야.
  • 배열 내 원소의 순서는 바이트 수와 무관
    • 컴퓨터가 각 값의 자료형에 따라 알아서 필요한 저장 공간 계산
  • int를 int로 나누면 int가 나옴
  • int를 float으로 나누면 float

6. 문자열과 배열

  • 문자열이 C에서 정의되는 방식과 메모리에 저장되는 방식을 설명할 수 있다.
  • 문자, 문자열

문자열

  • stringchar의 배열
  • 길어지면 메모리를 많이 차지. 정해진 크기를 가질 수 없음.
    • 변수명은 문자열의 시작점에 대한 정보를 알려줌
    • 문자열이 언제 끝나는지 알려주는 정보도 필요 -> 널(Null) 문자(\0)(널 종단 문자)
  • 널 문자: 8비트가 모두 0인 상태
  • 3글자를 저장하기 위해 널 문자까지 4바이트를 씀.
  • 문자열을 printf 함수로 출력하면 printf 함수가 문자 하나하나마다 널 문자인지 아닌지 판단해서 출력함
  • '%c'를 이용해서 string을 char 하나하나로 받아 출력하면 널 문자는 나오지 않지만, 널 문자를 '%i'로 받으면 0이 출력됨.
string names[4];

names[0] = "EMMA";
names[1] = "RODRIGO";
names[2] = "BRIAN";
names[3] = "DAVID";

printf("%s\n", names[0]);
printf("%c%c%c%c%i\n", names[0][0], names[0][1], names[0][2], names[0][3], names[0][4]);

// EMMA0
  • 문자열 길이보다 더 가서 문자를 출력하면 메모리에 저장된 값을 들여다볼 수 있음.

7. 문자열의 활용

  • 문자열을 탐색하고 일부 문자를 수정하는 코드를 구현할 수 있다.
  • strlen, toupper

문자열의 길이 및 탐색

  • 사용자로부터 문자열을 입력받아 한 글자씩 출력하는 프로그램
  • 문자열의 끝을 어떻게 알까?
    • for 루프 이용: for (int i = 0; s[i] != ‘\0’; i++) { ..}
    • string.h 라이브러리의 strlen() 함수 이용
  • string.h
    • 문자열 복사, 합치기, 비교, 검색 등의 함수가 있음

문자열의 탐색 및 수정

  • 사용자로부터 문자열을 입력받아 대문자로 바꿔주는 프로그램
    • 아스키코드 이용
    • ctype.h 라이브러리의 toupper() 함수 이용
  • ctype.h
    • 아스키코드인지, 숫자인지, 문자인지 등 판단
    • 소문자, 대문자 변환 등의 함수가 있음

8. 명령행 인자(command-line arguments)

  • makeclang 같은 프로그램을 실행할 때 컴파일하고자 하는 코드 외에도 컴파일 후 저장하고자 하는 파일명과 같이 추가적인 정보를 함께 줄 수 있는데, 이것을 명령행 인자라고 함
  • 명령행 인자를 받는 프로그램을 C로 작성할 수 있다.
  • 명령행 인자, argv, argc

main 함수

#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");
    }
}
  • argc는 함수가 받을 입력의 개수, argv[]는 그 입력이 포함되어 있는 배열
  • argv[0]는 기본적으로 프로그램의 이름으로 저장됨.
  • argc라고 저장 후 명령창에서 ./argc David로 실행하면 "hello, David" 출력
  • main 함수의 반환값은 int인데 기본적으로 프로그램이 잘 실행되면 0을 반환.

 

'NOTES > CS50' 카테고리의 다른 글

[CS50] Chapter 6. 자료구조  (0) 2023.03.04
[CS50] Chapter 5. 메모리  (0) 2023.02.25
[CS50] Chapter 4. 알고리즘  (0) 2023.02.13
[CS50] Chapter 2. C언어  (1) 2023.01.30
[CS50] Chapter 1. 컴퓨팅 사고  (0) 2023.01.30