왜 변수에 포인터를 입력해야하는지 ...

#include <stdio.h>
void main()
{
    int a[] = {10,20,30,40,50,60,70,80,90,100};
    int k,m,i,*ptr;
    k=m=0;
    ptr=a;
    for(i=0; i<10; i+=2)
    {
        k+=ptr[i];
        m+=ptr[i+1];
    }
    printf("***** result ***** \n\n");
    printf("(10+30+50+70+90)=%d\n",k); //250
    printf("(20+40+60+80+100)=%d\n",m); //300
}

저기 위 *ptr에서 왜 *을 붙여야 하는지 잘 모르겠습니다.

포인터를 주지 않고 그냥 ptr로 작성해도 괜찮지 않나요?

또한 *를 주었을 때 변수 a[]를 불러오는지 잘 모르겠습니다.

  • 덕분에 저도 배워갑니다. 이성우 2016.9.27 23:33

2답변

  • 안녕하세요! 올려주신 코드는 아래의 방식으로 하셔도 상관 없습니다!

    #include <stdio.h>
    void main()
    {
        int a[] = {10,20,30,40,50,60,70,80,90,100};
        int k,m,i;    //*ptr;
        k=m=0;
        // ptr=a;
        for(i=0; i<10; i+=2)
        {
            k+=a[i];
            m+=a[i+1];
        }
        printf("***** result ***** \n\n");
        printf("(10+30+50+70+90)=%d\n",k); //250
        printf("(20+40+60+80+100)=%d\n",m); //300
    }
    

    그리고 배열을 포인터로 받은 이유는 배열 자체가 포인터의 집합이기 때문입니다.

    예를 들자면 포인터는 열차의 1개 칸 혹은 동력이 있는 머리 부분이고 배열은 완성된 1개의 열차라고 보시면 됩니다.

    따라서 포인터로 배열을 받아 배열처럼 사용하는 것이 가능하기 때문에 그것을 보여주기 위한 코드로 보입니다.

  • 위의 답변으로도 충분하지만, 혹시라도 포인터와 배열의 관계에 대해 좀 더 깊이 알고 싶은 분들을 위해 추가적으로 내용을 남깁니다.

    int main()
    {
        int a[] = {10,20,30,40,50,60,70,80,90,100};
        // 위 코드는 암시적으로 아래 코드로 변환됩니다.
        // int a[10] =  {10,20,30,40,50,60,70,80,90,100};
        // c, c++ 에서 배열 타입은 고정된 크기가 정해져야만 하기 때문입니다.
        // 실제로 a 라는 변수의 타입은 'int [10]' 타입입니다.
    
        // 그런데 배열 타입은 보기에 좀 복잡해 보이기 때문에 가독성이 떨어집니다.
        // 그래서 보통은 포인터 타입으로 변환해서 사용합니다.
        // c, c++ 에서 배열 타입은 암시적으로 포인터 타입으로 캐스팅할 수 있습니다.
    
        int* ptr = a; // 때문에 a변수를 다른 변수에 저장하고 싶을 때, 이렇게 씁니다.
    
        // 하지만 위와 같은 경우 사실 암시적 캐스팅에 의해 배열의 길이 정보를 잃어버리게 됩니다.
        // 배열 타입은 타입 자체에 배열의 크기를 가지고 있다는 점에서 포인터와 다릅니다.
    
        // 즉, 변수 'a'와 변수 'ptr'은 사실상 같은 값(배열의 시작 주소)를 가지지만,
        // 'a'는 타입자체에 배열길이가 10이라는 정보를 가지고 있고,
        // 'ptr'은 단지 int형 주소값이라는 정보만 가지고 있는 점에서 차이가 생깁니다.
    
        // 그럼 그 배열길이 정보라는게 어디서 써먹냐? 싶을 수 있는데,
        // c에서의 예제는 이해하기 복잡한 부분이 많기 때문에,
        // c++의 Range-based for loop를 예로 들겠습니다.
    
        // 이 경우 'a'라는 변수의 타입이 배열의 길이정보를 가지기 때문에 배열을 순회할 수 있습니다.
        for (int i : a)
        {
            i = 0;
        }
    
        // 하지만 이 경우는 'ptr'이 포인터 타입이기 때문에 길이정보가 없어 배열을 순회할 수 없습니다.
        /*
        for (int i : ptr) // error
        {
            i = 0;
        }
        */
    
        // 질문에서의 이 부분의 코드가 동작할 수 있는 이유는
        int k,m,i;
        k=m=0;
        for (i = 0; i < 10; i += 2)
        {
            k += ptr[i]; // 여기서의 [ ]는 타입이 아니라 연산자이기 때문입니다.
            m += ptr[i+1];
        }
    
        // '[ ]' 연산자는 포인터 타입에서도 사용할 수 있으며,
        // 해당 포인터 변수에 저장된 주소로부터 '[ ]' 안에 들어가는 숫자만큼
        // 포인터 연산을 통해 이동한 해당 위치의 값의 참조를 반환하는 연산자입니다.
    
        // 즉, k += ptr[i] 는 k += *(ptr + i) 와 같은 코드이고,
        // (ptr + i)는 ptr값에 i값을 더한다는게 아니라,
        // ptr값에 (i * sizeof(int))의 결과값을 더한다는 뜻입니다. (포인터 연산)
        // 포인터 연산으로 변경된 위치의 주소값을 '*'연산자를 통해 참조하여 레퍼런스를 반환하게 되며,
        // 반환되는 타입은 int& 타입으로 볼 수 있습니다.
    
        // 참고로 위의 'a' 변수를 레퍼런스 타입으로 받으려면
        int(&b)[10] = a; //이렇게 써야하며,
    
        // 배열 타입에 대한 레퍼런스 타입은 배열 타입과 똑같이 사용할 수 있습니다.
        for (int i : b) // ok
        {
            i = 0;
        }
    
        return 0;
    }
    
    • 답변해주셔서 감사합니다. TAEG 2016.9.29 21:46

ᕕ( ᐛ )ᕗ
로그인이 필요합니다

작성한 답변에 다른 개발자들이 댓글을 작성하거나 댓글에 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.