c++

20210719 포인터,함수 ~ 과제

TIN9 2021. 7. 20.
반응형

안녕하세요 틴구입니다

오늘은 저번 주에 이어서 포인터와 함수에 대해서 알아보도록 합시다!!

먼저 포인터에 대해서 더 알아보도록 할게요

포인터도 결국 메모리 주소를 저장하는 변수이기 때문에 const를 이용해서 상수로
만들어줄 수 있습니다.
포인터 변수를 const를 붙여주는 방법은 크게 3가지의 방법이 있는데
const int* 처럼 앞에 붙이는 방법 : 참조하고 있는 변수의 값을 변경할 수 없다.
int* const 처럼 뒤에 붙이는 방법 : 참조하고 있는 메모리 주소를 변경할 수 없다.
const int* const 둘 다 붙이는 방법 : 둘 다 안된다.

이렇게 3가지가 있습니다

 

포인터 변수의 경우

int Number = 10;

int Number1 = 20;

int *pNumber = &Number;

pNumber = &Number1;

*pNumber = 399;

를 이용해 주소와 값을 둘 다 바꿀 수 있지만

 

const int*의 경우

cont int* cpNumber = &Number;

cpNumber = Number1;

는 가능하지만

*cpNumber = 500;

은 불가능하다.

 

int* const의 경우

int* const cpNumber = &Number;

*cpNumber = 599;

는 가능하지만

cpNumber = Number1;

은 불가능하다

 

const int* const의 경우

const int* const cpNumber = &Number;

*cpNumber = 499;

cpNumber = Number1;

둘 다 불가능합니다

 

다중포인터

다중포인터란 포인터 변수의 주소를 저장하는 포인터를 만드는 것을 의미한다

포인터도 변수이기 때문에 메모리에 공간이 할당될 수 있습니다.

32bit일때는 4바이트 64bit일 때는 8바이트가 할당이 됩니다.

일반 변수의 주소는 포인터 변수에 저장하고 포인터 변수의 주소는 포인터의 포인터 변수에 저장하는 개념입니다.

int Number = 100;
int* pNumber = &Number;
int** ppNumber = &pNumber;
int*** pppNumber = &ppNumber;

이런 식의 형태로 이루어져 있습니다.

그리고 포인터도 변수이기 때문에 다 Null로 초기화해주어야 합니다

또 일반 포인터를 사용할 때 다른 주소 넣어줄 거 아니면 nullptr;로 초기화를 해주어야 합니다

int* pNumber;  ---- X

int* pNumber = nullptr;  ---- O

이런 식으로 말이죠!!

 

또 구조체를 이용한 포인터도 가능합니다.

 

struct Player

{

    int Attack;

    int HP;

    int MP;

}

 

Player  Player;

Player* pPlayer = &Player;

이런식으로 사용이 가능하다.

근데 구조체 포인터를 사용할 때 주의해야 하는 게 있다

역참조보다 . 이 연산자 우선순위가 높기 때문에

그냥 *pPlayer.Attack 이런 식으로 사용하면 문제가 됩니다.

Attack변수에 대한 역참조가 돼버리고 포인터 변수는 실제 구조체 크기만큼 메모리가 만들어져서

사용되는 변수가 아니기 때문에 참조하는 Player의 Attack 변수에 접근하는 것이 아니게 됩니다.

연산자 우선순위로 인해 (*pPlayer)를 하고 .을 이용해 접근해야 합니다.

(*pPlayer).Attack = 100; 

이런 식으로 사용이 가능합니다 

pPlayer->Attack = 100;

으로도 사용이 가능합니다.

둘 다 동일함

void

void는 타입이 없는 것을 의미하고

void* 타입은 어떤 타입의 메모리 주소든 모두 저장할 수 있습니다.

ex)

int Number = 100;

Number* pNumber = &Number;

float NumberF = 3.14f;

NumberF* pNumberF = &NumberF

void* pTest = &Number;

pTest = &Player;

pTest = &NumberF;

 

단 void* 는 역참조가 불가능합니다.

역참조라는 것은 포인터 타입이 무엇이냐에 따라 하는 것인데 void는 타입이 없다는 것을 의미하기 때문에

역참조가 불가능합니다.

void*는 단순하게 메모리 주소를 저장해두는 용도로만 사용이 됩니다.

실제 역참조를 하기 위해서는 정확하게 넣어준 타입으로 형변환을 통해서 역참조를 해야 한다.

((Player*)pTest)->Attack = 300;

 

함수

함수란 같은 코드를 여러 번 동작시킬 경우 함수로 미리 만들어두고 해당 함수를 원하는 곳에서

호출만 하면 해당 코드가 동작될 수 있게 만들어주는 기능입니다.

 

함수의 형태

반환타입 함수이름(인자)

{

    동작될 코드

}

의 형태로 구성되어 있습니다.

 

반환타입이란 이 함수가 특정 코드를 수행하고 어떤 결과를 호출한 곳으로 전달할 필요가 있다면

반환타입을 이용해서 전달할 값의 타입을 지정하고 반환해주면 됩니다.

정수를 반환해야 한다면 반환타입을 int로 하고 return 원하는 값; 을 통해서 해당 함수의

어느 곳에서든지 값을 반환하게끔 만들어줍니다.

 

함수 이름은 이 함수가 동작할 기능에 맞는 정확한 이름을 작성해주는 것을 말합니다 a, b, c 이런 단순한 이름 x

 

인자란 있어도 되고 없어도 됩니다. 만약 이 함수를 사용할 때 이 함수에 데이터를 전달할 필요가 있을 경우 인자를 이용해서 함수로 데이터를 전달해주게 됩니다.

인자는 해당 함수 내에서만 사용할 수 있는 변수입니다.

인자는 해당 함수가 호출이 되면 그때 메모리에 공간이 만들어지게 되고 해당 함수가 종료되면 메모리는 제거됩니다

메모리가 제거되는 방법은 함수 호출 규약에 의해서 제거가 됩니다.

 

반환 타입을 이용해서 함수의 결과를 반환하는 형태를 Call By Value라 하고

함사의 인자에 포인터 타입을 이용해서 포인터 변수를 역참조하여 결과를 반환하는 형태를 Call By Address라고 합니다.

 

또 반환 타입에 void 를 사용하면 반환값을 return 안 해도 됩니다
return 은 이 함수를 종료시키고 이 함수의 수행된 결괏값을 반환할 때 사용합니다.
void 타입의 반환타입을 갖는 함수에서는 return; 을 통해서 원할 때 이 함수를
종료시킬 수도 있는 것이다.

함수의 오버로딩

함수의 오버로딩은 같은 이름으로 여러 개의 함수를 만들어줄 수 있는 기능이다.
단, 이름이 같다면 반드시 인자의 개수 혹은 타입이 달라야 한다.
반환타입은 오버로딩에 영향이 없다.
ex)
void ChangeNumber(int Number)
{
    Number = 9999;
}

void ChangeNumber(float Number)
{
    Number = 3.14f;
}

과제

이번 과제는 저번에 풀이했던 빙고게임을 함수를 사용해 만드는 거예요!

한번 바로 해볼까요???


#include <iostream>
#include <time.h>

/*
* 작성자 : 주윤상
* 작성일 : 2021.07.19
* 함수 : void BingoSet, void BingoSet, void OutputBingo, 
  int BingoInput, int BingoCheck, void SelectNumber1
* 내용 : 함수와 포인터를 이용해 빙고게임을 출력하기
*/

// 빙고판 숫자를 1 ~ 25를 만들기
void BingoSet(int* pNumber)
{
    for (int i = 0; i < 25; ++i)
    {
        pNumber[i] = i + 1;
    }
}
// 빙고판 숫자 섞기
void BingoRand(int* pNumber)
{
    for (int i = 0; i < 100; ++i)
    {
        int Index1 = rand() % 25;
        int Index2 = rand() % 25;

        int Temp = pNumber[Index1];
        pNumber[Index1] = pNumber[Index2];
        pNumber[Index2] = Temp;
    }
}
// 빙고판 숫자 출력
void OutputBingo(int* pNumber)
{
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            if (pNumber[i * 5 + j] == INT_MAX)
            {
                std::cout << "*\t";
            }
            else
            {
                std::cout << pNumber[i * 5 + j] << "\t";
            }
        }
        std::cout << std::endl;
    }
}
// Player 숫자 선택
int BingoInput(int Input)
{
    std::cout << "숫자를 입력하세요" << std::endl;
    std::cout << "Exit : 0" << std::endl;
    std::cin >> Input;
    return Input;
}

// 빙고 출력을 위한 Check
int BingoCheck(int Number[])
{
    int Check1 = 0;
    int Check2 = 0;
    int Bingo = 0;

    for (int i = 0; i < 5; ++i)
    {
        Check1 = 0;
        Check2 = 0;
        for (int j = 0; j < 5; ++j)
        {
            if (Number[i * 5 + j] == INT_MAX)
            ++Check1;

            if (Number[j * 5 + i] == INT_MAX)
            ++Check2;
        }

        if (Check1 == 5)
            ++Bingo;

        if (Check2 == 5)
            ++Bingo;
    }

    Check1 = 0;

    for (int i = 0; i < 25; i += 6)
    {
        if (Number[i] == INT_MAX)
            ++Check1;
    }

    if (Check1 == 5)
        ++Bingo;

    Check1 = 0;

    for (int i = 4; i <= 20; i += 4)
    {
        if (Number[i] == INT_MAX)
            ++Check1;
    }

    if (Check1 == 5)
    ++Bingo;

    return Bingo;
}

// AI
void SelectNumber1(int* pNumber, int* pSelectNumber, int SelectCount, int Input)
{
    for (int i = 0; i < 25; ++i)
    {
        if (pNumber[i] != INT_MAX)
        {
            pSelectNumber[SelectCount] = pNumber[i];
            ++SelectCount;
        }
    }

    int SelectIndex = rand() & SelectCount;
    Input = pSelectNumber[SelectIndex];
}


int main()
{
    srand((unsigned int)time(0));
    rand();

    int Number[25] = {};
    int AINumber[25] = {};

    BingoSet(Number);
    BingoSet(AINumber);

    BingoRand(Number);
    BingoRand(AINumber);

    int Bingo = 0;
    int AIBingo = 0;

    int SelectNumber[25] = {};
    int SelectCount = 0;

    while (true)
    {
        system("cls");
        std::cout << "========== Player ==========" << std::endl;
        OutputBingo(Number);

        std::cout << std::endl;
        std::cout << "Bingo : " << Bingo << std::endl;
        std::cout << std::endl;

        std::cout << "============ AI ============" << std::endl;

        OutputBingo(AINumber);

        std::cout << std::endl;
        std::cout << "AIBingo : " << AIBingo << std::endl;
        std::cout << std::endl;

        int Input = 0;
        Input = BingoInput(Input);

        if (Input == 0)
            break;

        else if (Input < 0 || Input > 25)
            continue;

        if (Bingo >= 5)
        {
            std::cout << "Player 승리" << std::endl;
                break;
        }
        else if (AIBingo >= 5)
        {
            std::cout << "AI 승리" << std::endl;
                break;
        }
        bool Find = false;

        for (int i = 0; i < 25; ++i)
        {
            if (Number[i] == Input)
           {
                Find = true;
                Number[i] = INT_MAX;
                    break;
            }
        }

        if (Find == false)
            continue;

        for (int i = 0; i < 25; ++i)
        {
            if (AINumber[i] == Input)
            {
                AINumber[i] = INT_MAX;
                    break;
            }
        }

        SelectNumber1(Number, SelectNumber, SelectCount, Input);


        Bingo = BingoCheck(Number);
        AIBingo = BingoCheck(AINumber);


    }
    return 0;
}

이렇게 만들어 보았습니다!!

그럼 다음 시간에 만나요~~

반응형

댓글