C++

C++ 포인터 산술(Pointer Arithmetic)

김구티2 2024. 5. 1. 10:14

1. 포인터 산술의 개념

C++에서 포인터 변수는 다른 변수, 함수, 구조 및 다른 포인터의 주소를 저장하는 데 사용되며, 이러한 포인터를 사용하여 해당 주소에 저장된 데이터에 액세스하고 조작할 수 있다.

포인터 산술은 말 그대로, 포인터에 대해 산술 연산을 수행하는 것을 의미한다. 포인터에 대해 유효한 연산을 의미하는 것으로, C++의 포인터에 유효한 산술 연산은 다음과 같다:

① 증가 및 감소 포인터
② 포인터에 상수 더하기
③ 포인터에서 상수 빼기
④ 동일한 유형의 두 포인터 빼기
⑤ 포인터 비교

2. 증가 및 감소 포인터

포인터를 늘리거나 줄이면, 메모리에 있는 다음 또는 이전 데이터의 주소를 참조하게 된다. 이 과정은 숫자 데이터를 늘리거나 줄이는 것과는 분명 다르다.

예를 들어, 숫자 데이터를 늘리거나 줄일 때, 그 값은 1만큼 증가하거나 감소한다. 그러나 포인터를 늘리거나 줄이는 대신, 주소는 1만큼 증가하거나 감소하고, 가리키는 데이터 유형의 크기를 곱한다. *이것이 바로 포인터 선언이 데이터 유형에 대한 정보를 요구하는 이유 중 하나기도 하다.

① 포인터 증가
포인터를 증가시키는 것은 포인터에 저장된 변수 주소의 종류에 따라 달라진다. 만약 포인터가 정수형 변수의 주소를 저장했다면, 정수형 포인터의 크기는 32비트 또는 64비트 시스템에 따라 각각 4바이트 또는 8바이트가 될 수 있다. 따라서 이제 정수형 변수를 증가시키면, 크기에 따라 4바이트 또는 8바이트가 증가하는 것이다.

예를 들어, 포인터가 주소 1000을 유지할 때 포인터를 늘리면, 포인터가 4바이트 또는 8바이트씩 증가하고, 포인터는 이제 주소 1004를 유지하게 된다.

② 포인터 감소
포인터에 감소 작업을 적용하면, 포인터가 4바이트 또는 8바이트씩 감소한다.

예를 들어, 포인터가 주소 1004를 유지할 때 포인터를 줄이면, 포인터가 4바이트 또는 8바이트씩 감소하고, 이후 포인터가 주소 1000을 유지하게 되는 것이다.

 

아래의 그림을 통해 더욱 쉽게 이해할 수 있다.

증가 및 감소 포인터의 예시:

// CPP program to demonstrate the incrementy and decrement 
// of a pointer 
#include <iostream> 
using namespace std; 

int main() 


     int num = 27; 
     // Storing address of num in num_pointer 
     int* num_pointer = # 

     // Print size of int 
     cout << "Size of int: " << sizeof(int) << endl; 

     // Print the address stored at num_pointer 
     cout << "Before Increment: " << num_pointer << endl; 
     // Increment pointer 
     num_pointer++; 

     cout << "After Increment: " << num_pointer << endl; 

     // Print the address stored at num_pointer 
     cout << "Before Decrement: " << num_pointer << endl; 
     // Decrement pointer 
     num_pointer--; 

     cout << "After Decrement: " << num_pointer << endl; 

     return 0; 
}

 

출력:

Size of int: 4
Before Increment: 0x7ffe3e7f56d4
After Increment: 0x7ffe3e7f56d8
Before Decrement: 0x7ffe3e7f56d8
After Decrement: 0x7ffe3e7f56d4

 

변수'num의 주소를 저장한 포인터 ptr에서 1을 뺀 상태다. 뺄셈은 먼저 1에 정수의 크기인 4바이트를 곱한 다음, 포인터에서 뺄셈을 한다.

같은 방식으로 이는 float, double, char 등과 같은 다른 데이터 유형에도 적용할 수 있다.

3. 포인터에 상수 더하기

포인터에 정수 값을 추가할 수 있으며, 포인터는 포인터가 가리키는 데이터 유형의 크기에 따라 조정된다. 예를 들어, 정수 포인터가 주소 1000을 저장하고 값 5를 포인터에 추가하면, 다음과 같이 새 주소가 저장된다:

1000 + (5 * 4(size of an integer)) = 1020

포인터에 상수 더하기 예시:

// CPP program to demonstrate the addition of a constant to 
// a pointer 
#include <iostream> 
using namespace std; 

int main() 


     int num = 20; 
     int* ptr = # 

     cout << "Address stored in ptr: " << ptr << endl; 

     // Adding the integer value 1 to the pointer ptr 
     ptr = ptr + 1; 
     cout << "Adding 1 to ptr: " << ptr << endl; 

     // Adding the integer value 2 to the pointer ptr 
     ptr = ptr + 2; 
     cout << "Adding 2 to ptr: " << ptr << endl; 

     return 0; 
}

 

출력:

Address stored in ptr: 0x7ffdb8634a94
Adding 1 to ptr: 0x7ffdb8634a98
Adding 2 to ptr: 0x7ffdb8634aa0

 

정수 유형의 변수를 초기화한 다음, 변수 num의 주소를 가진 정수 유형의 포인터 ptr을 초기화했다. 다음으로, 포인터 ptr에 저장된 주소를 ptr에 1을 추가한 후, ptr에 저장된 주소를 다시 프린트한다. 이제 출력에서 1 대신 4가 ptr에 추가되는 것을 볼 수 있다. 왜냐하면, 포인터에 임의의 상수를 추가할 때, 먼저 정수인 포인터 유형의 크기에 곱하고, 여기서는 4바이트가 필요하기 때문이다. 따라서 먼저 1에 4를 곱한 다음, (1*4)를 포인터에 더한다. 2를 추가하면, (2*4)가 포인터 ptr에 추가된다.

4. 포인터에서 상수 빼기

포인터에서 상수를 뺄 수도 있는데, 이는 포인터에 상수를 더하는 것과 같은 이치로 이해하면 된다. 예를 들어, 정수 포인터가 주소 1000을 저장하고 우리가 포인터에서 값 5를 빼면 새 주소는 다음과 같이 저장된다:

1000 - (5 * 4(size of an integer)) = 980

예시:

// CPP program to demonstrate the subtraction of a constant 
// from a pointer 
#include <iostream> 
using namespace std; 

int main() 


     int num = 100; 

     int* ptr = # 

     cout << "Address stored in ptr: " << ptr << endl; 

     // Subtracting the integer value 1 from pointer ptr 
     ptr = ptr - 1; 
     cout << "Subtract 1 from ptr: " << ptr << endl; 

     return 0; 
}

5. 동일한 유형의 두 포인터 빼기

두 포인터의 뺄셈은 두 포인터의 데이터 유형이 같을 때만 수행할 수 있다. 문자형에서 숫자형을 뺀 결과를 계산할 수는 없는 노릇이니 말이다. 두 포인터의 뺄셈은 두 포인터 사이에 존재하는 요소의 수를 제공한다.

 

예시:

// CPP program to demonstrate the subtraction of two 
// pointers 
#include <iostream> 
using namespace std; 

int main() 


     int num = 45; 

     int* ptr1 = # 

     // Adding 4 to ptr1 and stored in ptr2 
     int* ptr2 = ptr1 + 4; 

     cout << "Address stored in ptr1:" << ptr1 << endl; 
     cout << "Address stored in ptr2:" << ptr2 << endl; 

     // Subtracting ptr2 from ptr1 
     cout << "ptr2 - ptr1 = " << ptr2 - ptr1 << endl; 

     return 0; 
}

 

출력:

Address stored in ptr1:0x7ffdd3f5673c
Address stored in ptr2:0x7ffdd3f5674c
ptr2 - ptr1 = 4

6. 포인터 비교

C++에서는 관계 연산자(>, <, >=, <=, ==, !=)를 사용하여 두 포인터 간의 비교를 수행할 수 있다. 일반적으로 두 포인터가 동일한 메모리 위치를 가리키는지 여부를 확인하기 위해 이 연산을 사용한다.

 

예시:

// C++ Program to illustrate the pointer comparison 
#include <iostream> 
using namespace std; 

int main() 

     // declaring some pointers 
     int num = 10; 
     int* ptr1 = # 
     int** ptr2 = &ptr1; 
     int* ptr3 = *ptr2; 

     // comparing equality 
     if (ptr1 == ptr3) { 
          cout << "Both point to same memory location"
    
     else 
          cout << "ptr1 points to: " << ptr1 << endl; 
          cout << "ptr3 points to: " << ptr3 << endl; 
    
     return 0; 
}

 

출력:

Both point to same memory location

7. Null과의 비교

우리는 포인터를 Null과 비교할 수 있다. 이 연산은 우리가 주어진 포인터가 어떤 메모리 주소를 가리키는지 아닌지를 찾는데 도움을 준다. 이것은 우리가 분할 오류와 같은 오류를 제어하는데 도움을 줄 것이다.

 

예시:

// C++ program to compare the pointer to NULL 
#include <iostream> 
using namespace std; 

int main() 

     int num = 10; 
     // assigning null in case we dont use pointer 
     int* ptr = NULL; 
     ptr = # 

     // checking if the pointer is in use or not 
     if (ptr == NULL) { 
          cout << "No value is pointed"
    
     else 
          cout << "The value pointed is " << *ptr; 
    
     return 0; 
}

 

출력:

The value pointed is 10

 

참고로, Null로 새로운 포인터 변수를 초기화하여 포인터에 의미 있는 값이 할당되었는지 확인할 수 있도록 하는 것이 좋을 것이다.

728x90

'C++' 카테고리의 다른 글

C++ 포인터 응용  (0) 2024.05.17
C++ 댕글링, 보이드, 널, 와이드 포인터  (0) 2024.05.16
C++ 포인터(Pointers) 총정리  (0) 2024.04.29
C++ 포인터와 레퍼런스 정리  (0) 2024.04.29
C++ 람다식(Lambda expression) 총정리  (2) 2024.04.25