포인터 배열 배열처럼 나란히 선언하기에
역참조 안 하고 배열 호출 그대로 사용할 수 있다.
그럼 배열과 포인터의 차이점을 알아보자.
Arrays and Pointers
● 배열의 이름은 배열의 첫 요소의 주소를 가리킨다. (remind)
● 포인터 변수의 값은 주소값이다.
● 포인터 변수와 배열이 같은 주소를 가리킨다면, 포인터 변수와 배열은 (거의) 동일하게 사용 가능하다.
☞ (차이점 : 배열은 주소값을 정의 이후 변경 불가. Sizeof() 반환값이 다름)
int scores[] = { 100,95,90 };
cout << scores << endl; // 0x00000047752FFAC8
cout << *scores << endl; // 100
cout << scores[0] << endl; // 100
int* score_ptr = scores;
cout << score_ptr << endl; // 0x00000047752FFAC8
cout << *score_ptr << endl; // 100
cout << score_ptr[0] << endl; // 100
여기서 말하는 배열은 정적 배열을 말한다.
int main()
{
int arr[] = { 1,2,3 };
cout << arr << endl;
}
이렇게 작성할 경우 콘솔 값은
000000D7B21FF7D8 가 나온다.
arr은 arr[0] 의 주솟값을 가리킨다.
포인터는 메모리값에 주소값만 들어갈 수 있다.
포인터 변수와 배열이 같은 주소를 가리키게 된다면 포인터 변수와 배열은 동일하게 사용이 가능하다.
int scores[] = { 100,95,90 };
cout << sizeof(scores) << endl; // 12
int* score_ptr = scores;
cout << sizeof(score_ptr) << endl; // 4
// Debug x86
출력값이 다르다
정적인 배열은 배열 안의 요소들의 전체적인 개수만큼 sizeof 값에 반환된다.
하지만 포인터는 주소값을 가지고 있기 때문에 int 포인터인 만큼 sizeof 값에 4byte 반환된다.
그렇기에 int num =10; 이라는 변수를 선언하고
배열에 변수의 주솟값은 넣을 수 없고,
포인터에는 변수의 주솟값을 넣을 수 있다.
int num = 10;
int scores[] = { 100,95,90 };
cout << sizeof(scores) << endl;
scores = # //Fail
int* score_ptr = scores;
cout << sizeof(score_ptr) << endl;
score_ptr = #
● array_name[index] == pointer_name [index]
● *(array_name + index) == *(pointer_name + index)
int scores[] = { 100,95,90 };
int* scores_ptr = scores;
cout << scores_ptr << endl; //0033FA94
cout << (scores_ptr + 1) << endl; //0033FA98
cout << (scores_ptr + 2) << endl; //0033FA9C
cout << *scores_ptr << endl; //100
cout << *(scores_ptr + 1) << endl; //95
cout << *(scores_ptr + 2) << endl; //90
cout << scores_ptr[0] << endl; //100
cout << scores_ptr[1] << endl; //95
cout << scores_ptr[2] << endl; //90
인덱스 [0] [1]에 대한 의미인지
포인터를 만들 때 타입을 명시하도록 했는지
전반적으로 파악할 수 있다.
배열의 주소에 1을 더하면 두 번째 주솟값이 보인다.
int는 4byte 이므로
끝자리만 보면 4 -> 8 -> C(12)로 4 byte씩 이동한 걸 알 수 있다.
표현을 +1 , +2으로 표현을 했지만 실질적으로는
scores_ptr + 1*sizeof(int) 만큼 이동하는 것이다.
+1이라는 건 1칸이 아니라 int 형에서의 다음칸을 의미한다.
그럼 double 형일 때는 어떨까? (double 8 byte)
double scores[] = { 100,95,90 };
double* scores_ptr = scores;
cout << scores_ptr << endl; //010FFA40
cout << (scores_ptr + 1) << endl; //010FFA48
cout << (scores_ptr + 2) << endl; //010FFA50
cout << *scores_ptr << endl; //100
cout << *(scores_ptr + 1) << endl; //95
cout << *(scores_ptr + 2) << endl; //90
cout << scores_ptr[0] << endl; //100
cout << scores_ptr[1] << endl; //95
cout << scores_ptr[2] << endl; //90
8 byte씩 주소값이 증가한 것을 알 수 있다.
포인터의 타입이 알고 있어야
컴파일러가 포인터의 인덱스를 접근할 때
몇 byte씩 띄어서 볼 수 있는지 알 수 있다.
Const and Pointer
● const의 포인터 (pointers to const)
● const인 포인터 (const pointers)
● const의 const 인 포인터 (const pointers to const)
간략하게라도 외워둘 것
const int a = 10;
변수에 const를 사용하는 것처럼
포인터에도 const를 사용하는 방법이 3가지가 있다.
Const and Pointer
● const의 포인터 (pointers to const)
▶ 데이터가 const / 포인터는 다른 데이터를 가리킬 수 있다.
int high_score = 100;
int low_score = 60;
const int* score_ptr = &high_score;
*score_ptr = 80; // ERROR
score_ptr = &low_score; // OK
int 포인터 앞에 const가 붙여져 있다면
데이터가 const로 된다.
그 뜻은 *score_ptr의 값, 즉 high_score의 메모리 값을 const로 지정하였기에
값 변경이 되지 않는다.
대신 score_ptr이 다른 메모리 주소값을 가질 수는 있다.
Const and Pointer
● const의 포인터 (pointers to const)
● const인 포인터 (const pointers)
▶ 포인터가 const / 데이터는 변할 수 있다.
int high_score = 100;
int low_score = 60;
int* const score_ptr = &high_score;
*score_ptr = 80; // OK
score_ptr = &low_score; // ERROR
Const and Pointer
● const의 포인터 (pointers to const)
● const인 포인터 (const pointers)
● const 의 const 인 포인터 (const pointers to const)
▶ 둘 다 const 인 경우
int high_score = 100;
int low_score = 60;
const int* const score_ptr = &high_score;
*score_ptr = 80; // ERROR
score_ptr = &low_score; // ERROR
데이터도 변경이 안되고 포인터도 변경이 안된다.
const의 위치에 따라서 동작이 다르기 때문에 외워두는 게 좋다.
https://youtu.be/1 g4 KLKS6 AP0? si=DlAP97 PAAz5 cNHeE
'C++ > C++ : Study' 카테고리의 다른 글
c++ 포인터 참조자 (1) 개요 (0) | 2024.09.22 |
---|---|
C++ 포인터 참조자 (5) 포인터의 전달과 반환 (0) | 2024.09.22 |
C++ 포인터 참조자 (3) 동적 할당 (1) | 2024.09.18 |
C++ 포인터 참조자 (2) 역참조 (1) | 2024.09.16 |
C++ inline function & Recursive Function (0) | 2024.09.15 |