C언어와, C언어와 강력한 호환성을 자랑하는 C++에서는 포인터(pointer)라는 개념이 사용된다. 이번 포스팅에서는 포인터에 대해서 알아보자.
💡 포인터
실행 중인 메모리의 주소 값으로, 주소를 이용해서 메모리에 직접 값을 쓰거나, 메모리로부터 값을 읽어올 수 있다.
기본적으로 변수는 프로그램 내에서 사용하는 이름으로써, 각 변수마다 메모리 공간이 새롭게 할당된다. 예를 들어보면 다음과 같다.
int a = 10; // a라는 변수를 선언해, 10이라는 값을 부여
int * ptr; // 포인터 변수 선언
ptr = &a; // ptr 포인터 변수에 a의 주소 값을 저장한다
변수를 선언하였을 때 변수에 대한 메모리 주소는 알수가 없다. 프로그램이 시작할 때 변수에 메모리 주소가 정해지기 때문이다.
포인터 변수는, 실행 중인 프로그램에서 변수의 메모리 주소를 알아내고, 이를 사용할 수 있도록 해주는 변수이다.
"*" 연산자를 통해서 포틴터 변수를 선언할 수 있으며, 변수의 주소는 & 연산자를 이용해서 할당할 수 있다.
또 다른 예시를 들어보자.
int n;
int *p = &n;
*p = 25; // n에 25가 저장됨
int m;
m = *p + 10; // m에는 35의 값이 저장됨
포인터는 배열과 매우 밀접한 관련을 가지고 있다. C/C++에서 배열 이름은, 배열 메모리의 시작 주소를 가리키는 포인터 역할을 하기 때문에, 포인터로 사용할 수 있다.
예를 들어보자.
int n[10];
// 다음 2개의 코드는 같은 내용이다.
n[5] = 8;
*(n+5) = 8;
따라서 포인터 변수에 배열의 시작 주소를 줄 수 있음을 알 수 있다.
int arr[5] = {1,2,3,4,5};
int *ptr = arr;
for(int i = 0; i<5; i++){
cout<<*(ptr+i)<<endl;
}
만약 배열을 포인터 변수에 할당하면, 다음과 같은 산술 연산도 가능하다.
int *p;
int n[10];
p = n; // 포인터 변수에 배열 주소 할당
*p = 100; // n[0] = 100이랑 동일
*(p+5) = 8; // n[5] = 8과 동일
p = p+7; // p는 n[7]의 주소를 가지게 됨
*p = 99; // n[7] = 99와 동일해짐
다음은 포인터를 이용해서 배열의 원소에 접근하는 예시 코드이다.
#include <iostream>
using namespace std;
int main() {
int n[10];
int i;
int* p;
for (i = 0; i < 10; i++)
*(n + i) = i * 3; // 배열의 이름 n을 포인터처럼 사용이 가능하다.
p = n; // 포인터를 통해서 배열 접근이 가능
for (i = 0; i < 10; i++)
cout << *(p + i) << ' '; // 포인터를 통해서 배열의 원소들의 값 출력
cout << endl;
for (i = 0; i < 10; i++) {
*p = *p + 2; // 포인터를 이용해서 배열 n의 값들을 2씩 증가
p++; // p는 다음 주소로 증가한다.
}
for (i = 0; i < 10; i++)
cout << n[i] << ' ';
cout << endl;
}
함수의 매개변수(인자)로 포인터를 사용할 수 있으며, 이를 통해서 함수 내부에서 변수의 값을 메모리 수준에서 직접 수정이 가능하다.
#include<iostream>
using namespace std;
bool equal(int* p, int* q);
int main() {
int a = 5, b = 6;
if (equal(&a, &b)) cout << "equal" << endl;
else cout << "not equal" << endl;
}
bool equal(int* p, int* q) {
if (*p == *q) return true;
else return false;
}