Byn's Research Note

AI based Mixed Reality, Human-Computer Interaction

↓ My Web CV & Portfolio 자세히보기

Computer Scinece/Programming Principles

Programming Principles[1] : C++의 기본 문법 (C++ basics)

JaehyeonByun 2024. 9. 18. 21:29

 

C++

 

C++는 1979년 Bjarne Stroustrup이 개발한 객체지향 프로그래밍 언어로, C 언어의 성능을 유지하면서도 고급 언어 기능을 확장해 더 효율적이고 구조적인 코드 작성을 가능하게 한다. C++는 클래스, 상속, 다형성, 캡슐화 같은 객체지향 프로그래밍(OOP) 개념을 도입해 코드의 재사용성과 유지보수성을 높이며, 템플릿 기능을 통해 제네릭 프로그래밍을 지원해 코드의 유연성을 강화한다. C++는 또한 저수준 메모리 관리가 가능해 운영체제, 게임 엔진, 그래픽 처리 등 고성능 응용 프로그램 개발에 널리 사용되며 표준 라이브러리(STL)를 통해 다양한 자료구조와 알고리즘을 내장하여 개발 효율을 높인다. 본격적인 시작에 앞서 C++의 기본 문법을 정리할 것이다.

1. 변수와 자료형

Variable

 

변수(Variables)는 프로그램 내에서 데이터를 저장하고 처리할 수 있는 메모리 공간으로, 선언할 때 자료형과 변수 이름을 지정하여 사용할 수 있다. 예를 들어 int score = 0;는 정수형 변수 score를 선언하고 초기값으로 0을 할당하는 코드이다. 모든 변수는 선언과 동시에 초기화하는 것이 중요하며, 초기화하지 않으면 해당 메모리 위치에 남아 있는 이전 값(쓰레기 값)이 저장될 수 있다. 이러한 쓰레기 값은 예상치 못한 동작을 유발할 수 있어, 안전한 프로그래밍을 위해 항상 초기값을 지정하는 습관이 필요하다.

int i = 0; // 고전적 초기화 
int i { 100 } // 보편적 초기화

변수명은 숫자로 시작하면 안되고 사이에 공백이 들어가면 안됨

 

자료형(Data type)은 컴퓨터가 데이터를 이해하고 처리할 수 있도록 데이터의 종류와 크기를 정의하는 요소로 주요한 자료형에는 정수형, 부동 소수점형, 문자형, 부울형이 있다. 정수형은 소수점 없는 정수 값을 저장하며, short는 16비트, int는 32비트, long은 32비트, long long은 64비트를 차지해 더 큰 숫자를 저장할 수 있다. 부동 소수점형은 소수점을 포함한 실수 값을 저장하며 float는 32비트, double은 64비트, long double은 64비트 이상을 사용할 수 있다. 부동 소수점형은 정밀한 소수 계산이 필요한 상황에 주로 쓰인다.

auto d = 1.0 // 자동 타입 추론(automatic type deduction) 함수의 매게 변수로는 사용이 불가 
const int i = 1 // 기호 상수 - 변수 선언 앞에 const를 붙이면 상수가 됨

C++에서는 콘솔 입출력을 처리하기 위해 cin과 cout 객체를 사용한다. cin은 표준 입력 스트림을 통해 사용자로부터 데이터를 입력받는데 사용된다. 입력된 데이터는 변수의 타입에 따라 자동으로 형 변환되어 저장되며 예를 들어 int number; cin >> number;라는 코드는 사용자로부터 정수를 입력받아 number 변수에 저장한다. 반면, cout은 표준 출력 스트림을 통해 데이터를 콘솔에 출력하는 데 사용된다. 문자열, 정수, 실수 등의 다양한 데이터 타입을 손쉽게 출력할 수 있으며, 예를 들어 cout << "Hello, World!" << endl;은 "Hello, World!"를 출력하고 줄 바꿈을 추가한다.

 

또한, C++는 값을 증가하거나 감소시키는 증감 연산자(++, --)를 지원하는데, 이 연산자는 변수의 값을 1씩 늘리거나 줄인다. 후위 증가 연산자(i++)는 현재 명령을 실행한 후에 값을 증가시키며, 전위 증가 연산자(++i)는 값을 먼저 증가시킨 후 명령을 실행한다. 이를 통해 연산 순서에 따라 미세하게 다른 결과를 얻을 수 있어 유용하다.

auto d = 1.0 // 자동 타입 추론(automatic type deduction) 함수의 매게 변수로는 사용이 불가 
const int i = 1 // 기호 상수 - 변수 선언 앞에 const를 붙이면 상수가 됨

2. 제어 구조

control structure

관계 연산자(relational operator)는 두 개의 피연산자를 비교하여 그 결과를 참(true) 또는 거짓(false)으로 판단하는 데 사용된다. 예를 들어, ==는 두 값이 같은지를, >는 왼쪽 값이 오른쪽 값보다 큰지를, !=는 두 값이 다른지를 비교한다. 반면에 논리 연산자(logical operator)는 여러 조건을 결합하여 복합적인 참 또는 거짓의 결과를 도출하는 데 사용된다. &&(논리 AND)는 모든 조건이 참일 때만 참을 반환하고, ||(논리 OR)는 하나 이상의 조건이 참이면 참을 반환하며, !(논리 NOT)는 조건의 참/거짓을 반대로 뒤집는다. 이 두 종류의 연산자는 프로그래밍에서 조건문을 작성할 때 필수적인 요소이다.

Statement

조건문(Conditional statement) 반복문(iteration statement)도 제어 구조에 해당한다. if문은 조건이 참일 때 명령을 실행하고 거짓일 경우 아무 작업도 수행하지 않으며, 조건은 반드시 괄호로 묶어야 하고 두 개 이상의 조건이 있을 경우 중괄호로 코드 블록을 설정해야 한다. 사용자 실수로 인한 예외 발생 시에는 else 구문을 활용한 예외 처리가 필요하며, if ~ else 구조로 코드를 작성하면 CPU의 부하를 줄일 수 있다. switch문은 특정 수식을 계산하여 case와 비교하고 일치하는 경우 해당 문장을 실행하다가 break에 도달하면 종료되며, 기본적으로 정수형이나 문자형 상수에만 사용되므로 다룰 수 있는 조건이 제한적이다. 한정된 값이나 정형화된 값의 분기에 적합하며, 모든 switch문은 if문으로 변환 가능하지만 그 반대는 불가능하다. break문이 없을 경우 하위 명령문이 모두 실행되므로 반드시 명시해야 한다.

 

while문은 동일한 처리 과정을 여러 번 반복하며, 무한 루프를 생성하는 데 많이 사용된다. do while 루프는 조건과 관계없이 최소 한 번 실행되는 while문으로, 문장이 반드시 한 번 실행되어야 할 때 유용하다. for문은 특정 횟수만큼 반복할 때 사용되며 주로 배열에 활용되는데 반복 루프를 벗어나기 위해 break문을 사용하고, 현재 반복 과정의 나머지를 건너뛰고 다음 반복을 시작하려면 continue문을 사용한다.

 

3. 배열

Array

배열(array)은 같은 종류의 데이터들이 순차적으로 메모리에 저장되는 자료구조로, 배열명은 곧 주소를 나타낸다. 배열의 특정 인덱스만 초기화하면 나머지 요소들은 쓰레기값으로 채워지며, 범위 기반 for 루프를 통해 배열을 순회할 수 있다.

 

C++의 배열에서 주의할 점은 for 루프에서 변수 i를 사용하면 배열 요소의 복사본이 생성되기 때문에 원본 배열은 수정되지 않는다. 이는 포인터 개념과 관련이 있는데, 배열의 각 요소는 메모리의 특정 주소에 저장되어 있으며, 일반 변수 i는 이 주소를 가리키는 포인터가 아닌 배열 요소의 값을 직접 복사한다. 예를 들어, int i는 arr 배열의 각 요소의 값(예: 1, 2 등)을 복사하여 i에 저장하므로 i를 통해 값을 변경하더라도 arr 배열의 원래 값에는 영향을 주지 않는다. 반면, int& i 참조자를 사용하면 i는 배열 요소의 주소를 참조하는 포인터로 작동하여 원본 배열의 값을 직접 변경할 수 있다. 이러한 방식은 메모리를 보다 효율적으로 사용하고, 복사로 인한 오버헤드를 줄여 실행 속도를 개선하는 효과를 가져온다.

int sal[5] = { 0 }; // 요소를 모두 0으로 초기화 int sales[5] = { 1,2,3 }; // 고전적 초기화 + 초기값 개수가 요소보다 적으면 나머진 0으로 초기화 
int scores[] { 100,200,300 }; // 보편적 초기화 + 선언과 함께 초기화 할 경우 배열 크기 생략 가능
int arr[] = {1, 2, 3, 4, 5};
for (int i : arr) {
    i += 10; // 이 줄은 i의 값을 10 증가시키지만, arr 배열은 변경되지 않음
}
for (int& i : arr) {
    i += 10; // 이 줄은 arr 배열의 각 요소를 직접 변경
}
 
Two-Dimenstional Array

2차원 배열은 배열의 배열로 구성된 자료구조로 주로 2차원 테이블 형태로 데이터를 저장하는 데 사용된다. 이 구조에서 첫 번째 인덱스는 행 번호를 나타내고, 두 번째 인덱스는 열 번호를 나타낸다. 예를 들어 int arr[3][4]라는 2차원 배열이 있을 경우 이 배열은 3개의 행과 4개의 열로 구성되며 각 요소는 arr[0][0], arr[0][1]와 같이 행과 열의 인덱스를 통해 접근할 수 있다. 이를 통해 행렬 계산, 이미지 데이터 처리 등 다양한 응용 분야에서 효과적으로 데이터를 관리하고 사용할 수 있다.

int s[3][5] = { NULL }; // 2차원 배열 선언 
int s[3][5] {{1,2,3,4,5},{2,4,6,8,10},{3,6,9,12,15}}; // 선언과 동시에 초기화

 

함수 포인터를 이용하면 C++ 스타일로 2차원 배열을 출력할 수 있다. 예를 들어, int arr4[3][3]라는 2차원 배열이 있을 때, for (int(&ln)[3] : arr4) 구문을 사용하여 각 행을 참조하는 ln이라는 레퍼런스를 생성할 수 있다. 이때 ln은 arr4의 각 행을 가리키며 내부 for 루프인 for (int col : ln)을 통해 각 열의 값을 순회하면서 출력할 수 있다. 이 방법을 사용하면 cout << col << " "와 같이 각 요소를 C++ 스타일로 간편하게 출력할 수 있어 가독성이 높고, 코드의 의도를 명확하게 전달할 수 있다.

for (int(&ln)[3] : arr4) { for (int col : ln) { cout << col << " "; } } //포인터를 이용하여 c++ 스타일로 2차원 배열 출력
 

4. 함수

Function

함수(function)는 특정 작업을 수행하고 그 결과를 반환하는 코드 블록으로 내장 함수사용자 정의 함수가 있다. 함수는 선언부구현부로 나뉘며, 선언부는 반환형, 함수 이름, 매개변수를 차례로 명시하는 가장 중요한 부분이다. 예를 들어, int max(int x, int y)는 선언부이며, { if(x > y) return x; else return y; }는 구현부로 함수가 수행할 내용을 담고 있다.

int max(int x, int y) // 선언부는 반환형 - 함수의 이름 - 매개변수를 차례대로 적음
{if(x>y) return x; else return y; } // 구현부는 중괄호 부분 함수가 수행에 필요한 문장 작성

함수 원형은 함수가 정의되기 전에 미리 작성하여 컴파일러에게 매개변수 검사와 반환형 검사를 알리는 역할을 한다. 함수 호출 시 인수를 전달하는 방법에는 값으로 호출(call by value) 참조로 호출(call by reference)이 있다. 값으로 호출은 인수의 값이 매개변수로 복사되어 원본 변수에 영향을 주지 않으며 안정성을 제공한다. 반면, 참조로 호출은 원본 인수가 함수에 전달되어 매개변수를 변경하면 원본 인수도 변경된다. 

int square(int, int); // 함수 원형 정의
int& ref = var; // 참조자 ref는 변수 var의 별명으로 값을 대입하면 참조하는 변수의 값이 변경

중복 함수(Overloading)는 동일한 이름의 함수가 매개변수 형태에 따라 여러 개 정의될 수 있게 하며 디폴트 인수(default argument)는 매개변수가 주어지지 않을 때 기본값을 사용할 수 있도록 한다. 예를 들어, void display(char c = '*', int n = 10)에서 인수가 제공되지 않으면 기본값으로 출력된다. 주의할 점은 디폴트 인수는 반드시 마지막 인수여야 한다. 

void display(char c = '*', int n = 10) { ~ } //디폴트 인수로 인수가 전달되지 않으면 디폴트 출력

 

인라인(inline) 함수는 C++에서 짧고 자주 호출되는 함수를 정의할 때 주로 사용하는 함수이다. 일반적으로 함수는 호출될 때마다 함수의 본체가 메모리에서 실행되지만, 인라인 함수는 컴파일러에게 이 함수를 호출하는 위치에 함수의 코드를 직접 삽입하라고 요청한다. 이렇게 하면 함수 호출에 필요한 시간과 자원을 줄일 수 있어 성능을 향상시킬 수 있다.

inline int square(int x) {
    return x * x;
}
int result = square(5); // 컴파일러는 이 부분을 int result = 5 * 5;로 변환

 

대표적인 내장 함수인 string 클래스에서 주의할 점은 입력 시 공백을 인식하지 않기 때문에 getline(cin, sentence);와 같은 별도의 함수를 사용하여 공백을 포함한 문자열을 입력받아야 한다는 것이다.

getline(cin, sentence); // string 클래스 공백 입력