-
[Pointer] 배열과 포인터개발/C·C++ 2021. 4. 14. 21:36
타입과 Decay
배열의 이름은 상수 포인터처럼 사용할 수 있지만 엄밀히 말해 그 둘이 같다고 보기는 어렵습니다. 애초에 타입부터 다르기 때문입니다. C++에서는 typeid라는 연산자를 이용해서 변수의 타입을 확인할 수 있습니다.
#include <iostream> using namespace std; int main() { int nums[4] = { 1,2,3,4 }; int num0 = 0; int* pNum = &num0; cout << typeid(nums).name() << endl; cout << typeid(pNum).name() << endl; }
배열을 함수의 인자로 넘길 때 매개변수를 포인터로 정의하지 않고 배열로 선언해도 마찬가지입니다. 배열일 때는 size를 구할 수 있지만 포인터로 변환되면 배열의 크기 정보를 알 수 없습니다. 이를 decay라고 합니다.
#include <iostream> using namespace std; void func(int arr[]) { cout << typeid(arr).name() << endl; cout << sizeof arr << endl; } int main(int c, char* v[]) { int nums[4] = { 1,2,3,4 }; cout << typeid(nums).name() << endl; cout << sizeof nums << endl; cout << endl; func(nums); }
정적인 배열을 사용할 때는 std::array 클래스를 사용하면 decay를 막을 수 있고 안전하게 배열을 사용할 수 있습니다. 정적으로 선언한 배열에서 배열의 크기보다 큰 인덱스로 접근해 출력을 해보면 쓰레기 값이 출력됩니다. 정의되지 않은 동작이지만 오류로 판단하지 않는 것입니다. std::array 클래스의 at() 함수를 사용하면 오류를 발생시켜 줍니다. Release 모드에서는 아예 아무 것도 출력해주지 않습니다. 해당 인덱스에 접근하지 않는 것입니다.
#include <iostream> #include <array> using namespace std; int main() { array<int, 4> arr{ 1,2,3,4 }; int nums[4] = { 1,2,3,4 }; cout << nums[4] << endl; cout << arr.at(4) << endl; }
이차원 배열과 이중 포인터
모든 이차원 배열이 이중 포인터일까요? 다음 코드를 봅시다.
#include <iostream> using namespace std; void funcChar(int c, const char **arr) // void funcChar(int c, const char *arr[]) // ok { for (int i = 0; i < c; ++i) { cout << arr[i] << endl; } } int main() { const char *arr[2] = { "abc", "def" }; funcChar(2, arr); }
main()에서 선언한 arr 변수는 배열의 포인터입니다([]가 *보다 우선 순위가 높습니다. ). 각 요소에 문자열의 시작 주소를 넣습니다. 이것이 이중 포인터입니다. 다음은 비슷한 듯 조금 다릅니다.
#include <iostream> using namespace std; void funcChar2(int c, char (*charPtr)[5]) // void funcChar2(int c, char **charPtr) // error { for (int i = 0; i < c; ++i) { cout << charPtr[i] << endl; } } int main() { char strs[][5] = { "abcd", "efg" }; funcChar2(2, strs); }
이차원 배열로 선언한 strs 변수는 각 요소에 문자열 자체를 갖고 있습니다 "abcd" | "efg" 이렇게요. 문자열의 배열입니다. 일부러 컴파일 오류를 내서 확인해보면 strs 변수가 (*)[5] 형식이라고 뜹니다. funcChar2()에서 이중 포인터로 받을 수 없고 (*charPtr)[5] 이렇게 포인터의 배열로 받아야 합니다.
다음 코드를 디버깅해서 조사식으로 살펴보면 str1은 시작 주소를 담기에 H만 표현하고 str2에는 모든 인덱스에 Hello가 들어가있는 모습을 확인할 수 있습니다. 이 차이에서 비롯됐습니다.
#include <iostream> using namespace std; int main() { const char* str1 = "Hello"; char str2[] = "Hello"; }
'개발 > C·C++' 카테고리의 다른 글
디폴트 파라미터와 함수의 프로토타입 (0) 2021.04.17 참조(reference) 변수 (0) 2021.04.17 [Dangling Pointer] 유효하지 않은 포인터 (0) 2021.04.10 [Pointer] 달과 손가락 (0) 2021.04.10 [Enum] 가독성을 위한 약간의 수고 (0) 2021.04.09