C++ Chapter 6.7 : 포인터와 정적 배열

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


포인터와 배열 이름은 일맥상통하는게 있다.

int array[5] = {0, 1, 2, 3, 4}; 
int * ptr = array;

배열의 이름 👉🏻 포인터 상수나 마찬가지. (변하지 않는 주소 값)

  • array&array[0]은 같다.
    • 배열의 이름 👉🏻배열의 첫번째 원소의 주소
  • *arrayarray[0]은 같다.
    • *array 👉🏻 배열의 첫번째 원소를 간접 참조함.
  • int * ptr = array;
    • ptr 포인터 변수가 array 배열의 주소를 담게 되었으니 이제 ptr로 array 배열에 간접참조가 가능해짐.
    • *ptrarray[0]은 같다.
    • *ptr = 100array[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;
}
  • 배열이 구조체나 클래스의 멤버로 있을 땐
    • 파라미터가 구조체 타입으로 받든 구조체 포인터로 받든
    • 배열 그 자체가 넘어간다
      • 위와 같이 배열의 주소가 포인터에 복사되어 넘어가는 것이 아닌!


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기