unreal 5기

250819 언리얼엔진 본캠프 11일차 포인터 (2)

parkjinnam 2025. 8. 19. 12:24

어제에 이어서 오늘도 포인터의 나머지 부분을 공부해 보도록 하자 어제 우리는 포인터의 정의와 역할, 포인터를 선언하는 방법과 해석방법 그리고 포인터에 저장된 주소를 읽는 방법과 주소에 저장된 값을 보는 방법에 대해서 배웠다. 빠르게 다음 예제를 확인해 보자

다음의 결과를 예측해보고 결과를 확인해보자

 

printf();의 첫 번째 코드만 한번 해석해 보자

// (pointer_to_char에 저장된 메모리 주소를 void*로 형변환 후 16진수 정수 8자리) :  변수 ch에 저장된 값 C를 % c의 서식자(C의 십진수의 형태 아마도 유니코드?) 후 줄 바꿈

으로 예상된다 다른 것도 해당 포인터에 저장된 주소와 그 값을 출력하는 형태를 띠고 있다. 한번 결과를 봐보자

캬 성장해 버렸다

 

예측한 결과대로 값이 출력되는 것을 볼 수 있다. 튜터님의 말씀대로 결괏값이 어떨지 천천히 정독하면서 코드를 해석하는 것이 맨땅에 코딩을 공부하면서 많이 도움이 된다고 느낀다. 다음 예제도 한번 보자

이번엔 각 출력을 하기 전에 pointer_to_char의 값을 변경하고 있다 그럼 다음과 같이 출력되지 않을까?

1. 포인터에 저장된 주소의 형변환 값을 %p 서식으로 표현 : 포인터 주소의 값(ch1 = L)

 

포인터의 메모리 주소가 ch2로 변경

2.  포인터에 저장된 주소의 형변환 값을 %p의 서식으로 표현 : 포인터 주소의 값(ch2 = O)

 

포인터의 메모리 주소가 ch1로 변경

 

3. 1. 의 값과 동일

 

한번 결과를 확인해 보자

 

이로서 포인터를 원하는 값으로 그때마다 변경해 주면서 그 주소의 값을 불러올 수 있음을 알 수 있다.

튜터님왈 야바위라 생각해라

 

각 변수들과 그를 가리키는 포인터를 지정해두고 포인터 값들을 마구 섞어준 다음 printf();를 통해서 값을 출력하는 코드로 볼 수 있다. 여기서 주석으로 퀴즈 하나가 달려있는데 한번 같이 보자

 

// Q, num1을 가르키는 포인터는?

 

같이 흐름을 읽으면서 정답을 찾아보자 최초에 num1의 주소를 저장한 포인터는 ptr1이었다. num3의 주소가 저장되어 있던 ptr3에 ptr2의 주소 즉 num2의 주소가 대입되고(num1의 주소를 가리키는건 ptr1) ptr2의 값에 ptr1의 주소 즉 num1의 주소가 대입되고(num1의 주소를 가르키는건 ptr1, ptr2) ptr1의 주소는 ptr2의 주소가 대입된다.(num1의 주소를 가르키는건 ptr1, ptr2)

 

즉 num1을 가르키는 포인터는 ptr1, ptr2 두 개고 정리하자면 다음과 같다.

num1의 주소 ptr1, 2

num2의 주소 ptr3

num3의 주소를 저장한 포인터는 없다.

 

결과를 한번 확인해 보자.

정답~

이 기세로 다음 예제도 확인해 보자.

 

뭔가 잔뜩 섞어주셨다. 일단 여기에도 주석이 달려있다

 

// Q. 출력 결과는?

 

천천히 한번 확인해 보자 각 변수별로 지정된 포인터에 ptr1 에는 ptr2가 대입되었다. ptr2에는 ptr3가 대입되었다. 즉

num1의 주소를 저장한 포인터는 없어졌고 num2의 주소를 저장한 포인터는 ptr1, num3의 주소를 저장한 포인터는 ptr2, ptr3인 상황이다. 정리하자면

 

1. num1의 주소를 저장한 포인터 : 없다.

2. num2의 주소를 저장한 포인터 : ptr1

3. num3의 주소를 저장한 포인터 : ptr2, ptr3

 

그다음 ptr3의 값을 역참조한 값 즉 num3의 값인 45에 2를 곱해서 대입해 준다(*=) 즉 num3은 90이 되었다.

비슷하게 ptr1의 주소를 역참조한 값은 num2이고 이는 30인데 거기에 ptr3의 값을 역참조한 90을 더해서 대입한다(+=) 다음으로 ptr2의 값을 역참조하여 num3의 값(현재는 90)을 2배를 해서 대입한다(*=) 각각의 변수들의 현재 값을 정리하자면

 

num1 == 15

num2 == 120

num3 == 180

 

이 될 것이고 printf();에 의해 순서대로 출력될 것이다.

가뿐하다

 

참조에 의한 호출? 값에 의한 호출?

함수 A가 함수 B를 호출할 때, 인자를 전달하면서 호출한다고 가정해 보면 함수 B가 종료될 때 인자의 원본값도 바꾼다면 참조에 의한 호출. 인자의 원본값이 바뀔 수 없다면 값의 의한 호출이라고 부른다고 한다. 잘 와닿지 않으니 예제를 같이 봐보자.

코드가 길다

 

천천히 정독해 보도록 하자 인자로 int자료형의 op1, op2를 받는 swap1와 op1의 포인터와 op2의 포인터를 받는 swap2를 전방선언 해주고 있다. 두 함수는 void의 값을 반환하고 있다는 점도 짚고 넘어가도록 하자 

1. swap1

temp를 int자료형 변수로 선언해 주고 temp에 op1을 대입해 준다음 op1에 op2를 대입해주고 op2에 temp를 대입해준다

이러면 결과적으로 op1과 op2의 값이 바뀌게 된다.

 

2. swap2

int자료형 변수 temp를 선언해주고 temp에 op1으로 입력될 포인터의 주소를 역참조한 값을 대입하고 *op1에 *op2를 대입해준 뒤 *op2에 temp값 즉 최초의 *op1의 값을 대입해준다 이러면 결과적으로  *op1과 *op2의 값이 바뀌게 된다

 

이제 메인함수를 봐보도록 하자 num1 = 10으로 num2 = 20으로 선언해 준 뒤 스왑 전의 각각 num1, 2 값을 출력해 주고

swap1을 실행 후 결괏값이 출력된다. 그 다음 swap2 전 num1, num2값을 출력해준 뒤 swap2를 실행, 그 결과값이 출력될 것이다.

swap1과 swap2의 차이는 명확하다 swap1은 값에 의한 호출이며 swap2는 참조에 의한 호출이다. 그럼 swap1은 원본 인자 값에 변화가 없을 것이며 swap2를 실행해야만 변화가 있을 것으로 예상해 볼 수 있다 한번 확인해 보자

 

이제 우리는 함수가 호출될 때 값에 의해 호출되는지(원본 변화 x) 참조에 의해 호출되는지(원본 변화 o) 확인해야 할 것이다. 다음 예제도 보자

 

최솟값과 최댓값을 뽑아주는 코드이다 결과에 따라 1과 10이 나올 것이다

 

 

지난 시간 배열을 배운 기억이 있다 이 배열의 이름도 포인터의 기능을 한다 즉 배열의 시작 주소를 저장하고 있는 배열의 이름 또한 포인터로서 기능을 하는 샘이다 반대로 포인터도 배열처럼 [] 연산자를 사용할 수 있다. 포인터에 사칙연산을 한다면(예컨대 ptr+1) 그 정수만큼 주소가 이동하게 된다. 또한 pointer to char에 1을 더하면 char의 자료형 크기 1만큼 주소에 더해지고 pointer to int에 1을 더하면 int자료형의 크기 4만큼 주소가 더해지게 된다.

여기에 더해 기억해야 할 중요 포인트가 있다.

 

1. 포인터의 크기는 32bit 기준 4바이트, 64bit 기준 8바이트이다.

 

2. 배열은 첫 번째 요소의 메모리 주소와 자료형만 안다면 n번째 요소도 알 수 있다.

 

그 외에도 함수포인터 등이 있지만 그 내용은 차차 알아보도록 하자