c++ 에서 배열을 전달하려면 포인터를 사용하는 방법밖에 없다.
예제를 참고하면서 이해하자.
예제
배열의 총합을 더하는 함수를 만들어보자.
#include <iostream>
void totalData(const int *pData, int nLength, int *pTotal);
int main()
{
int arData[5]{ 5,4,3,2,1 };
int nTotal{};
totalData(arData, 5, &nTotal);
printf("배열의 총합 : %d\n", nTotal);
}
void totalData(const int * pData, int nLength, int *pTotal)
{
*pTotal = 0;
for (int i = 0; i < nLength; i++)
{
*pTotal += pData[i];
}
}
함수 인자에 포인터가 있다면 우리는 2가지로 알아들을 수 있다.
void totalData(const int *pData, int nLength, int *pTotal);
1. 변수의 주소값이다.
2. 배열의 첫번째 주소값이다.
이 2가지를 어떻게 구분해야할까?
저번에 작성했던
2020/05/08 - [기타 공부/C++] - [C++] 배열 쓸 때 참고하기
게시글에서 배열은 배열 길이를 잃어버리면 안된다고 했다.
포인터 변수 뒤에 길이를 의미하는 변수가 있다면 (Length, Size 등) 그 포인터는 배열을 의미한다.
그러면 위의 예제에서는 이렇게 구분할 수 있다.
const int *pData // 배열의 첫번째 주소값 의미 (뒤에 길이를 의미하는 nLength라는 변수가 있다.)
int *pTotal // 변수의 주소값 의미
const 의미
구글링을 해보니까 const는 상수 포인터라고 한다.
읽기 전용이라고 생각하면 이해가 잘 된다.
위의 예제에서 우리는 배열의 총합을 구하는 것이므로 배열의 값을 변경할 이유가 없다.
그러므로 const를 붙여준다. (읽기 전용이라는 의미)
알기 쉽게 정리하자면,
값이 변경 되지 않으면 const 붙이기.
값이 변경되면 const 붙이지 않기.
이것을 잘 지켜야지 함수 모양을 잘 만들 수 있다. (함수 만들기는 쉽지만, 잘 만드는 것은 어렵다.)
우리는 위의 예제를 보고 이렇게 생각하면 된다.
void totalData(const int *pData, int nLength, int *pTotal);
// const int *pData
// 읽기 전용이구나.
// int nLength
// 배열의 크기 (앞의 포인터 변수가 배열이구나.)
// int *pTotal
// const 키워드가 없으므로 함수가 끝나면 값이 바뀌어 있겠구나.
char 배열과 문자열
1. char 배열
char가 여러 개 있는 것이다.
끝을 배열 길이로 구분한다.
// 선언할 때부터 가지고 있던 배열 길이를 그냥 넘겨준다.
void testFunction(char *pData, int nLength);
2. 문자열
char가 여러 개 있는 것이다.
끝을 null로 구분한다.
// 문자열의 길이는 null을 만날 때까지의 길이이다. 따로 한번 구해야 한다.
int stringLength(const char * str)
{
int nIndex{};
while (str[nIndex] != '\0')
nIndex++;
return nIndex;
}
2개의 구분을 잘할 수 있다는 가정 하에,
포인터 변수 뒤에 길이를 의미하는 변수가 있다면 그 포인터는 배열을 의미한다고 위에서 말했다.
그렇지만, 한가지 예외가 있다.
문자열은 배열 길이와 상관없이 null 까지의 길이를 체크하기 때문에 길이를 의미하는 변수가 필요없다.
그러므로 변수 네이밍을 str 을 이용해서 char 배열이 아니라 문자열이라고 인식할 수 있게 해야 한다.
void testFunction1(char *pData, int nLength); // char 배열이다.
void testFunction2(char *strData); // char 배열이지만, 문자열을 의미한다.
함수를 잘 짜는 법.
문자열 배열을 복사하는 함수를 예시로 들어보자.
함수 구현 내용은 별 중요하지 않다. 어차피 로직이고 main 함수에서도 만들 수 있는 거니까.
#include <iostream>
bool copyData(char * strDest, int nDestLength, const char * strSrc);
int stringLength(const char * str);
int main()
{
char strDest[10] = "aaaaa";
char strSrc[11] = "bbbbbbbbb";
if (copyData(strDest, 10, strSrc))
printf("%s\n", strDest);
else
printf("복사에 실패했습니다.");
}
// const char * 는 size 필요없다. 이해못하면 외우자.
bool copyData(char * strDest, int nDestLength, const char * strSrc)
{
if (nDestLength - 1 < stringLength(strSrc)) // null자리 포함
return false;
int nIndex{};
while (strSrc[nIndex] != '\0')
{
strDest[nIndex] = strSrc[nIndex];
nIndex++;
}
strDest[nIndex] = '\0';
return true;
}
int stringLength(const char * str)
{
int nIndex{};
while (str[nIndex] != '\0')
nIndex++;
return nIndex;
}
우리는 같은 프로그래머 입장에서 함수의 구현 내용을 보지 않아도 잘 사용할 수 있도록 모양을 만들어야 한다.
함수 프로토타입만 보고도 기능을 이해하고 사용할 수 있다.
bool copyData(char * strDest, int nDestLength, const char * strSrc);
bool
// 성공 실패 여부를 반환하나보다.
copyData
// 데이터를 복사하는 함수인가보다.
char * strDest
// 변수명이 dest -> 이 배열에 복사를 당하겠구나.
// 변수명 str -> 문자열인가보다.
// const가 없음 -> 배열의 값이 변하겠구나.
int nDestLength
// 배열 길이를 의미하나보다.
// 어 근데 문자열은 길이가 필요 없는데, 이거는 배열의 총 길이인가보다.
// 복사할 때 배열 길이를 초과하면 안되니까.
const char * strSrc
// 변수명이 src -> 이 배열의 값을 복사하겠구나.
// 변수명이 str -> 문자열인가보다.
// const -> 읽기 전용이구나.
이런 것이 바로 잘 만든 함수 모양이다.
잘 만든 함수는 함수 프로토타입만 보고도 프로그래머끼리 의사소통이 되는 함수를 의미한다.
'기타 > C++' 카테고리의 다른 글
[C++] 네임스페이스 (0) | 2020.06.06 |
---|---|
[C++] 구조체 (0) | 2020.06.06 |
[C++] 함수 쓸 때 참고하기 (0) | 2020.06.06 |
[C++] 포인터 쓸 때 참고하기 (0) | 2020.05.20 |
[C++] 배열 쓸 때 참고하기 (0) | 2020.05.08 |