포인터

int *p;

포인터 타입변수는 변수의 주소값을 다루는 데이터 타입입니다.

변수의 주소에 접근하여 제어해야할 때, 큰 데이터, 배열을 옮길 때 활용할 수 있습니다.


포인터도 데이터 타입이지만, 일반적인 변수와 유사하게 타입(base type)을 가지게 됩니다

렇기에 다른 타입의 포인터 변수로 초기화하면 에러가 발생합니다.


포인터 변수 선언

int *p;

포인터 변수를 선언하는 방식은 간단합니다.

원하는 데이터 타입을 입력하고, 변수명과 데이터 타입 사이에 *연산자를 입력합니다.

int* a;
int * b;
int *c;

위치는 크게 상관이 없습니다. 본인이 원하는 스타일로 작성할 수 있습니다.


* 연산자 (Deferencing Operator)

int *p = /* 주소값 */;

printf("%d \n", *p);

*연산자는 포인터 변수에 저장된 주소값이 나타내는 데이터를 나타내는 기능을 가지고 있습니다.

포인터 변수 앞에 *연산자를 사용하면, 주소에 저장된 데이터로 접근할 수 있습니다.


포인터 변수에도 *연산자를 활용하면 일반 변수와 비슷하게 활용할 수 있습니다.


& 연산자 (Addressing Operator)

int a = 0; 

int *p = &a;

출력 함수인 scanf함수에서도 활용했던 연산자입니다.

&연산자는 변수의 주소값을 나타내는 기능을 가지고 있습니다.

모든 변수에 활용할수 있고, 포인터 변수의 데이터 타입과 일치하면 포인터 변수에 &연산자를 활용하여 주소를 저장할 수 있습니다.


NULL

int *p = NULL;

NULL은 주소가 없음을 의미합니다.


NULL 과 0의 차이

null and 0


NULL은 0 과 비슷한 개념이지만, 다릅니다.

0은 ‘0’이라는 데이터가 있지만, NULL 은 데이터 자체가 없는 경우를 뜻합니다.


배열과 포인터

전에 설명했듯, 배열은 메모리에 연속적으로 선언되는 구조입니다.

때문에, 배열은 포인터 변수와 거의 비슷한 구조를 가집니다.


arr[n];

배열을 활용하기 위해선 [] 연산자를 활용합니다.

이 연산자는 해당 변수(주소)에 n 번이후에 있는 데이터를 뜻합니다.

이로 알 수 있듯, 배열은 포인터와 유사하게 활용할 수 있습니다.


*(arr + n)

위 코드는 위에서 설명한 배열과 같은 역할을 합니다.


int arr[10];
int *p = &arr[0];
p = arr;

포인터는 배열을 저장할 수 있습니다.

전에 설명했듯 c언어는 다른 언어와 다르게 배열은 다른 배열로 초기화할 수 없습니다.

만약 하고 싶다면, 반복문을 활용해서 각각 초기화를 진행해야 합니다.

하지만, 포인터를 활용하면 배열을 초기화 할 수 있습니다.


int *k;
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

k = arr;
printf("%d", k[5]);

위 코드는 포인터를 활용하여 배열에 접근하는 방식입니다.

결과값으로는 6이 나옵니다.


배열과 포인터의 차이

배열과 포인터는 구조적으로는 거의 동일한 구조를 가지고 있습니다.

하지만, 전에 설명했듯 배열은 주소를 바꿀 수 없습니다.

포인터는 주소를 자유롭게 바꿀 수 있죠.

또, 이후에 설명하겠지만, 포인터를 배열처럼 활용한다면, 배열을 더 효율적으로 활용할 수 있습니다.


포인터 활용

void swap(int *a, int *b) {
    int temp;
    temp = *a;
    *a = *b;
    *b = temp; 
}

전에 설명했듯, 함수는 해당 변수를 데이터만 가져옵니다.

그렇기 때문에, 변수의 데이터를 아무리 바꾸어도 데이터는 변하지 않습니다.


하지만 위 코드는 포인터로 주소값을 받아옵니다.

함수에서 주소로 접근하여 변수 데이터를 활용하기 때문에, 데이터가 원하는대로 변경됩니다.


call by value / call by reference

위에서 설명한 데이터만 가져오는 경우가 call by value 방식입니다.

변수의 데이터를 호출(call)하기 때문에, 변수의 데이터는 바뀌지 않습니다.

  • 이 경우 변수는 호출된 데이터를 저장하는 데이터 공간이(메모리) 생성됩니다.

포인터를 활용한 방식이 call by reference 방식입니다.

변수의 주소를 호출하기 때문에, 변수의 데이터도 변경됩니다.


void changeString(char *str, char text[]) {
    str = text;
}
....

char a[10];
changeString(a, "abcd");

전에 설명했던 문자열(문자의 배열)도 결국 배열입니다.

그렇기에 함수에서 호출하는 경우 call by reference 방식으로 호출됩니다.



이미지 출처

💡 지적 환영합니다

Comments