🖥️ CS, 개발상식/자료구조

[자료구조/C] 포인터

dev_zoe 2020. 7. 29. 18:56
반응형

포인터란?

다른 변수의 메모리 주소(바이트 단위)를 가지고 있는 변수

정수형, 실수형, 문자형 등 여러 가지 자료형으로 선언될 수 있다.

 

  • 주소연산자 : &
  • 간접 (참조) 연산자 : *

ex)

int *p; // 정수형 포인터 선언
int a = 200; //정수형 변수 선언

p = &a; //포인터 p는 a의 메모리 주소를 가리킨다. 즉, p는 변수 a를 가리킨다.

출처:C언어로 쉽게 풀어쓴 자료구조

  • p의 값은? : 변수 a의 주소값
  • *p의 값은? : 변수 a가 실제로 가지고 있는 값(200)
  • 위 코드에 *p = 20을 마지막에 추가하면 a의 값은? : 20으로 바뀐다. 포인터 p는 변수 a를 가리키고 있어서 값을 복사하는 것이 아니다. 따라서 *p의 값을 변경하면 a의 값도 같이 바뀐다.

 

널 포인터

어떤 객체도 가리키지 않는 포인터이다.

포인터가 아무 것도 가리키고 있지 않을 때 널 포인터 상태로 두는 것이 좋다. 널 포인터로 간접 참조하려고 하면 컴퓨터 시스템에서 오류가 발생할 수 있기 때문이다.

 

if (p==NULL){
	fprintf(stderr, "오류: 포인터가 아무 것도 가리키지 않습니다.");
    return;
}

 

포인터와 배열

배열의 이름은 배열 첫번째 원소의 주소값을 나타내는 포인터 상수이다.

 

출처: C언어로 쉽게 풀어쓴 자료구조

실제로 컴파일러가 배열의 이름에 공간을 할당하지 않는다.

대신에 배열의 이름에 배열의 첫 번째 요소의 주소를 대치한다.

즉, 배열의 이름은 포인터이다.

 

이것은 메모리 공간과 함수 호출 시간을 절약하기 위함이기도 하다.

함수에서 실제로 배열을 호출하여 사용할 때 배열을 복사할 필요가 없기 때문이다.

 

ex)

int array[3] = {10, 20, 30};
int *p = array;

for (int i=0; i<3; i++){
    printf("%d\n", *p); //array의 각 원소의 실제 값 => 10, 20, 30 차례대로 출력
    p++; //배열의 다음 원소의 주소로 이동
}

 

이때, array[0]의 주소값이 0B70이면 array[1]은 +sizeof(int), 즉 4byte가 더해져 0B74이고 array[2]도 똑같은 방식으로 0B78이된다.

 

포인터 변수인 p는 마치 배열의 이름처럼 쓰일 수 있다.

즉,

p + i = &p[i] = &array[i]

*(p+i) = p[i] = array[i]

 

ex)

void changeData(int p[], int size) //p[]는 *p로 대체 가능
{
   int ;
   for (i=0; i<size; i++)
   		p[i] = 99; // *(p+i) = 99; 로 대체 가능
}

...

int main(void){
    int data[5] = {1, 2, 3, 4, 5};
    
    changeData(data, 5); //data는 data 배열의 첫 번째 요소의 주소값
}

 

함수의 매개변수로 포인터 사용하기

1. Call-by-value(값에 의한 호출)

 

void f1(int x)
{
	x = x+10;
}

int main(void)
{
    int a = 5;
    f1(a);
    printf("%d\n", a);
}

 

여기서 x의 값은 15가 되지만, a의 값은 여전히 5이다.

값에 의한 호출은 인수의 값만 매개변수로 전달하기 때문에 x가 a의 값을 복사하여 사용하기 때문이다.

 

2. Call-by-reference(참조에 의한 호출) ★

 

void f2(int *p)
{
	*p = *p+10;
}

int main(void)
{
   int a = 5;
   f2(&a);
   printf("%d\n", a);
}

 

여기서 a의 값은 15가 된다. 인수의 주소가 매개 변수로 전달되기 때문에 포인터 p는 a를 가리키게 되고, a의 값에 10이 더해져 15가 된다.

 

 

따라서, 메모리를 복사하지 않고 포인터가 가리키는 변수 자체의 값을 변경하고자 하면 반드시 call-by-reference로 인수를 전달해야한다.

 

 

반응형