C++ 프로그래밍 03 - 언어의 기초(2)

Wonil Jang·2024년 10월 17일

컴퓨터과학

목록 보기
12/12
post-thumbnail

해당 포스트는 강의를 수강 후 개인적으로 이해한 부분을 글로 기록하고 해석하기 위한 목적으로 이해한 부분이 틀릴수도 있습니다. 잘못 이해하고 있거나 틀린 부분에 대해서는 편하게 지적해 주시면 수정하겠습니다.

1. 흐름제어 구문

  • 프로그램의 진행을 제어 할 수 있는 구문
  1. 기본적인 흐름제어 구조

    1. 순차 구조

      • 문장이 나열된 순서에 따라 차례로 실행하는 구조
    2. 조건제어 구조

      • 지정된 조건에 따라 실행 흐름을 제어하는 구조
      • if문, swtich문
    3. 반복제어 구조

      • 정해진 범위의 문장을 반복적으로 실행하게 하는 구조
      • for문, while문, do ... while문

2. 조건문 - if

if(a > b) // 조건
	cout << a << endl; // if문의 조건이 참일 때 실행 구문
else 
	cout << b << endl; // if문의 조건이 거짓일 때 실행 구문

조건이 참인 경우에만 실행 구문이 있는 경우 else 구문은 생략할 수 있다.

3. 조건문 - switch

  • if문은 일반적인 모든 조건을 판단하는데 활용할 수 있지만 switch문은 정수형 수식에 대한 판단을 한다.
  • case마다 break 명령어가 없는 경우 다음 case도 실행한다.
// 코드 예제, int형 변수 score의 값에 따라 A ~ F의 학점 부여하는 코드
switch(score / 10) {
  case 10:
  case 9: 
      grade = 'A'
      break;
  case 8:
      grade = 'B'
      break;
  case 7:
      grade = 'C'
      break;
  case 6:
      grade = 'D'
      break;
  default: 
      grade = 'F'
}

4. 반복문 - for 루프

  1. for문 사용 형식
    • 정해진 횟수 만큼 반복하고자 하는 경우 사용
    for(초기화_문장; 반복조건; 증감_문장) {
    	반복 실행할 구문
    }
    // 코드 예제, 10개의 정수 값을 입력하여 합계 구하기
    int val, total = 0;
    for(int i = 0; i < 10; i++) {
    	cin >> val;
        total += val;
    }
    1. 범위 기반 for 루프 (C++ 11 이후)
    for(원소선언 : 데이터집합) {
    	반복 실행 구문
    }
    // 코드 예제, 배열 안의 모든 값을 합산 하기 
    int arr[5] = {2, 3, 9, 4, 7};
    int sum = 0;
    for(int a : arr)
    	sum += a;
    cout << "합계 = " << sum << endl;

3. 반복문 - while 루프

  • 조건을 판단한 후 참일 경우 반복 구문을 실행한다.
while(반복조건) {
	반복 실행 구문
}
// 코드 예제, 10개의 정수 값을 입력하여 합계 구하기
int val, total = 0;
int i = 0;
while(i < 10) {
	cin << val;
	total += val;
	i++;
}

4. 반복문 - do ... while 루프

  • while 루프와 비슷하지만 조건을 판단하는 순서가 다르다. 반복 문장을 실행한 후 조건을 판단하여 조건이 참인 경우 반복 실행 구문(do)을 반복하여 실행한다.
do
	반복 구문;
while(반복 조건);

2. 구조체와 클래스

1. 구조체

  1. 구조체란
  • 여러 가지 자료형의 데이터 집합을 저장할 수 있는 새로운 자료형을 정의한 것
  1. 구조체 선언문 형식
struct StructName {
	Type1 item1;
    Type2 item2;
    .
    .
    .
};
  1. 구조체의 예
// 2차원 좌표
struct C2dType {
 	double x, y;
};

// 원
struct CircleType {
	C2dType center;
    double radius;
};
  1. 구조체 데이터를 처리하는 함수
  • C 언어에서는 구조체와는 별개의 함수로 정의한다.
// 코드 예제, 원의 면적을 구하는 함수
// 위 구조체의 예의 CircleType과 이어진다. 

double circleArea(CircleType c) {
	return c.radius * c.radius * PI;
};

int main() {
	CircleType c1 = {{0, 0}, 10};

	cout << "원의 면적 : " << circleArea(c1) << endl;
};

2. 클래스

  1. 클래스란?
  • 표현하고자 하는 대상(객체)의 데이터(속성)와 함께 그 대상이 할 수 있는 동작을 나타내는 함수(행위)들을 묶어서 선언한 것
// 코드 예제, '원' 클래스, 위 예제 코드와 이어진다.
class CircleClass {
	C2dType center;
    double radius;
public:
	void init(double cx, double cy, double r) {}
    double area() const {}
    bool chkOverlap(const CircleCalss& c) const {}
    void display() const {}
};

3. 구조체와 클래스의 비교

  • C 언어의 구조체는 구조체와 구조체를 활용한 함수가 모두 별개로 되어있는 반면 C++ 언어의 클래스는 구조체와 구조체를 활용한 함수가 모드 같은 블락 내부에 묶어서 사용할 수 있다.

3. 배열

  • 동일한 자료형의 값을 연속적으로 할당된 공간에 묶어 하나의 이름을 가지는 변수로 만든 데이터
  • 각각의 원소는 0번부터 시작하는 순차적인 번호(인덱스)를 부여 받는다.
  • 배열의 차원: 배열의 인덱스 개수

1. 1차원 배열

  1. 1차원 배열의 선언
float fArray[4]; // 해당 코드에서 [4]의 부분이 배열의 차원
  1. 1차원 배열의 사용
// 코드 예제
float fArray[4];
int i = 0;
fArray[i] = 10.0f;
cin >> fArray[1] >> fArray[2] >> fArray[3];
cout << fArray[1] * fArray[2];

2. 2차원 배열

  • 1차원 배열이 원소인 배열
int Arr2D[4][3];
  • C++ 언어에서 2차원 배열은 메모리 상에 행 우선 순서(row-major order)로 저장한다.

3. 배열의 활용

  1. 배열의 초기화
int a[5] = {1, 2, 3, 4, 5}; // '=' 는 생략 가능하다.
int b[5] = {1, 2, 3}; // b[3]와 b[4]는 0으로 초기화 된다. 
int c[] = {1, 2, 3, 4, 5}; // 배열의 크기를 생략한 경우 배열에 입력한 값의 갯수만큼 지정된다. 
int d[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; // 4개의 데이터를 가지고 있는 1차원 배열이 2개 있는 배열, 2차원 배열 
  1. 여러 개의 데이터 중 최댓값 구하기
int main() {
	int max;
    int data[10] = {10, 23, 5, 9, 22, 48, 12, 10, 55, 31};
    max = data[0];
    cout << "데이터: " << data[0];
    for(int i = 1; i < 10; i++) {
    	cout << " " << data[i];
        if(max < data[i]) max = data[i];
	};
    cout << "\n\n배열의 최댓값: " << max << endl;
    return 0;
};

4. 포인터와 동적 메모리 할당

1. 포인터란?

  • 어떠한 대상이 위치한 곳을 가리키는(주소를 저장하는) 변수
  • 가리키는 대상: 포인터에 지정된 자료형에 해당되는 변수, 동적으로 할당된 메모리, 함수 등

2. 포인터 선언 형식

TypeName* ptrVar;
// TypeName: 가리킬 값의 자료형
// ptrVar: 포인터 변수 이름

3. 포인터의 활용

  1. 포인터의 사용
  • 포인터가 유효한 대상을 가리키게 한 후 사용
ptrVar = &var; // ptrVar이 var을 가리키게 한다. 
*ptrVar = value; // ptrVar을 이용하여 var의 값에 접근
  • &: 주소 계산 연산자
  • *ptrVar: 포인터 ptrVar이 가리키는 곳
// 코드예제
int a;
int* iPtr = &a; // iPtr은 변수 a의 값에 접근할 수 있는 포인터
*iPtr = 10; // iPtr 포인터를 사용하여 a의 변수에 10 할당
  1. 사용 예제
// SimplePt.cpp
#include <iostream>
using namespace std;

int main() {
	int a = 10;
    int* ptr;
    ptr = &a;
    cout << "ptr이 가리키는 값: " << *ptr << endl; // ptr이 가리키는 값: 10
    *ptr = 20;
    cout << "변수 a의 값: " << a << endl; // 변수 a의 값: 20
    return 0;
};

4. 동적 메모리 할당

  1. 동적 메모리 할당이란?
  • 프로그램 동작 중 메모리의 필요성과 소요량을 결정하여 필요한 공간을 할당하는 것

일반적인 변수의 경우 변수의 생성 시점 또는 함수나 프로그램이 끝나는 시점에 따라 생명 주기를 가지게 되지만 동적 메모리 할당의 경우 메모리의 생성 시점과 메모리의 소멸 시점에 따라 생명 주기를 가진다.

  • 메모리 공간의 생성 시점: new 연산자의 실행 시점
  • 메모리 공간의 소멸 시점: delete 연산자의 실행 시점
  • 포인터 변수가 할당된 기억 공간을 가리키게 한다.
  1. 메모리 할당 연산자
ptrVar = new TypeName;
ptrVar = new TypeName[n];
  1. 메모리 반납 연산자
delete ptrVar;
delete [] ptrVar;
  1. 단일 데이터 공간의 할당 및 반환 예제
// 메모리 할당
int* intPtr;
intPtr = new int;
*intPtr = 10;

// 메모리 반납
delete intPtr;
intPtr = nullptr; // nullptr: C++ 11부터 도입된 상수
  1. 배열 데이터 공간의 할당 및 반환 예제
// 메모리 할당 
int* intPtr;
intPtr = new int[4];
*intPtr = 10;
*(intPtr+1) = 20;
intPtr[2] = 30;

// 메모리 반납
delete [] intPtr;
intPtr = nullptr;

5. 참조

1. 참조란?

  • 어떠한 대상을 가리키는 값(포인터와 유사)
  • 참조 변수는 참조 대상의 별명처럼 사용할 수 있다.
  • l-value 참조: 실체가 있는 대상(l-value)에 대한 참조
a = b + 10; // a: l-value, b + 10: r-value, 왼쪽 오른쪽으로 구분 
  • l-value 참조 변수의 선언 형식
TypeName& refVar = varName;

- TypeName: 참조 대상의 자료형
- refVar: 참조 변수의 이름
- varName: 참조 대상

포인터는 초기화가 반드시 필요하지 않지만 참조는 반드시 초기화가 되어야 한다.

2. l-value 참조 변수의 사용 예제

// 참조 변수 예제
int a = 10, b = 20;
int& aRef = a;
cout << aRef << endl;
aRef = 100;
aRef = b;

// 차이를 비교하기 위한 포인터 예제
int a = 10, b = 20;
int* aPtr = &a;
cout << *aPtr << endl;
*aPtr = 100;
*aPtr = b;

3. const 참조

  • const 참조를 사용하면 참조 변수가 참조하는 대상의 값을 바꿀 수 없다.
// 코드 예제
int x {10};
const int& xRef = x;
cout << xRef << endl; // 10
xRef += 10; // error, const 참조 변수여서 값을 수정할 수 없다.

4. 참조가 포인터의 다른 점

  1. 참조 변수를 이용하여 값을 읽거나 저장할 때 참조 대상 변수를 사용하는 형식과 동일하다.

  2. 참조 변수는 초기화를 통해 반드시 어떤 대상을 참조해야 한다.

    • 초기화되지 않은 상태로 인해 무엇을 참조하고 있는지 알 수 없는 상황은 발생하지 않는다.
  3. 참조의 유효기간 동안 하나의 대상만 참조할 수 있기 때문에 초기화를 통해 지정된 참조 대상을 바꿀수 없다.

5. r-value 참조

  1. r-value 참조란?
  • 사용한 후에 값이 더 이상 필요하지 않은 대상을 참조
  1. r-value 참조의 용도
  • 객체의 값을 다른 객체로 이동
profile
아 좀 신나고 싶네! XD

0개의 댓글