알고리즘

[알고리즘] 포인터(자료구조2)

sundori 2023. 9. 14. 20:09

목차

    # 포인터 개념

    사용한느 모든 변수는 메모리의 특정 위치에 저장되는데 그 위치를 나타내는 메모리 주소를 포인터라고 한다.

    포인터 변수는 메모리의 주소값을 저장하며, 포인터 변수 P가 어떤 변수 A의 주소를 저장하고 있다는 것은 포인터 변수 P가 변수 A의 위치(메모리 주소)를  가리키고 있다는 의미이다.

    다른 말로는 포인터를 사용해 다른 변수를 액세스 할 수 있다는 소리이다.

    int A;
    int *P =  &A; // 메모리 주소 한 개 저장.
    /*
    *int A에서 int 형 A변수를 선언했을 때 할당된 메모리 번지 예를들어 1번지라할 때, int *P = &A에 의해서
    *변수 A의 주소 1번지를 포인터 P에 저장하므로 포인터 P는 변수 A를 가리키게 된다.
    *그러면 변수 A와 포인터 P가 논리적으로 서로 연결되어 P을 사용하여 변수 A를 액세스할 수 있게 된다.
    */

    포인터 선언

    자료형 *포인터이름;
    ...
    char *P; // 1바이트이의 문자형 변수의 주소를 저장할 포인터 선언
    short *P;// 2바이트의 short형 변수의 주소를 저장할 포인터 선언
    int *P;  // 4바이트의 정수형  변수의 주소를 저장할 포인터 선언

    포인터에서 선언한 자료형에 따른 메모리 액세스 범위!

    • 위 그림에서 포인터의 자료형에 상관없이 char *p, short *p, int *p 모두 포인터 p 자체의 크기는 메모리 주소 한 개의 크기인 4byte.

    포인터 연산

    c언어에서 사용하는 포인터 관련 연산자는 주소 연산자(&)참조 연산자(*)가 있다.

     

    주소 연산자(&)

    주소 연산자 &는 변수의 주소를 얻는 데 사용하며 변수 앞에 주소 연산자를 사용하면 그 변수의 주소를 사용할 수 있다.

    이때 주소 연산자를 사용할 변수와 포인터는 같은 자료형으로 선언되어 있어야 한다.

    포인터 = &변수;
    p = &A;

    포인터 선언과 사용 예.

    참조 연산자(*)

    다른 변수의 주소가 저장된 포인터에 참조 연산자*를 사용하면 저장된 주소 영역(참조 영역) 또는 저장된 주소 영역의 값(참조 값)을 액세스 할 수 있다.

    *포인터 = 값;
    변수 = *포인터;
    ...
    // 각 변수 선언
    int A;
    int *p;
    //참조 연산자를 이용한 값 대입.
    *p = 10;
    A = *p;

    포인터 초기화

    포인터를 초기화하는 방법은 일반 변수를  초기화하는 방법과 같다!

    하지만... 초깃값이 일반 데이터값이 아니라 메모리 주소라는 것을 인지해야 한다.

    // 잘못된 초기화.
    int *p = 5; 
    /*
    *5번지가 있을 수 있지만 메모리 주소는 컴파일을 하면서 
    *시스템이 정하기 때문에 임의로 정할 수 없다.
    *내가 사는 집 주소를 임의로 정할 수 없듯이 말이다.
    */
    ...
    // 올바른 초기화 예들.
    int A;
    int *p = &A; 
    // 주소 연산자를 사용하여 변수 주소를 지정한다.
    ...
    char *p = (char *)malloc(100);
    // 동적 메모리를 할당하고 그 시작 주소를 포인터 값으로 지정한다.
    // 동적 메모리를 할당하는 malloc()함수를 사용하여 문자형(char) 공간
    // 100개를 할당하고, 그 시작 주소를 포인터에 반환한다.
    ...
    char A[100];
    char *p = A;
    // 배열의 이름은 시작 주소이다. 따라서 배열 이름을 이용하여 시작 주소를 지정한다.
    ...
    char A[100];
    char *p = &A[0];
    // 배열의 첫 번째 원소의 주소를 이용하여 시작 주소를 지정한다.
    ...
    char *p = "String";
    // 문자형 포인터에 문자열의 시작 주소를 지정한다.

    포인터 배열

    포인터 배열은 여러 개의 포인터를 하나의 배열로 만든 것으로, 배열과 포인터의 특징을 모두 활용이 가능하다.

    자료형 *포인터배열이름[배열크기];
    ...
    char *p[2] = {{"Hello"}, {"World!"}};
    p[0] H e l l o \n
    p[1] W o r l d \n

    이중 포인터

    이중 포인터는 포인터를 가리키고 있는 포인터, 즉 일반 변수의 주소가 아니라 포인터의 주소를 가지고 있는 포인터를 의미한다.

    int main(void)
    {
        int i = 10;
        // 변수 i 선언
        int *p = &i;
        // 포인터 p 선언과 동시에 i의 주소 값 지정.
        int **q = &p;
        // 이중 포인터 선언과 동시에 포인터 p의 주소 값 지정.
        *p = 200;
        // 포인터 p가 i의 주소값을 가지고 있으므로 i의 값이 10에서 200으로 바뀐다.
        **q = 300;
        // 포인터 q는 포인터 p의 주소 값을 가지고 있고
        // 포인터 p는 i의 주소 값을 가지고 있으므로
        // 결국에는 i의 값이 10 -> 200 -> 300 순서로 바뀐다.
    }

    이해가 어렵다면 밑에 표를 봐보자.

    변수 i = 30   포인터 p = 1   이중 포인터 q = 16
    1번지 2번지 3번지  4번지 .... 16번지 17번지 18번지 19번지 ..... 24번지 25번지 26번지 27번지