본문 바로가기
C++ 공부

C++ 공부 2일차(배열, 성적 관리 프로그램 만들기, 함수, 두 수의 합을 반환하는 함수 만들기)

by unrealstudy-jin 2025. 8. 12.

배열

배열을 사용해야 하는 이유

변수의 개수가 적다면 하나씩 선언하고 값을 입력 해도 되지만 만약 1000개 이상 이라면 하나씩 선언 하고 입력을 하려면 변수 선언과 입력 자체가 쉽지 않고 하더라도 코드의 길이가 많이 길어진다.

모두 같은 성격의 데이터라면 하나의 구조(배열)로 관리하는 것이 효율적이다.

배열을 사용하면 같은 타입의 여러 데이터를 하나의 묶음으로 관리할 수 있고 반복문을 활용하여 데이터를 처리할 수 있다.

 

배열 문법

배열은 동일한 타입의 여러 값을 한꺼번에 담을 수 있는 자료 구조이다.

예를 들어, 4명의 학생 점수를 저장하려면 다섯 개의 변수를 만드는 대신, 크기가 4인 배열 하나를 만들면 됩니다.

 

배열의 특징

1. 배열은 임의 접근이 가능하다.

배열의 이름은 하나이고, 여러 개의 변수를 나열한 자료구조이기 때문에 접근할 수 있는 방법이 필요하다.

배열은 [ ]연산자를 통해서 각 원소에 접근할 수 있습니다. [ ]연산자를 통해 특정 원소에 접근하는 것을 임의 접근이라고 한다.

[ ] 연산자는 배열첨자연산자 라고 한다.

예를 들어, int arr[4]와 같이 크기가 4인 정수형 배열의 경우, arr[0]이 맨 처음 원소이고, arr[3]가 제일 마지막 원소이다.

int arr[4] 정수형 배열

2. 변수와 마찬가지로 배열은 선언과 동시에 초기화 및 선언 후 추후에 초기화가 모두 가능하다.

3. 배열은 통째로 복사 및 대입이 되지 않습니다.

배열의 원소는 일반 변수와 같이 복사 및 대입이 가능하나, 배열 자체를 통째로 대입하는 것은 불가능합니다.

 

예제 1. 배열 선언과 초기화

#include <iostream>
using namespace std;

// 배열 선언과 초기화 예제
int main()
{
    // 선언과 동시에 초기화
    int arr1[3] = {1, 2, 3};

    // 선언 후 개별 원소 초기화
    int arr2[3];
    arr2[0] = 10;
    arr2[1] = 20;
    arr2[2] = 30;

    // 배열 출력
    cout << "arr1: " << arr1[0] << ", " << arr1[1] << ", " << arr1[2] << endl;
    cout << "arr2: " << arr2[0] << ", " << arr2[1] << ", " << arr2[2] << endl;

    return 0;
}

 

예제 1. 결과

 

예제 2. 배열의 복사 및 대입 불가능

#include <iostream>
using namespace std;

// 배열의 복사 및 대입 불가능한 예제
int main()
{
    int arr1[3] = {1, 2, 3};
    int arr2[3];

    // 개별 원소를 복사하는 것은 가능
    for (int i = 0; i < 3; i++) {
        arr2[i] = arr1[i];
    }

    // 배열 통째로 대입 (불가능, 주석 처리)
    // arr2 = arr1;  // 컴파일 오류 발생

    // 복사된 배열 출력
    cout << "arr2: " << arr2[0] << ", " << arr2[1] << ", " << arr2[2] << endl;

    return 0;
}

arr1[0] = 1, arr1[1] = 2, arr1[2] = 3 값을 for문을 이용하여 arr2[i]에 대입해서 각 원소값을 arr2[0] = 1, arr2[1] = 2, arr2[2] = 3로 대입할 순 있지만 arr2 = arr1 처럼 배열 자체를 대입하려 하면 컴파일 오류가 발생한다.

 

예제 2. 결과

 

예제 3. 배열 선언하고 임의접근 하기

#include <iostream>
using namespace std;

// 배열을 선언하고 [] 연산자로 접근하는 예제
int main()
{
    int arr[4] = {10, 20, 30, 40};

    // 배열 원소에 임의 접근하여 출력
    cout << "첫 번째 원소: " << arr[0] << endl;
    cout << "두 번째 원소: " << arr[1] << endl;
    cout << "세 번째 원소: " << arr[2] << endl;
    cout << "네 번째 원소: " << arr[3] << endl;

    // 범위를 벗어난 접근 (에러 발생 가능)
    // cout << arr[4] << endl;  // 정의되지 않은 동작 (UB, 오류 가능)

    return 0;
}

 

예제 3. 결과

 

예제 4. 배열의 입출력

#include <iostream>
using namespace std;

// 배열 원소를 개별적으로 입력 및 출력하는 예제 (반복문 없이)
int main()
{
    int arr[3]; // 크기 3의 배열 선언

    // 각 원소에 대해 개별적으로 입력 받기
    cout << "첫 번째 정수를 입력하세요: ";
    cin >> arr[0];

    cout << "두 번째 정수를 입력하세요: ";
    cin >> arr[1];

    cout << "세 번째 정수를 입력하세요: ";
    cin >> arr[2];

    // 각 원소 개별 출력
    cout << "입력한 값: " << arr[0] << ", " << arr[1] << ", " << arr[2] << endl;

    return 0;
}

 

예제 4. 결과

성적 관리 프로그램 만들기

1. 학생 5명의 입력받은 성적을 저장할 수 있어야 합니다. => 배열 선언

2. 입력 성적들의 합을 구할 수 있어야 합니다. => cin, +

3. 입력받은 성적들의 평균을 구할 수 있어야 합니다. => cin, /

결과

 

함수

프로그래밍을 하다 보면 반복적으로 사용되는 코드나 논리적으로 하나로 묶이는 코드가 있다.

이런 코드를 이름을 붙여 정의하고 가져다 쓰는 방식으로 구현하면 코드가 깔끔해지고 재사용성이 높아진다.

이렇게 작업을 정의하고 이름을 붙이는 문법을 함수라고 한다.

 

함수의 구성 요소

1. 인자 : 함수에 사용되는 외부 값. 위 그림에서 num1, num2에 해당함.(= 입력 값)

2. 동작 : 어떤 작업을 수행할지 정의함. 위 그림에서 더하기 연산에 해당됨.

3. 반환 : 작업을 수행한 후 최종적으로 외부에 전달할 값(= 결과 값). 위 그림에서는 더한 값을 반환한다.

반환은 필수가 아니고 반환하지 않는 함수를 만드려면 반환 타입void로 하면 된다.

4. 이름 : 이 작업을 호출하기 위한 이름이 필요하다.

 

예시 1. 두 정수를 더하는 함수 정의 및 호출

// 목적: 두 개의 정수를 더하는 함수 정의 및 호출 예제
#include <iostream>
using namespace std;

// 두 정수를 더하는 함수
int add(int a, int b)
{
    return a + b; // 결과 반환
}

int main()
{
    int result = add(3, 7);
    cout << "3 + 7 = " << result << endl; // 출력: 3 + 7 = 10
    return 0;
}

인자는 int a, int b / 동작은 더하기 / 반환은 a + b / 이름은 add이다.

 

예시 1. 결과

 

예시 2. 반환 값이 없는 함수(void)

// 목적: 반환값 없이 특정 메시지를 출력하는 함수
#include <iostream>
using namespace std;

// 메시지를 출력하는 함수 (반환 없음)
void printMessage()
{
    cout << "Hello, Function!" << endl;
}

int main()
{
    printMessage(); // 함수 호출
    return 0;
}

 

예시 2. 결과

 

예시 3. 잘못된 함수 정의(void함수에 반환 값 넣기)

// 목적: 반환값이 없는데 반환하는 오류 발생 예제
#include <iostream>
using namespace std;

// 잘못된 함수 정의
void incorrectFunction() {
    return 42; // 오류 발생: void 함수는 값을 반환할 수 없음
}

int main() {
    incorrectFunction();
    return 0;
}

 

예시 3. 결과

오류 발생

오류가 발생했을 때 마구잡이로 수정하기 보다 에러 메세지를 읽어보고 해결을 해야 똑같은 에러 발생시 해결할 수 있다.
구글 검색이나 gpt에 에러 몌세지를 복사하면 에러의 원인이 거의 나온다.

두 수의 합을 반환하는 함수 만들기

인자

이 함수는 정수형 변수 2개를 외부 값으로부터 받습니다.

동작

인자로 받은 두 수를 더해서 반환합니다.

반환

함수의 반환 타입은 정수형입니다.

이름

함수의 이름은 add입니다.

함수에서 값을 전달하는 방법

1. 값 전달 (일반 변수)

C++에서 일반적인 변수(값 타입 변수)는 값을 복사하여 함수로 전달됩니다.

따라서 함수 내부에서 값을 변경해도 원본 변수의 값은 변경되지 않습니다.

#include <iostream>
using namespace std;

// 함수: 값 전달 (Call by Value)
void modifyValue(int x)
{
    x = 100;  // 함수 내부에서 값 변경
}

int main()
{
    int num = 50;
    modifyValue(num); // 값 전달 (복사됨)
    
    cout << "값 전달 후 num: " << num << endl;

    return 0;
}
    // 출력: 값 전달 후 num: 50

2. 주소값 전달 (변수 - 포인터 사용)

C++에서 변수의 주소값을 함수에 전달하면, 해당 변수에 접근할 수 있게 됩니다.

따라서 함수가 종료가 된 이후에도 해당 주소의 변수는 값이 수정되어 있습니다.

포인터에 대해서는 다음 글에서 자세하게 공부할것이다.

#include <iostream>
using namespace std;

// 함수: 포인터를 사용한 값 변경
void modifyValue(int* ptr)
{
    *ptr = 100;  // 포인터가 가리키는 변수의 값을 변경
}

int main()
{
    int num = 50;
    modifyValue(&num); // num의 주소 전달

    cout << "포인터 전달 후 num: " << num << endl;

    return 0;
}
    // 출력: 포인터 전달 후 num: 100

3. 주소값 전달 (배열 -  포인터 사용)

C++에서 배열의 주소값을 함수에 전달하면, 해당 배열에 접근 할수 있게 됩니다.

따라서 함수가 종료가 된 이후에도 해당 배열의 값이 수정되어 있습니다.

(포인터의 원리를 생각해 보면 변수를 전달하는 경우와 동일합니다.)

#include <iostream>
using namespace std;

// 함수: 포인터를 사용한 값 변경
void modeifyArr(char* ptr)
{
    ptr[0] = 'X';  // 포인터가 가리키는 변수의 값을 변경
}

int main()
{
    char str[4] = {'A', 'B', 'C', 'D'};
    modeifyArr(str); // num의 주소 전달

    cout << "포인터 전달 후 str[0] = " << str[0] << endl;

    return 0;
}
    // 출력: 포인터 전달 후 str[0] = X

4. 참조자 전달

참조자로 값을 전달하면, 함수 내부에서 값을 변경할 때, 원본 변수의 값도 변경됩니다.

#include <iostream>
using namespace std;

// 함수: 참조를 사용한 값 변경
void modifyValueByReference(int& x) {
    x = 200;  // 참조를 사용하여 원본 값 변경
}

int main() {
    int num = 50;
    modifyValueByReference(num); // 참조 전달

    cout << "참조 전달 후 num: " << num << endl;

    return 0;
}
    // 출력: 참조 전달 후 num: 200

함수가 사용되는 예시

예시 1. 원의 넓이 계산

#include <iostream>
using namespace std;

/**
 * @brief 반지름을 입력받아 원의 넓이를 계산하는 함수
 * @param radius 원의 반지름
 * @return double 원의 넓이
 */
double calculateCircleArea(double radius)
{
    return 3.14 * radius * radius;
}

int main()
{
    double radius = 5.0;
    cout << "원의 넓이: " << calculateCircleArea(radius) << endl;
    return 0;
}

현재 calculateCircleArea함수의 radius와 main함수의 radius가 이름이 같아서 헷갈리는데 둘은 같은 공간(변수)이 아니다.

 

예시 1. 결과

 

예시 2. 평균 계산

#include <iostream>
using namespace std;

/**
 * @brief 4개의 점수를 입력받아 평균 점수를 계산하는 함수
 * @param score1 첫 번째 점수
 * @param score2 두 번째 점수
 * @param score3 세 번째 점수
 * @param score4 네 번째 점수
 * @return int 평균 점수 (소수점 제외)
 */
int calculateAverage(int score1, int score2, int score3, int score4)
{
    int sum = score1 + score2 + score3 + score4;
    return sum / 4; // 정수 나눗셈으로 소수점 없이 계산
}

int main()
{
    int score1 = 80, score2 = 90, score3 = 85, score4 = 70;
    cout << "평균 점수: " << calculateAverage(score1, score2, score3, score4) << endl;
    return 0;
}

 

예시 2. 결과

 

예시 3. 이름 형식 변환

#include <iostream>
#include <string>
using namespace std;

/**
 * @brief 이름과 성을 입력받아 "성 이름" 형식으로 변환하는 함수
 * @param firstName 이름
 * @param lastName 성
 * @return string 변환된 이름
 */
string formatName(string firstName, string lastName)
{
    return lastName + " " + firstName; // 문자열 결합
}

int main()
{
    string firstName = "철수";
    string lastName = "김";
    cout << "이름 형식 변환: " << formatName(firstName, lastName) << endl;
    return 0;
}

문자열의 합에서는 문자열끼리 이어진다.

 

예시 3. 결과

 

예시 4. 점수 출력

#include <iostream>
using namespace std;

/**
 * @brief 네 개의 점수를 받아 합계를 계산하고 출력하는 함수
 * @param score1 첫 번째 점수
 * @param score2 두 번째 점수
 * @param score3 세 번째 점수
 * @param score4 네 번째 점수
 */
void printTotalScore(int score1, int score2, int score3, int score4)
{
    int total = score1 + score2 + score3 + score4; // 점수 합계 계산
    cout << "점수 합계: " << total << endl;
}

int main()
{
    printTotalScore(80, 90, 85, 70); // 합계 출력
    return 0;
}

 

예시 4. 결과