프로그래밍이란 무엇인가?

어떤 목적을 달성하기 위한 프로그램을 만드는 것으로 게임도, 계산기도 웹 서비스도 모두 목적을 달성하기 위한 프로그램입니다. 컴퓨터에서 프로그래밍을 하기 위해선 프로그래밍 언어를 학습하여 일련의 동작을 수행하도록 하여 달성하고자 하는 목표를 향해서 나아가도록 합니다.


이 튜토리얼에서는 리눅스Debian을 이용하여 소스코드를 작성하고 컴파일 및 구동을 해볼 것 입니다. Windows 사용자라면 Visual Studio Community를 설치하여 사용하시면 됩니다. 리눅스를 사용하는 그 모든 순간은 어려움의 연속이겠지만 그 어려움을 해결했을때의 재미와 더불어 개발자가 목표라면 터미널 환경엔 익숙할 필요가 있습니다.


처음 개발을 시작한다면 대부분 쉬운 파이썬이나 컴파일러가 필요하지 않은 웹 상에서 돌아가는 프로그래밍 언어인 자바스크립트를 권장하기도 합니다. 하지만 쉬운 것 부터 시작했을때 어려운 것으로 올라가긴 어렵지만 어려운 것을 재미있게 시작하면 쉬운것은 더 쉽게 익혀나갈 수 있습니다. 또한 C++는 C언어와 마찬가지로 컴퓨터 과학을 이해하는데 도움이 되는 낮은 수준의 컨트롤이 가능하며 객체 지향이라는 프로그래밍의 페러다임이 녹아 있습니다.


이 글에서 굳이 데비안을 사용하는 이유는 리눅스 배포판 중에서 데스크톱으로 가장 널리 쓰이는 운영체제이기 때문입니다. 자료가 많아 문제가 발생했을 경우 검색하면 다양한 자료를 찾을 수 있습니다. 데비안 계열의 대표적인 배포판은 Ubuntu, Linux Mint가 있습니다.


데비안 패키지 설치

먼저 C와 C++에서는 소스코드를 작성하고 실행하기 위해서 컴파일 이라는 과정을 거쳐야 합니다. 우리가 작성한 소스코드는 사람이 이해하기 쉽도록 만들어진 고급 언어에 해당하며 컴퓨터가 이 말을 알아듣기 위해선 0101과 같은 이진법으로 전환을 해주어야 합니다. 이 과정이 컴파일 입니다. 컴파일을 할 수 있게 하기위해서 패키지를 설치해 주도록 하겠습니다.

sudo apt-get install build-essential

위 명령어를 입력하여 간단하게 패키지를 설치할 수 있습니다. (여기서 간단하다는 말은 웹페이지에 들어갈 필요없이 명령어만으로 설치할 수 있기에 간단하다고 표현하고 있습니다.) 위 명령어로 패키지를 설치하면 gcc, g++, make, perl등의 기본적이고 가장 필수적인 라이브러리가 설치됩니다. 무슨 패키지인지는 모두 알 필요는 없습니다.


Hello, World!

컴파일을 테스트해 볼 소스코드를 만들어 보도록 하겠습니다. 대부분의 프로그래밍 언어는 Hello, World! 라는 문구를 출력하는 소스코드를 작성하는 것으로 시작을 알립니다. 컴퓨터가 세상과 처음 만나는 인사라고나 할까요? 그냥 하나의 관습입니다. 모든 언어의 시작은 위 문구로 시작하므로 우리는 이 Hello, World! 라는 문구를 출력하는 코드를 통해서 각 언어가 어떻게 다른지 살펴볼 수 있습니다.


  • C언어 에서는

C언어에서는 Hello, World! 를 어떻게 출력하는지 살펴보겠습니다.

#include <stdio.h>

int main(void)
{
    printf("Hello, World!\n");
    return 0;
}


  • C++ 에서는
#include <iostream>

using namespace std;

int main(void) {
    cout << "Hello, World!" << endl;
    return 0;
}

뭔가 다른 언어라고 하지만 크게 다른 것 같지는 않습니다. 이름에서도 알 수 있듯 C++는 C 보다는 확장된 개념으로 '객체 지향'이라는 개념이 추가되었습니다. 최근에 뜨고있는 많은 언어들은 '객체 지향'이라는 개념이 포함되어 있습니다. 여러분이 C가 아닌 C++로 시작한다면 다른 언어를 배울때도 큰 어려움이 없을 것 입니다.


소스코드 작성

자, 그럼 본격적으로 프로그래밍을 시작해 보도록 하겠습니다.

Visual Studio 2017

  1. 파일 > 새로 만들기 > 프로젝트
  2. 프로젝트 생성
  3. 빈 프로젝트
  4. 소스코드 생성

Linux Debian

만일 X-Window를 설치한 상황이라면 Visual Studio Code를 설치해서 소스코드를 작성할 수도 있겠지만 우리는 VIM을 이용해서 소스코드를 작성하도록 할 것입니다. VIM은 VI보다는 편리하지만 여전히 가벼운 터미널 텍스트 편집기 입니다. (속도는 뎌디겠지만 쾌감은 더욱 짜릿합니다.)

sudo apt-get install vim

VIM이 정상적으로 설치되었다면 vi source.cpp를 입력하면 텍스트 편집기로 이동합니다.


뭐가 막 뜬다고요? VIM의 안내 말입니다. 그냥 아무키나 눌러 그 화면을 없애십시오. 그뒤 까만창이 보이면 i를 눌러 입력모드로 접근할 수 있습니다. 그리고 소스코드를 작성합시다.

#include <iostream>

int main(void) {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

VIM 편집기를 사용하고 있는 경우 esc를 눌러서 입력모드를 종료할 수 있으며 :을 눌러서 wq 명령어를 입력하세요. w는 저장을 나타내며 q는 종료를 나타냅니다.


컴파일 및 작동

컴파일은 Visual Studio를 사용하고 있는 경우 Ctrl + F5를 눌러서 결과를 확인할 수 있습니다. 리눅스의 경우 우리가 방금 설치했던 build-essential에 포함된 g++를 이용하여 작성합니다. 기본적인 사용방법에 대해서 알아보겠습니다. (속도는 뎌디겠지만 쾌감은 더욱 짜릿합니다.)

g++ source.cpp

위와같은 명령어를 입력하면 a.out 이란는 파일로 실행파일이 생성됩니다. 출력파일의 이름을 변경하고 싶다면 다음과 같이 입력하세요.

g++ -o name source.cpp

그럼 name.out으로 실행파일이 생성됩니다. 다음 명령어를 입력하여 실행합시다.

./a.out


소스코드 해석

// iostream은 기본적인 입출력을 가능하게 해주는 도구입니다.
// 프로그래밍은 아무것도 없는 무에서 유를 창조하는 것입니다.
// 하지만 기본적인 것들은 이미 만들어져 있어서 아래와 같이
// include를 통하여 만들어진 것을 사용할 수 있게됩니다.
#include <iostream>

// main은 프로그램이 시작하는 지점입니다.
// "자! 여기서부터 시작이야!"
int main(void) {

    // std라는 네임스페이스에 포함된 cout이라는 함수를 사용하여 문장을 출력합니다.
    // endl은 네임스페이스에 포함된 개행('\n')을 의미합니다.
    std::cout << "Hello, World!" << std::endl;

    // 프로그램이 정상적으로 끝났음을 의미합니다.
    return 0;
}

네임스페이스? 함수? 입출력? 이는 차후에 소스코드를 통해서 무슨 의미인지 쉽게 파악할 수 있을 것입니다. 어렵다고 걱정하지 마세요.


입출력 예제

방금 우리는 Hello, World! 라는 문구를 출력하는 소스를 작성했습니다. 이번엔 입력을 받아서 입력받은 내용을 출력하는 소스코드를 작성해 보도록 하겠습니다.

#include <iostream>

using namespace std;

int main(void) {
    int number = 0;
    cout << "당신이 좋아하는 숫자를 입력하세요 : ";
    cin >> number;

    cout << "당신이 좋아하는 숫자는 " << number << " 입니다." << endl;
    return 0;
}
당신이 좋아하는 숫자를 입력하세요 : 1
당신이 좋아하는 숫자는 1 입니다.

cin 이라는 함수를 사용하여 사용자로부터 입력을 받을 수 있습니다. cout은 <<로 작성했는데 cin은 반대방향인 >>로 되어있는 것을 볼 수 있습니다. 그런데 "Hello, Wolrd!" 코드와 조금 다른점이 있습니다. 3행에 보이는

using namespace std;

그리고 아까는 std::cout이라고 입력했지만 지금은 std를 생략하고 cout만 사용하고 있습니다. 지금은 namespace에 대해서 정확하게 모르니 지금은 단지 'std를 생략할 수 있게 해준다'라고 생각하시면 좋을 듯 합니다.


주석

#include <iostream>

using namespace std;

int main(void) {
    // 이 부분은 주석이라고 합니다.
    // 코드 동작에 아무런 영향을 미치지 않습니다.

    /*
     *
     * 이런식으로 작성할 수도 있습니다.
     * 
     */

    return 0;
}

주석은 코드를 설명할 경우 사용합니다. 자신이 작성한 코드를 자신은 알아볼 수 있지만 상대방은 알아보기 힘든 경우가 많습니다. 따라서 이 코드는 어떤 동작을 하고 왜 이렇게 만들었는지 상대에게 좀 더 쉽게 표현할 수 있습니다.


변수

#include <iostream>

using namespace std;

int main(void) {
    int a = 1;
    int b = 2;
    int sum = a + b;
    cout << "1 + 2 = " << sum << endl;
    return 0;
}

변수는 이처럼 자신이 정한 이름에 무언가를 대입(=)하여 사용할 수 있습니다. 단지 그 이름이 그 숫자처럼 사용된다는 의미가 아닙니다. 컴퓨터는 그렇게 모호하게 동작하는 기계가 아닙니다. 프로그래밍 언어에서 변수를 선언한 것은 메모리를 할당 받는다는 의미입니다.


게임을 하려면 많은 RAM을 사용해야 합니다. 게임에서는 엄청난량의 리소스가 생성되기 때문입니다. 우리도 게임에서 사용하는 메모리를 사용하여 프로그램을 만들게 됩니다. a라는 이름의 메모리 공간을 만들어 그 공간 안에 1을 넣은 것입니다. 메모리는 C언어에서 매우 중요한 개념으로 차후에 포인터라는 개념이 등장할때 이 개념이 머릿속에 있어야 합니다.


그럼 sum은 a, b를 넣을 수 있을 만큼 메모리가 커지나요?


위 설명만 본다면 이와같이 이해할 수 있을거 같아서 적습니다만, 아닙니다. sum 앞에 보이는 int가 메모리의 크기를 결정합니다. a는 1이라는 정수값을 넣을 수 있을 만큼 메모리를 할당받을 뿐입니다.


자료형

#include <iostream>

using namespace std;

int main(void) {
    int a = 1;
    bool b = false;
    char c = 'b';
    double d = 3.14;
    string e = "BaeJino";

    cout << "a : " << sizeof(a) << endl;
    cout << "b : " << sizeof(b) << endl;
    cout << "c : " << sizeof(c) << endl;
    cout << "d : " << sizeof(d) << endl;
    cout << "e : " << sizeof(e) << endl;
    return 0;
}
a : 4
b : 1
c : 1
d : 8
e : 32

자료형

  • int : 정수형
  • bool : 참/거짓(불리언)
  • char : 문자형
  • double : 실수형
  • string : 문자열

더 많은 자료

sizeof() 함수는 메모리의 크기를 얼마나 할당받았는지 확인하는 함수입니다. 정수형(int)은 4byte을 할당받았습니다. 각 자료형에 따라 필요한 메모리의 크기가 다르다는 것을 확인할 수 있습니다.


연산자

#include <iostream>

using namespace std;

int main(void) {
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 35;

    cout << "10 + 20 = " << a + b << endl;
    cout << "10 - 20 = " << a - b << endl;
    cout << "20 * 30 = " << b * c << endl;
    cout << "30 / 10 = " << c / a << endl;
    cout << "35 % 30 = " << d % c << endl;

    return 0;
}
10 + 20 = 30
10 - 20 = -10
20 * 30 = 600
30 / 10 = 3
35 % 30 = 5

사칙 연산에 대해서 모르는 사람은 없을 것으로 생각됩니다만, 15행에 보이는 %에 대해서 잘 모르겠다는 사람들이 있습니다. %는 나머지를 의미합니다. 이 연산은 날자에서 요일을 구할때 요긴하게 사용됩니다. 1일이 월요일 입니다. 27일은 무슨 요일입니까? 라고 물었을때 우리는 27 % 7 을 이용해서 간단하게 답을 찾을 수 있습니다.

입력을 받고 연산을 해준다면 간단한 계산지는 만들 수 있을 것 같지 않습니까? 스스로 프로그램을 만들어 보는 것이 프로그래밍 실력과 흥미를 쌓는데 큰 도움이 됩니다.


증감 연산자

#include <iostream>

using namespace std;

int main(void) {
    int a = 0;
    a++;
    a++;
    cout << a << endl;
    a--;
    a--;
    cout << a << endl;
    cout << ++a << endl;
    cout << a++ << endl;
    cout << a << endl;
    return 0;
}
2
0
1
1
2

++, --는 증감 연산자라는 이름으로 사용됩니다. 1만큼 더해주거나 빼주게 됩니다. 다만 증감연산자가 앞에 붙었느냐 뒤에 붙었느냐에 동작은 완전히 달라집니다. 앞에 붙은 경우 증감 연산자가 동작한 후 출력되며 뒤에 붙은 경우 출력하고 증감 연산자가 동작합니다.

이걸 어디다가 사용하냐구요? 나중에 반복문이 나올경우 많이 사용하게 됩니다.


할당 연산자

#include <iostream>

using namespace std;

int main(void) {
    int a = 0;
    a += 5;
    // a = a + 5 와 동일한 동작을 수행합니다.
    cout << a << endl;
}

증감 연산자와 비슷한 구조를 하고 있습니다. += 는 덧셈 할당, -= 는 뺼셈 할당, 그 외 /, %, * 등등을 사용할 수 있습니다.


상수

#include <iostream>

using namespace std;

int main(void) {
    const int kAlanTuringBirthYear = 1912;
    const int ALAN_TURING_BIRTH_YEAR = 1912;

    cout << "앨런 튜링 출생 연도 : " << ALAN_TURING_BIRTH_YEAR << endl;
}
앨런 튜링 출생 연도 : 1912

세상에는 절대 변하지 않는 값이 있습니다. 그것이 상수입니다. 가령 당신이 태어난 연도는 절대 변하지 않을 것이며 역사적인 사건이 발생한 날도 변하지 않습니다(뭐 잘못 기록된 경우라면 모르겠지만요). 같은 상수를 2가지를 만들었는데 상단에 표시된 상수가 구글에서 권장하는 작명법입니다. 아래는 이전부터 통용되어 온 방식으로 여전히 아래 방식을 이용하여 작성되는 경우가 대부분입니다.


조건문

#include <iostream>

using namespace std;

int main(void) {
    int age = 0;
    cout << "미성년자 출입 금지구역, 당신의 나이? : " << endl;
    cin >> age;

    if(age < 20) {
        cout << "입장 불가" << endl;
    }
    else {
        cout << "입장 가능" << endl;
    }
    return 0;
}
미성년자 출입 금지구역, 당신의 나이? : 19
입장 불가

미성년자 출입 금지구역, 당신의 나이? : 20
입장 가능

조건에 만족하면 만족하는 if 블록을 실행하고, 만족하지 않으면 만족하지 않은 else 블록을 실행합니다. if와 else뿐만 아니라 else if를 사용하여 다른 조건을 생성할 수도 있습니다.

블록은 { } 에 둘러싸인 부분을 의미합니다!

if (a == 1) {
    cout << "a는 1입니다." << endl;
}
else if (a == 2) {
    cout << "a는 2입니다." << endl;
}
else {
    cout << "a는 1도 2도 아닙니다." << endl;
}


반복문

#include <iostream>

using namespace std;

int main(void) {
    for(int i=0; i<10; i++) {
        cout << i << endl;
    }

    return 0;
}

반복문은 말그대로 for 블록을 조건이 만족할때까지 실행합니다. for문을 작성하는 규칙은 다음과 같습니다.

for(변수 ; 끝나는 조건 ; 끝나게 만들 동작)

for문 안에서만 사용할 변수 i를 생성합니다. i는 0부터 시작이며 10보다 작을때까지 반복됩니다. 반복문을 한번 실행하면 i는 1씩 증가합니다.


배운내용 정리!

배운내용을 모두 정리하여 여기 나온 조건을 모두 만족하는 코드를 만들어 보세요. 이 코드는 스스로 만들어 보면서 배운 내용을 자신의 지식으로 만들어 보시길 권장합니다.

문제1.

조건

  • 숫자를 입력받을 것
  • 0을 입력받은 경우 잘못됐다고 출력할 것
  • 입력받은 숫자의 구구단을 출력할 것
  • 출력은 "x * 1 = x"와 같이 할 것
입력 : 0
잘못된 숫자입니다.
입력 : 5
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
5 * 7 = 35
5 * 8 = 40
5 * 9 = 45

문제2.

조건

  • 숫자를 입력받을 것
  • 음수를 받은 경우 잘못됐다고 출력할 것
  • 1일은 수요일이다
  • 입력받은 숫자는 무슨 요일인가
입력 : -15
잘못된 숫자입니다.
입력 : 1
수요일
입력 : 28
화요일