먼저 아래의 코드를 보면 변수 a와 b는 같은 주소를 가르킨다.
#include <stdio.h>
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
int* b = a;
printf("a : %d\n", a);
printf("b : %d\n", b);
printf("a(pointer address) : %p\n", a);
printf("b(pointer address) : %p\n", b);
return 0;
}
/*
a : 6422016
b : 6422016
a(pointer address) : 000000000061FE00
b(pointer address) : 000000000061FE00
*/
그래서 "배열을 가진 변수의 only 이름은 배열의 첫번째 주소를 가진다. 그러니 a와 b는 같은 것이다."라고 이해를 하는데, 엄격히는 아니다.
다름을 확인할 수 있는 방법은 아래의 코드 결과와 같다.
#include <stdio.h>
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
int* b = a;
printf("a : %d\n", a);
printf("b : %d\n", b);
printf("a(pointer address) : %p\n", a);
printf("b(pointer address) : %p\n", b);
printf("size of a : %d\n", sizeof(a));
printf("size of b : %d\n", sizeof(b));
return 0;
}
/*
a : 6422016
b : 6422016
a(pointer address) : 000000000061FE00
b(pointer address) : 000000000061FE00
size of a : 20
size of b : 8
*/
배열은 컴파일러가 배열의 크기와 메모리 위치를 알고 있어야 한다. 즉, 배열 전체에 대한 정보를 가지고 있다.
포인터는 단순히 메모리의 특정 주소를 가르키는 변수이다. 즉, 배열의 크기 정보를 가지고 있지 않다.
그래서 sizeof로 확인하면 배열은 전체 정보를 가지고있는 변수 a는 4 byte(int) * 5의 값을 리턴하는 것이고,
단순히 주소값만 가지고있는 포인터 변수 b는 주소값 8 byte 값을 리턴하는 것이다.
즉, "배열 변수 이름 != 포인터"인것이다.
그럼 코드 중 "int* b = a;"라는 코드를 자세히 살펴보면, 이것은 암시적 형변환이 일어난다고 보면 되는 것이다.
배열 타입에서 포인터 타입으로 형변환을 하게되면서 배열의 크기에 대한 정보를 잃게된다.
이를 Array to Pointer Decay라고 한다.
코테같은 것을 할 때를 생각해보면, 배열을 함수 등으로 넘길 때 항상 size 변수도 같이 넘긴다.
이유는 아래와 같은 상황을 보자.
#include <stdio.h>
void tempFunc( int b[5] ) {
printf("b : %d\n", b);
printf("b(pointer address) : %p\n", b);
printf("size of b : %d\n", sizeof(b));
}
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
printf("a : %d\n", a);
printf("a(pointer address) : %p\n", a);
printf("size of a : %d\n", sizeof(a));
tempFunc(a);
return 0;
}
/*
a : 6422016
a(pointer address) : 000000000061FE00
size of a : 20
b : 6422016
b(pointer address) : 000000000061FE00
size of b : 8
*/
함수로 인자를 넘길 때도 형변환이 생기는데, 이를 방지하여 size 변수 없이 함수 매개변수로 넘기는 방법은 C에서는 없는 것으로 알고있고 C++ 에서는 아래와 같은 방법이 가능하다.
#include <iostream>
void tempFunc( int (&b)[5] ) {
std::cout << "b (pointer address) : " << static_cast<void*>(b) << std::endl;
std::cout << "size of b : " << sizeof(b) << std::endl;
}
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
std::cout << "a (pointer address) : " << static_cast<void*>(a) << std::endl;
std::cout << "size of a : " << sizeof(a) << std::endl;
tempFunc(a);
return 0;
}
/*
a (pointer address) : 0x61fe00
size of a : 20
b (pointer address) : 0x61fe00
size of b : 20
*/
'프로그래밍 > C,C++,C#' 카테고리의 다른 글
[C,C++,C#] 구조체 padding 제거(feat. 구조체 크기 계산) (0) | 2023.06.04 |
---|---|
[C,C++,C#] 구조체 메모리 크기 계산 (0) | 2023.06.04 |
[C,C++,C#] 전처리 ##연산자 (0) | 2023.06.04 |
[C] 공용체(union) 변수 사용 (feat. 콜론 연산자) (0) | 2023.04.07 |
[C/C++] 간편하게 LOG 남기기(feat. 가변인자) (0) | 2023.03.29 |
댓글