포인터 이해 확인 문제 풀이
1. 출력되는 값 iData의 값은 무엇이 될까?
short sArr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int* pI = (int*)sArr;
int iData = *((short*)(pI + 2));
printf("1번 문제 정답 : %d\n", iData);
먼저 short 타입은 2바이트 정수형이고, int 타입의 크기는 4바이트 정수형이라는 것을 생각해야 한다.
첫 번째 줄 코드에 선언된 배열 내부는 이렇게 생겼을 것이다.
두 번째 줄의 다음 코드는 컴파일러 오류를 방지하기 위한 강제 캐스팅을 실행한다.
int* pI = (int*)sArr;
해당 코드를 실행하면 다음과 같이 int 포인터 변수 pI가 캐스팅에 의해
short에서 int로 취급하는 배열의 첫 번째 주소를 받게 된다.
이어서 세 번째 줄 코드를 살펴보자.
int iData = *((short*)(pI + 2));
int 자료형인 iData 변수에 pI + 2한 값만큼의 위치에서 short형 데이터를 얻어온다.
이때 int는 4바이트 자료형이므로, +2를 하라는 의미는 메모리 상에서 4개씩 한 묶음을 2번 증가시키라는 의미이다.
즉, 아래와 같이 8byte만큼 증가시키게 된다.
첫 번째 주소의 위치에서 8칸 만큼 이동하면 4번 째 주소의 끝에 도달한다.
마지막으로 이동한 위치에서부터 short 타입에 해당하는 주소를 받아온다. short 타입은 2바이트 자료형이므로 5번째 주소에 도달하게 된다.
따라서 최종 정답은 5가 된다.
2. 출력되는 값 iData의 값은 무엇이 될까?
char cArr[2] = { 1, 1 };
short* pS = (short*)cArr;
iData = *pS;
printf("2번 문제 정답 : %d\n", iData);
먼저 short 타입은 2바이트 정수형이고, char 타입은 1바이트 크기의 정수형이라는 것을 생각해야 한다.
첫 번째 줄 코드에 선언된 배열 내부는 이렇게 생겼을 것이다.
이 상태에서 두 번째줄 코드를 살펴보자.
short* pS = (short*)cArr;
본래 char 타입이었던 배열의 주소를 받아 short 포인터 변수로 받았다. 이때 오류를 방지하기 위해 강제 캐스팅으로 char 타입의 배열을 short 포인터로 변환하여 넣어 주었다.
이 때의 작동 모습을 내부적으로 표현하면 다음과 같다.
세 번째 코드를 보면 앞서 해결한 1번 문제와 달리 특별히 캐스팅을 거치지 않고
바로 포인트 주소로 접근 명령 했음을 알 수 있다.
iData = *pS;
하지만 short 포인터는 이전 코드에서 그 주소를 2바이트 정수인 short로 보도록 명령받은 상태이다.
그렇기 때문에 주소 안에 short가 있을 것이라고 생각하면서 해당 주소에 접근하게 된다.
따라서 내부 메모리 구조를 아래와 같이 2바이트 정수라고 봐야한다.
그림에서 설명한 대로 계산을 진행하면 최종 답은 257이 된다.
3. 아래의 코드에서 테스트 함수를 호출하면 출력 결과가 어떻게 될까?
#include <stdlib.h>
#include <stdio.h>
int Test(int a)
{
a = 500;
}
int main()
{
int a = 100;
Test(a);
printf("출력 : %d\n", a);
return 0;
}
결과는 100 이 된다. Test 함수에서의 a 스택은 메인 함수의 a와는 별개의 메모리에 저장되어 있는 서로 다른 객체이다. 따라서 a라는 변수를 500이라고 할당해도 그것은 메인 함수에 있는 a가 아니며 함수 스코프 안의 a는 스택 메모리 영역에 있으므로 함수 종료 시 없어진다. 이를 개선하려면 다음과 같이 주소로 접근해야 한다.
#include <stdlib.h>
#include <stdio.h>
void Test(int* a)
{
*a = 500;
}
int main()
{
int a = 100;
Test(a);
printf("출력 : %d\n", a);
return 0;
}
a의 주소에 접근하였기 때문에 출력 시 a의 값은 500으로 변환된다. 이처럼 실제 변경하고 싶은 원본 데이터의 주소를 알려주면 그쪽에서 주소를 통한 역참조가 가능해진다. 이를 통해 원본 데이터의 값을 변환할 수 있다.
4. 위와 같은 논리로 scanf를 다시 살펴보자. scanf는 작동 시 주소를 요구한다.
scanf_s("%d", &a);
scanf 안의 (&)는 이 변수의 주소를 준다는 것을 의미한다. 이렇게 주소를 줬으므로 전달받은 주소에 접근해 그곳을 수정해 줄 수 있다.
scanf은 콘솔 창의 어떤 데이터로 입력해 주면 입력한 데이터를 내가 지정해 준 변수한테 넣어주는 역할을 한다.
따라서 scanf 함수 쪽에서는 호출 시 입력된 값을 입력받고 싶은 변수의 주소를 알려주어야 함수 안에서 콘솔 창에 입력된 데이터를 알려준 주소에 접근하여 넣어준다.
'C,C++ > [강의] 어소트락 C++' 카테고리의 다른 글
void (0) | 2023.01.18 |
---|---|
const, const 포인터 (0) | 2023.01.14 |
포인터 배열 (0) | 2023.01.09 |
포인터 (0) | 2023.01.07 |
운영체제 (0) | 2023.01.06 |