※ C / C++을 이미 알고 있으나 개인적인 공부를 위해 포스팅 하는 글이므로
C++에 대한 구체적인 정보를 담고 있지 않습니다.
▶ 배열과 포인터의 차이점 (사람들이 같다고 착각하는 이유)
1) 포인터
int* p;
ㆍ p는 단지 그곳으로 워프하는 포탈이라 생각하자
ㆍ 진퉁은 쩌~~~ 멀리 어딘가 있음
ㆍ p는 그저 주소를 담아주는 바구니일뿐 (4or8바이트)
2) 배열
int arr[10];
ㆍ 진짜배기 원조 데이터가 이 안에 진짜로 있는거임. (얘 자체가 진퉁 데이터)
ㆍ 포인터는 그냥 4or8바이트 작은 데이터(포탈) 인 반면, 배열은 진짜 거대할 수도 있음
ㆍ 닭장처럼 데이터의 묶음이기 때문에 많고 거대할 수 있음
ㆍ 배열과 배열의 이름은 다른거다. 배열의 이름은 그저 첫번째 주소를 가리키고 있는놈이다.
※ 그렇다면 사람들이 [배열 = 포인터] 라고 착각하는 경향이 있는데 그 이유가 뭘까?
⊙ [ 배열의 이름 ] 은 배열의 시작 주소를 가리키는 TYPE* 포인터 와 완벽하게 호환하기 때문이다. (변환 가능)
int* p;
int arr[10] = { 1,2,3,4,5,6,7,8 };
p = arr;
ㆍ 해당 코드를 보자.
ㆍ 주소를 담는 바구니 p에다 arr의 시작 주소를 넣어줬다.
ㆍ [ TYPE형 1차원 배열 ] 과 [ TYPE*형 포인터 ] 는 완전히 호환이 된다. (문법적으로)
cout << p[0] << endl;
cout << arr[0] << endl;
cout << p[5] << endl;
cout << arr[5] << endl;
cout << *p << endl;
cout << *arr << endl;
cout << *(p + 3) << endl;
cout << *(arr + 3) << endl;
ㆍ 같은 주소를 가리키면 같은 결과가 나온다. (포인터 연산은 자료형 크기만큼 이동)
※ 이런식으로 호환이 되기때문에 착각하는 사람이 있는 것 같다.
※ 결론
ㆍ 배열의 이름(첫번쨰주소) = TYPE* 포인터
int arr2[2][2] = { {1,2},{3,4} };
ㆍ 내부적으론 1차원 배열이랑 동일하는 것을 지난 포스팅을 통해 알고있다.
int arr2[2][2] = { {1,2},{3,4} };
int** pp = (int**)arr2; //이 코드는 오류! 메모리 접근하다 터짐
ㆍ 왜 터질까?? -> 2차원 배열이 사실 내부적으론 1차원 배열과 동일 하다는 점에서 힌드를 얻을 수 있다.
1) ** pp는 첫번째 메모리 주소 를 가리키고 있다 1번 타고들어갔으니 *을 하나 벗기겠다
⊙ pp[ 주소1 ] <----메모리에 pp쳐서 타고 들어감 (* 하나 벗겨짐)
2) 주소1 에는 [ 00000001 ] 이라는 값이 들어있었음! *을 하나 더 벗기기 위해 나온 값을 타고들어갈게!
⊙ 주소2에는 [쓰레기] 가 들어가있었다. 따라서 당연히 터진다. 왜이럴까??
ㆍ 2차원 배열과 다중포인터는 전혀 호환되지 않는다.!
int* pp = arr2; //컴파일 오류
ㆍ 해당 코드는 들어가지 않는다.. 오류 메세지를 살펴보자
int(*p2)[2] = arr2; //정상 작동
ㆍ 정상적으로 잘 작동 한다.
ㆍ 문법이 좀 헷갈리는 부분이 있는 거 같다
cout << (*p2)[0] << endl;
cout << (*p2)[1] << endl;
cout << (*(p2+1))[0] << endl;
cout << (*(p2+1))[1] << endl;
cout << p2[0][0] << endl;
cout << p2[0][1] << endl;
cout << p2[1][0] << endl;
cout << p2[1][1] << endl;
ㆍ 값을 확인해봐도 정상적으로 들어간다.
▶ 사실 크래쉬가 나는건 다행이다.. 어디서 터졌는지 알 수 있기때문에
ㆍ 진짜 위험한 상황을 한번 보기위해 프로그램을 터트리는 코드를 한번 작성해봤다.
int* TestPointer()
{
int a = 1;
return &a;
}
void TestWrong(int* ptr)
{
int a[100] = {};
a[99] = 0xAAAAAAAA;
*ptr = 0x12341234;
}
int main()
{
int* pointer = TestPointer();
TestWrong(pointer);
return 0;
}
※ 텍스트로 보는 스택 프레임
int* pointer = TestPointer();
1) [매개변수] [RET] [지역변수] [매개변수] [RET] [지역변수a]
-> a가 함수가 끝나면서 스택프레임이 사라짐
2) [매개변수] [RET] [지역변수] //a는 어딘가에 주소는 유효한 상태 하지만 스택프레임으로 인해 사라진상태
-> pointer에 넘겨주었음
TestWrong(pointer);
3) 이 상태에서 해당 함수를 호출
void TestWrong(int* ptr)
{
int a[100] = {};
a[99] = 0xAAAAAAAA;
*ptr = 0x12341234;
}
ㆍ 디버그 모드니까 오류가 나오는데 릴리즈모드에선 오류가 나지도 않음...
ㆍ 나중에 엄청 큰 문제가 생길수도 있으니 이런 상황을 주의하자.
★ 함수의 생명 주기를 잘 생각해서 안에서만 유효한 값을 외부로 넘겨주는짓은 절대로 해서는 안되는 짓이니 주의하자
'C++프로그래밍 > C 와 C++ 기초실습' 카테고리의 다른 글
문자열(포인터) 연습해보기 (0) | 2024.09.20 |
---|---|
다중 포인터 (const char**) 문자열 (1) | 2024.09.18 |
배열과 포인터 (문자열) (0) | 2024.09.18 |
포인터와 참조타입 비교,차이 (const pointer) (0) | 2024.09.18 |
참조타입 (0) | 2024.09.18 |