C++ Chapter 6.7 : 포인터와 정적 배열
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
포인터와 배열 이름은 일맥상통하는게 있다.
int array[5] = {0, 1, 2, 3, 4};
int * ptr = array;
배열의 이름 👉🏻 포인터 상수나 마찬가지. (변하지 않는 주소 값)
array
와&array[0]
은 같다.- 배열의 이름 👉🏻배열의 첫번째 원소의 주소
*array
와array[0]
은 같다.*array
👉🏻 배열의 첫번째 원소를 간접 참조함.
int * ptr = array;
- ptr 포인터 변수가 array 배열의 주소를 담게 되었으니 이제 ptr로 array 배열에 간접참조가 가능해짐.
*ptr
와array[0]
은 같다.*ptr = 100
은array[0]=100
과 같다.- 배열의 주소를 복사해 담은 포인터로 배열의 원소 값을 이렇게 바꿀 수도 있지만 char * 형 포인터에 char [] 문자열 배열의 원소를 바꾸려는 시도는 불가능하다. [다다음 포스트 참고]
배열의 이름과 포인터의 차이
int array[5] = {0, 1, 2, 3, 4};
int * ptr = array;
sizeof(array) // 👉🏻 20
sizeof(ptr)) // 👉🏻 4
- sizeof에 배열의 이름을 넣으면 배열의 총 메모리 크기를 알려주지만
- sizeof에 포인터를 넣으면 포인터가 배열을 가리키고 있더라도 포인터의 크기만 알려준다.
- 포인터의 크기는 int * 든 double * 든 데이터 타입에 상관없이 4byte. (64 bit 환경에선 8byte)
함수 파라미터로 배열을 넘길 때
void printArray(int * array)
{
cout << sizeof(array) << endl;
// 지역변수 array에 배열의 이름이 들어오든 포인터가 들어오든 지역변수 array는 포인터이므로 언제나 4가 출력될 것.
}
int main()
{
int array[5] = {0, 1, 2, 3, 4};
int * ptr = array;
printArray(array); // 배열의 주소가 printArray 함수 내부의 array 지역변수에 대입된다.
printArray(ptr); // 포인터 ptr 값이 printArray 함수의 지역변수 array에 대입된다.
}
- 함수의 매개변수로 배열을 전달할 때는 포인터로서 전달 된다. (주소만 복사되어 넘어감)
- 성능 상 이유로 매개변수 타입 자체를 배열로 하여 배열을 통째로 복사하여 넘기는 것은 금지되어 있다.
- 배열 크기가 클때는 배열 복사하는데 시간이 많이 소요되기 때문.
- 매개변수를 포인터로 선언해서 배열의 이름 (= 배열의 첫번째 원소의 주소)만 복사하여 넘겨주면 포인터로 배열 원소에 접근할 수 있으므로 효율적이다.
- 어차피 배열 원소들은 연속된 메모리 공간으로 위치하므로 첫번째 원소 주소값 (= 배열의 이름)만 알면 다른 원소들도 4 (int 기준) 씩만 더해주어 주소를 알아낼 수 있다.
- 이처럼 배열의 주소를 포인터 매개변수로 넘길 땐 포인터 매개변수만으로는 배열의 크기를 알 수 없으므로 int len 형태로 배열의 크기를 직접 같이 넘겨주어야 한다.
void printArray(int * array, int len)
매개변수가 배열 같아 보여도 사실 포인터다.
void printArray(int array [5])
{
cout << sizeof(array) << endl;
}
int main()
{
int array[5] = {0, 1, 2, 3, 4};
int * ptr = array;
printArray(array);
printArray(ptr);
}
void printArray(int array [5])
- 매개변수를 배열로 받는 것 같아 보여도 사실 포인터다.
- 배열을 위한 포인터라고
[]
대괄호 기호를 써서 배열의 주소를 넘겨 받을 것임을 강조하는 것 뿐 - 오직 매개변수 타입에서만
*
를[]
로 바꾸는 것이 가능하다.- 더블포인터와 같이
*
가 여러개인 경우엔 하나만[]
로 바꿀 수 있다.void func(int ** pArr) // 가능 void func(int * pArr[]) // 가능 void func(int pArr[][]) // 불가능
- 더블포인터와 같이
- 따라서
[]
기호 안의 숫자도 아무 의미 없다. 실제로 3 크기의 배열을 넘기는 것이라도 매개변수에 [5]라고 되있다고 해서 오류가 발생하는 것도 아니다. - 프로그램에는 영향을 미치지 않고 단순 5 크기의 배열을 받을 것이라는 표시일뿐.
- 배열을 위한 포인터라고
구조체 혹은 클래스의 멤버로 속한 배열을 매개변수로 넘길 때
이 경우엔 포인터로 전환되지 않고 배열 자체가 그대로 넘겨진다.
#include <iostream>
#include <cstring>
using namespace std;
struct Mystruct
{
int array[5] = { 9, 7, 5, 3, 1 };
};
void doSomething(Mystruct * ms)
{
cout << sizeof((*ms).array) << endl; // 4가 아닌 20 출력
}
int main()
{
Mystruct ms;
cout << ms.array[0] << endl; // 9 출력
cout << sizeof(ms.array) << endl; // 20 출력 (멤버가 array 배열 하나 뿐)
doSomething(ms);
return 0;
}
- 배열이 구조체나 클래스의 멤버로 있을 땐
- 파라미터가 구조체 타입으로 받든 구조체 포인터로 받든
- 배열 그 자체가 넘어간다
- 위와 같이 배열의 주소가 포인터에 복사되어 넘어가는 것이 아닌!
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기