#include <iostream>
/*
함수: 원하는 코드를 모아서 구현을 해놓은 뒤에 원할때마다 해당 코드를 동작시켜줄 수 있게 해주는 기능을 함수라고 한다.
함수의 형태
반환타입 함수이름(인자)
{
동작시킬 코드
}
반환타입: 이 함수를 동작시키고 이 함수에서 원하는 결과가 있을 경우 그 결과를 얻어오고자 할 때 해당 결과의 변수 타입을 지정하면 된다.
void를 반환타입으로 사용한다면 결과를 반환하는 것이 없다. 라는 의미로 사용하게 된다.
int를 반환타입으로 사용한다면 이 함수를 실행하고 결과로 정수를 얻어오고자 할 때 int를 반환타입으로 사용하는 것이다.
return 키워드를 이용해서 함수의 결과를 반환한다.
함수이름 : 원하는대로 이름을 만들어 줄 수 있다.
단, 이 함수가 수행하는 기능에 맞는 이름을 잘 작성해 주어야 한다.
인자 : 있을수도 있고 없을수도 있다.
인자는 이 함수의 기능을 수행하기 위해서 이 함수의 외부에서 어떤 값을 넘겨주어야 할 경우 사용한다.
인자에 변수를 선언해서 이 함수를 호출할떄 해당 변수에 값을 넘겨주도록 하여 함수 내에서 코드가 동작될때 그 값을 이용하여 원하는 기능을 만들어주는 개념이다.
*/
//이 함수는 반환타입은 int라서 반드시 정수를 반환해야 하고 인자는 int타입 인자 2개를 받고 있다.
int Add(int Number1, int Number2)
{
//인자로 들어온 2개의 정수를 서로 더하여 그 결과를 반환하게 한다.
return Number1 + Number2;
}
void TestFunction(int* Number) //이럴 경우 메모리 릭이 발생할 수 있다.
{
int Number2 = 500;
Number = &Number2;
//지역변수 --> 함수가 종료되면 해당 포인터가 가리키는 주소는 할당이 해제됨. 에러가 발생할 수 있다.
}
void TestFunction1(int** Number) //방지하기 위해서는 이중 포인터를 사용해야 한다.
{
int Number2 = 500;
*Number = &Number2;
std::cout << "Number2 Addr : " << &Number2 << std::endl;
//하지만 이 경우에도 함수가 종료되면 &Number2가 해제되므로 에러가 발생한다.
}
void TestFunction2(int*& Number)
//포인터의 레퍼런스. 포인터 변수의 값을 레퍼런스로 받아서, 해당 포인터 변수의 값을 변경할 수 있다.
{
int Number2 = 500;
Number = &Number2;
std::cout << "Number2 Addr : " << &Number2 << std::endl;
//하지만 이 경우에도 함수가 종료되면 함수 내부에서 선언된 Number2라는 공간이 해제되므로 에러가 생길 것이다.
}
int main()
{
//함수를 호출하여 함수에 구현되어 있는 코드를 동작되게 한다.
//아래처럼 호출하면 Add함수의 Number1과 Number2에 10과 20이 각각 들어가게 된다.
//그리고 그 결과를 반환하여 Number 변수에 넣어주고 있다.
int Number = Add(10, 20);
std::cout << "Add(1,2) = " << Add(1, 2) << std::endl;
//main 함수에 코드가 많아지면 매우 복잡해지므로
//함수로 깔끔하게 정리해서 짜는 것이 좋다.
int Number1 = 100, Number2 = 300;
std::cout << Add(Number1, Number2) << std::endl;
//이렇게 할 경우 Main 함수의 Number1, Number2를 가져와서 함수의 새 공간에 그대로 값을 붙여넣고,
//계산을 한 뒤 또 새 공간을 만들어 해당 내용을 넣고
//함수에 만들었던 새 공간을 지운다.
//만약 반환된 메모리 공간도 따로 변수에 저장되지 않았을 경우
//다음 줄에서 해당 공간도 지워진다.
int* pNumber = new int;
delete pNumber;
//*pNumber = 500;
//만약 위처럼 할 경우 댕글링포인터가 된다.
// 위에서 메모리를 제거했는데 그 메모리에 접근하려고
// 하기 때문에 문제가 된다.
int* pNumber1 = nullptr;
TestFunction(pNumber1);
std::cout << "\nTestFunction(pNumber1) = " << pNumber1 << std::endl;
//std::cout << "pNumber = " << *pNumber1 << std::endl;
//pNumber1 을 nullptr로 초기화 한 뒤 TestFunction에서 값을 바꾸었지만 그대로 nullptr이라 접근이 불가능한 것을 알 수 있다.
TestFunction1(&pNumber1);
std::cout << "\nTestFunction1(&pNumber1) = " << pNumber1 << std::endl;
std::cout << "pNumber = " << *pNumber1 << std::endl;
//역시나 쓰레기값이 출력된다.
*pNumber1 = 999;
std::cout << "*pNumber1 = 999;" << std::endl;
std::cout << "pNumber = " << *pNumber1 << std::endl;
//여기선 정상적으로 값이 할당되었음.
TestFunction2(pNumber1);
std::cout << "TestFunction2(pNumber1) = " << pNumber1 << std::endl;
std::cout << "pNumber = " << *pNumber1 << std::endl;
//이전에 999로 초기화를 했으나
//함수를 거치면서 할당이 해제된 메모리 값이 포인터 변수에 들어가면서 다시 쓰레기값이 나오고 있다.
return 0;
}