본문 바로가기
쿤즈 Dev/C

[C언어] 포인터를 이용해서 배열 사용하기

by :)Koon 2020. 11. 10.

앞선 포스팅에서는 포인터의 가장 기본적인 내용에 대해서 알아보았습니다.

2020/10/31 - [쿤즈 Dev/C] - [C언어] C언어의 꽃. 포인터를 알아보자!

 

[C언어] C언어의 꽃. 포인터를 알아보자!

그동안 C언어를 포스팅 해 오면서 키워드와 식별자, 변수와 상수, 제어문과 반복문, 배열을 차례대로 알아보았습니다. 그리고 많아 분들이 포기하는 부분중 하나인 포인터를 포스팅하려 합니다.

koonsland.tistory.com

포인터는 C언어에서 필수적인 요소입니다. 메모리를 동적으로 할당하고 반납하면서 효율적으로 사용하기 위해서는 반드시 포인터를 사용해서 접근해야합니다.

 

 

이번 포스팅에서는 전에 알아보았던 배열과 포인터와의 관계를 알아보고 포인터를 이용해서 배열을 사용하는 방법을 알아보도록 하겠습니다.


포인터와 배열과의 관계

앞선 포스팅에서 말씀드렸듯이 포인터는 메모리의 주소를 가리키는 값을 의미합니다. 그래서 변수의 주소를 알기 위해서 우리는 & 기호를 붙여서 표현하였습니다. 예를 들어보겠습니다.

int x[3] = {1, 2, 3};

여기서 값 1을 표현하기 위해 변수로 나타내면 x[0] 으로 표현합니다. 그리고 이때 주소를 나타내면 &x[0] 라고 표현할 수 있습니다. 그리고 이를 우리는 포인터라 합니다.

 

여기서! 그냥 x 라고만 하면 어떤 의미가 될까요? 배열에서 변수의 이름만 나타내면 이는 이 배열의 첫 번째 주소를 의미합니다. 즉 &x[0] 과 x 는 같은 값을 가리키게 됩니다.

 

그렇다면 두 번째 주소는 어떻게 표현할까요? 배열로 표현하면 &x[1] 입니다. 그리고 이를 배열 변수의 이름으로 표현하게 되면 x+1 이 됩니다. 즉, 다음 주소를 의미하게 되죠. 이것이 포인터와 배열, 둘 사이의 관계의 시작입니다. 소스코드를 통해서 다시 한 번 확인해 보겠습니다.

 


소스코드1 array_pointer1.c

#include <stdio.h>
 
int main(int argc, char* argv)
{
    int x[3] = { 1, 2, 3 };
    int i;
 
    for (i = 0; i < 3; i++) {
        printf("&x[%d] : %p, x[%d] : %d\n", i, &x[i], i, x[i]);
    }
 
    printf("\n");
    
    for (i = 0; i < 3; i++) {
        printf("&x[%d] : %p, x[%d] : %d\n", i, x + i, i, *(x + i));
    }
 
    return 0;
};

결과1

&x[0] : 010FF950, x[0] : 1
&x[1] : 010FF954, x[1] : 2
&x[2] : 010FF958, x[2] : 3

&x[0] : 010FF950, x[0] : 1
&x[1] : 010FF954, x[1] : 2
&x[2] : 010FF958, x[2] : 3

최초 변수 x 는 정수형 자료형으로 크기가 3인 배열을 선언하였고 값은 1, 2, 3 으로 초기화 했습니다. 그리고 서로다른 방법을 이용해서 주소와 값을 출력해 볼 예정입니다.

 

첫 번째 for 반복문에서는 배열을 이용해서 순서대로 출력했습니다. 주소를 출력하기 위해서 %p 를 사용하였고 여기에 출력되는 값은 &x[i] 를 이용해서 주소를 출력하도록 프로그래밍했습니다.

 

두 번째 for 반복문에서는 & 연산자를 사용하지 않고 배열 변수인 x 를 이용해서 출력해 보았습니다. 위에서 설명드린듯이 순서대로 주소를 나타내기 위해서 x+0, x+1, x+2 로 표현하도록 하였으며 값을 출력하기 위해서는 * 연산자를 사용했습니다. * 연산자는 값을 나타낼때 사용하는 연산자입니다.


포인터 변수를 이용한 배열

이전 포스팅에서 포인터 변수에 대해서 알아보았습니다. 다시 설명드리면 포인터 변수는 어떠한 변수의 주소값을 저장할 수 있는 변수입니다. 그리고 이 변수를 선언할 때에는 반드시 * 연산자를 붙여서 포인터 변수임을 알려줍니다.

int* pnum;

이렇게 선언된 포인터 변수 pnum은 주소를 담을 수 있도록 선언되는 변수입니다. 그럼 이제 포인터 변수를 통해서 어떻게 접근하는지 소스코드를 통해서 알아보도록 하겠습니다.


소스코드2 arrya_pointer2.c

#include <stdio.h>

int main(int argc, char* argv)
{
    int x[3] = { 1, 2, 3 };
    int* px;
    
    px = x;

    printf("*px = %d\n", *px);              //x[0]
    printf("*(px+1) = %d\n", *(px + 1));    //x[1]

    return 0;
};

결과2

*px = 1
*(px+1) = 2

가장먼저 소스코드1과 같이 배열을 하나 선언합니다. 그리고 그 아래에 포인터 변수인 int* px; 를 선어합니다.

 

이렇게 선언된 배열변수 x 와 포인터 변수 px 를 연결하기 위해서 배열변수 x의 시작 주소를 포인터 변수에 대입시켜 줍니다. px = &x[0]; 으로 표현해야 하지만 배열 변수의 변수명은 배열의 시작주소와 같다고 했으므로 px = x; 로 표현해도 됩니다.

 

이제 포인터 변수만을 이용해서 결과를 출력해봅니다. px를 주소를 가지고 있고 *px 는 주소가 가리키는 값을 의미합니다. 따라서 *px = *(px + 0) = 1 이 되는 것입니다. 두 번째 값은 *(px+1) = x[2] = 2 로 표현할 수 있습니다.


이번 포스팅에서는 배열과 포인터와의 관계와 사용방법에 대해서 알아보았습니다. 배열의 변수를 그대로 사용해도 되는데 굳이 포인터 변수를 하나 더 만들어서 사용하는 이유는 뭘까요? 간단한 프로그램에서는 굳이 포인터 변수를 사용하지 않아도 됩니다. 하지만 자료구조로 이동하게 되면 포인터를 사용해야 접근하기가 훨씬 쉬워집니다.

 

지금은 이렇게 접근하는 방법이 있다고 알아두고 기본적인 내용이므로 반복 숙달하는 것이 필요합니다. 메모리 주소를 직접 참조해서 값을 변경하는 방법이 어렵게 느껴질 수 있기 때문이죠. 포기하지 마세요!

댓글