함수에서 배열을 어떻게 사용하는지에 대한 수업을 들었다.
#include <iostream>
void func(int arData[3]);
int main()
{
int arMain[3]{ 3,2,1 };
func(arMain);
}
void func(int arData[3])
{
for (int i = 0; i < 3; i++)
{
printf("%d ", arData[i]);
}
printf("\n");
}
코드 요약 :
이 코드는 arData[3] 배열을 함수 인자로 선언하고, main 함수에서 arMain[3] 배열을 선언하여 func에 전달하여 출력하는 코드이지만 이 코드에는 중요한 문제점이 존재한다.
문제점 :
배열은 함수에 인자로 전달될 때 값의 호출 (call by value) 가 아닌 배열의 첫 번째 요소의 주소가 전달이 되게 된다.
컴퓨터는 배열을 통째로 복사를 하게 되면 과부화가 걸리는 것을 인지하고 있기에 선언한 배열을 만들어주지 않는다.
그렇기에 껍대기는 값의 호출 (call by value) 의 모양을 취하고있지만 실상은 값의 호출 (call by value) 를 하지 않는것이다.
즉, 유일하게 배열만 call by value가 먹히지 않으며, 진짜 배열이 아니라 포인터처럼 동작하게 된다.
예시)
#include <iostream>
void func(int arData[3]);
int main()
{
int arMain[3]{ 3,2,1 };
func(arMain);
}
void func(int arData[999])
{
for (int i = 0; i < 3; i++)
{
printf("%d ", arData[i]);
}
printf("\n");
}
위 코드에서도 함수의 인자 크기 arData[999]는 의미가 없는것이다.
컴파일러에서는 함수인자에 []를 붙히게 되면 배열 인자를 포인터로 해석하게 되므로, 배열 크기는 무시되고 단지 배열의 첫 번째 요소의 주소만 전달하게 되는것이다. ( int *arData로 읽게 되는 것이다.)
이유 :
함수 인자에 배열을 사용할 때, 컴파일러는 이를 자동으로 포인터로 변환하여 배열의 시작 주소를 참조하기에
int arData[3]와 int arData[999]는 동일하게 처리되는것이다.
또한 sizeof를 사용하더라도 포인터의 크기가 나오지 배열의 크기가 나오지 않기 때문에 배열의 크기를 함께 전달해 주는 것이다 중요하다.
올바른 코드 작성법:
#include <iostream>
void func(const int *pData, int nLength);
int main()
{
int arMain[3]{ 3,2,1 };
func(arMain,3);
}
void func(const int* pData, int nLength)
{
for (int i = 0; i < nLength; i++)
{
printf("%d ", pData[i]);
}
printf("\n");
}
설명:
- 포인터와 배열 크기를 함수에 명시적으로 전달해야 한다.
- nLength는 배열의 크기를 나타내며, 값에 의한 호출 (Call by Value)로 전달된다.
- 배열의 크기를 전달할 때는 반드시 포인터와 함께 배열 크기를 명시적으로 전달하는 규칙을 따른다.
- 함수에서 배열을 처리할 때 반드시 배열의 크기를 명확히 해야 한다.
- 이 규칙을 지킴으로써 혼동을 방지한다.
문제 1. int 형 두개의 수를 함수로 전달하는 큰 수를 받아오는 함수
#include <iostream>
void maxNumber(int nData1, int nData2, int *nResult);
int main()
{
int n1{};
int n2{};
int nResult{};
scanf_s("%d", &n1);
scanf_s("%d", &n2);
maxNumber(n1, n2, &nResult);
printf("%d\n", nResult);
}
void maxNumber(int nData1, int nData2, int* nResult)
{
int nMax{};
if (nData1 > nData2)
nMax = nData1;
else
nMax = nData2;
*nResult = nMax;
}
문제 2. int 형 배열의 총 합을 얻어오는 함수
#include <iostream>
void sumTotal(const int *pData, int nLength, int *nTotal);
int main()
{
int arData[7]{ 7,6,5,4,3,2,1 };
int nTotal{};
sumTotal(arData, 7, &nTotal);
printf("%d\n", nTotal);
}
void sumTotal(const int* pData, int nLength, int* nSumTotal)
{
for (int i = 0; i < nLength; i++)
{
*nSumTotal += pData[i];
}
}
문제 3. int 형 두개의 숫자를 바꿔주는 함수
#include <iostream>
void exchangeNumber(int nData1, int nData2, int* pData1, int* pData2);
int main()
{
int n1{};
int n2{};
int nResult1{};
int nResult2{};
scanf_s("%d", &n1);
scanf_s("%d", &n2);
exchangeNumber(n1, n2, &nResult1, &nResult2);
printf("교환 전 : %d, %d, 교환 후 : %d, %d\n", n1, n2, nResult1, nResult2);
}
void exchangeNumber(int nData1, int nData2, int* pData1, int* pData2)
{
*pData1 = nData2;
*pData2 = nData1;
}
문제 4. int 형 배열에 특정 숫자를 횟수만큼 입력해주는 함수 ( 0번지부터 순서대로 채워주는 함수 )
#include <iostream>
void printData(int* pData, int nLength, int nNumber, int nFrequency);
int main()
{
int arData[5]{ 5,4,3,2,1 };
int nNumber{};
int nFrequency{};
scanf("%d", &nNumber);
scanf("%d", &nFrequency);
printData(arData, 5, nNumber, nFrequency);
for (int i = 0; i < 5; i++)
{
printf("%d ", arData[i]);
}
printf("\n");
}
void printData(int* pData, int nLength, int nNumber, int nFrequency)
{
if (nFrequency > nLength)
nFrequency = nLength;
for (int i = 0; i < nFrequency; i++)
{
pData[i] = nNumber;
}
}
주의 사항:
- 함수 선언 시, 해당 함수가 어떤 의도로 만들어졌는지 명확하게 표현해야 한다. 즉, 사용자의 입장에서 쉽게 이해할 수 있는 코드를 작성하는 것이 중요하다.
- 함수에 포인터는 하는 일이 많다. 값을 전달, 값의 내용물을 변경, 배열을 전달, 배열을 바꾸는지 이런 다양한 일을 하지만 포인터는 혼자서 이 모든일을 전부 하지 못하기에 인수를 추가하여 사용해야한다.
'C++' 카테고리의 다른 글
[강의] 10월 10일 수업정리 (2) | 2024.10.11 |
---|---|
[강의] 10월 4일 수업정리 (1) | 2024.10.05 |
[강의] 10월 1일 수업정리 (1) | 2024.10.01 |
[강의] 9월 27일 수업정리 (0) | 2024.09.27 |
[강의] 9월 26일 수업정리 (1) | 2024.09.27 |