ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [열혈강의 C]Part2. 13장 - 포인터와 배열! 함께 이해하기-첫번째[포인터/배열 완전정복]
    Development/C 2013. 8. 22. 14:07
    반응형





    고고      !!  신나2


     날씨도 더운데 이 선풍기 바람좀 쐬면서 좀 더 시원해지세요~ ㅋㅋㅋ 겨울에 이 글을 보는사람은 어쩔수 엄슴..ㅠㅠ 추워도 참으셔야댐


    이번 시간에는 포인터와 배열을 동시에 배워보도록 하겠습니다.

    포인터를 완벽히 정복하기 위해서는 포인터와 배열을 각각 이해하는 것뿐만 아니라, 이 둘을 함께 이해하는 과정도 필요합니다.

    포인터와 배열은 매우 밀접한 관계를 맺고 있기 때문인데요.이 관계를 이해하는 것은 포인터의 특징을 이해하는데 있어서 상당히 중요한 부분을 차지하니 꼭!! 마스터 하시길 바랍니다!! ㅇㅅㅇb


    향후 다차원배열과 다중포인터의 관계로 들어가다보면 지금보다 훨씬 어려워지게 됩니다. 

    그 때가서 후회하시지마시고 이 장에서 확실히 이해하고 넘어가시길 바랍니다-☆






    13-1. 포인터와 배열의 관계


    ※결론부터 말씀드리자면, 포인터와 배열의 가장 큰 차이점은 '변수'와 '상수'라는 점입니다.





    호호[1]배열의 이름은 무엇을 의미하는가? - 배열의 첫번째요소


     #include<stdio.h>

    int main(void)

    {

            int a[5]={0,1,2,3,4};

     

            printf("%d, %d \n", a[0],a[1]);        //배열요소 출력 

     

            printf("%d, %d \n", &a[0],&a[1]);     //배열요소의 주소 출력

           

            printf("배열이름: %d\n",a);           //배열 이름 출력

     

            return 0;

    }      

     





    <출력결과>



    여기서 유의깊에 보셔야 할 점은 바로 '배열이름'입니다. 

    배열a의 주소가 첫번째 요소인 '0'과 일치하는것을 확인 할 수 있습니다. 

    즉, 배열의 이름은 첫번째 요소를 가리킨다는것을 알 수가 있습니다.



     



    또한 첫번째 요소[0]과 두번째 요소[1]의 주소의 간격은 4라는걸 알수가 있는데, 포인터의 모든 크기는 4바이트입니다.

    (포인터의 크기가 4바이트인 이유?? - 바로 아래에 보시면 Tip이 있으니 참고하세용~)

    안돼깨알Tip보기!!▼(펼치기 클릭!)




    슈퍼맨


     즉, 포인터와 배열의 이름의 가장 큰자이점은 바로 '변수'와 '상수'라는 겁니다.


     비교조건 / 비교대상

    포인터 

    배열 

    이름이 존재하는가? 

    YES 

    YES 

    무엇을 나타내는가? 

    메모리의 주소 

    메모리의 주소 

    변수인가? 상수인가? 

    변수 

    상수 

     

    결론

    첫째, 둘 다 이름이 존재한다.

    둘째, 둘 다 메모리의 주소 값을 나타낸다.

    셋째, 포인터는 변수이다. 배열의 이름은 상수이다.



    즉, 배열의 이름은 상수이기 때문에 다음과 같은 코드는 오류를 발생 시킨다.

     대입 연산자의 왼쪽에 오는 피연산자는 값의 변경이 가능해야 하기 때문에 반드시 변수이어야 한다.

     #include<stdio.h>

    int main(void)

    {

            int a[5]={0,1,2,3,4};

            int b=10;

            a=&b; //a는 상수이므로 오류, a가 변수였다면 PASS!                  

     

            return 0;

    }      

     




    <출력결과 - 이미지를 클릭하시면 크게 보실 수 있습니다.>




    ???[Tip]포인터가 가리키는 변수를 상수화시키는 법!토닥토닥

    [펼쳐보기 클릭!!](이젠 말 안해도 알아서 잘 펼쳐보시길..)▼





    소풍[2]1차원 배열이름의 포인터 타입






    double arr[20];  // arr이 가리키는 첫번째 요소가 double형이므로, arr는 double형 포인터 (duble*)가 된다.





    끝. 



    응?? [2]는 별거없슴다 걍 다음으로 넘어가여 ㅋㅋㅋ





    생각중[3]포인터를 배열의 이름처럼 사용할 수 있다.


    하아.. 처음에 이 제목을 보고 "이건 또 뭔 소리인가" 싶었음.. "포인터를 배열의 이름처럼 사용해서 뭐 어쩌려는건데?!!" 라고 생각했습니다..

    책을 뒤적뒤적 넘겨보니 이를 응용한 연습문제를 찾을 수 있었습니다.

    고객이 임의정보 5개를 입력 한 후, 포인터 2개로 최대값과 최소값을 찾아 전달해주는 프로그램이었는데요.

    배열과 포인터를 통해 효율적으로 찾는 내용입니다. 아무튼 뭐.. 그런데 쓰인다는것만 알면될듯..;; ㅎㅎㅎ


    #include<stdio.h>

     

    int main(void)

    {

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

            int *ptr;

     

            ptr=arr; //포인터 ptr은 배열 모두를 가리키는 것이 아니라 arr[0]을 가리키게 된다.

     

                   printf("%d, %d, %d\n",ptr[0],ptr[1],ptr[2]);

     

            return 0;

    }



    <실행결과>


    실행결과는 1,2,3이 출력됩니다. 많이 신기하셨죠? ㅎㅎ 저두 많이 신기했습니다.


    ----------------------------------------------------------------------------------------------

    ptr=arr; //포인터 ptr가 배열arr[0]을 가리키는 증거를 보여드리겠습니다.


    #include<stdio.h>

     

    int main(void)

    {


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

            int *ptr;

            int *ptr2=&arr[0]; //증거확보용 포인터ㅋㅋㅋ

                  

                   ptr=arr;

     

                   printf("%d, %d\n",ptr,ptr2);

     

            return 0;

    }


       // 배열arr을 가리키는 포인터 [*ptr]와 배열의 첫번째 요소를 가리키는 포인터[*ptr2] 가 있습니다.

           두 포인터를 출력해보니가 보시는것처럼 주소가 같네요 ㅎㅎ 

    <실행결과>





    안습 이해하기 쉽게 설명한 그림임돠..이것도 이해안되시면 답없어요 ㅠㅠ;슬퍼2









    13-2. 포인터연산



    ※포인터 연산이란 포인터 값을 증가 혹은 감소시키는 연산입니다.

    (포인터를 가지고 곱하거나 나누기는 안됩니다.. 주소값을 멋대로 곱하거나 나누면 큰일나겠죠ㅎㅎ)



    하트3[1]포인터는 제한된 형태의 연산이 가능하다.



    ptr++;

    ptr+=3;

    --ptr;

    ptr=ptr1+1;

    ptr+=2;

       <포인터연산.c>


    위 코드의 ptr은 포인터입니다. 위 와같이 증,감하는 연산을 포인터 연산이라고 합니다.

    그렇다면 포인터연산은 어떤 의미를 지니는갸!!!똑똑



    #include<stdio.h>

     

    int main(void)

    {

            int *ptr1=0;           //int* ptr1=NULL; 과 같음

            char* ptr2=0;          //char* ptr2=NULL; 과 같음

            double *ptr3=0;        //double* ptr3=NULL; 과 같음

     

     

            printf("%d번지, %d번지, %d번지\n",ptr1++,ptr2++,ptr3++);

            printf("%d번지, %d번지, %d번지\n",ptr1,ptr2,ptr3);

        return 0;

    }



    <실행결과>


    보시면 아시겠지만 각 포인터들은 타입에 맞게 4,1,8byte씩 증가했다는걸 알 수 있습니다.

    (포인터를 굳이 타입을 지정해야되는 이유는 아까 처음 Tip에서도 설명드렸습니다! 못 보셧던분들은 다시 올라가셔서 보시고 오시길~ ㅎㅎ)



    포인터타입

    증가 전 포인터 값 

    1 증가 후 포인터 값 

    int*

    0

    4

    char*

    0

    1

    double*

    0

    8

    <포인터 연산에 따른 실질적인 값의 변화는 포인터 타입에 따라 다르다> 


    여기서 이제 ~ 쪼~끔 어려운 예제 들어갑니다!방구뽕


    #include<stdio.h>

     

    int main(void)

    {

            int arr[5]={1,2,3,4,5};

     

            int *pArr=arr;

           

            printf("%d\n", *pArr);     //

     

            printf("%d \n", *(++pArr));//

            printf("%d \n", *(++pArr));//

     

            printf("%d \n", *(pArr+1));//

            printf("%d \n", *(pArr+2));//

     

        return 0;

    }


    <궁금하면 실행해보세요▼>

    소스.txt



    출력결과는 어떻게 될까요~?

    .

    .

    두구두구두구두구..

    .

    .

    .

    .

    .

    .

    .

    .

    .

    .

    .

    .

    생각하구 계시죠??

    .

    .

    .

    .

    .

    .

    .

    .

    .

    .

    .

    흠.. 뭘까요??

    .

    .

    .

    .

    .

    .

    .

    .

    안알랴줌ㅋ

    .

    .

    .

    .

    .




    네~ 1,2,3,4,5입니다!! 맞추셨나요??ㅎㅎ


    좀 애매할수가 있습니다.

    그럼 지금부터 해석을 해볼까요~여행

    ① printf("%d\n", *pArr); //*pArr은 배열의 첫번째 요소'arr[0]'를 나타냅니다. 따라서 1,

    ② printf("%d \n", *(++pArr)); //1을 증가(arr[1])시키고 바로 출력 합니다. 따라서 2,

    printf("%d \n", *(++pArr)); // 1을 증가(arr[2])시키고 바로 출력 합니다. 따라서 3,

    printf("%d \n", *(pArr+1)); // 증가되었던 pArr에(arr[3]) 1을 더합니다. 따라서 4,

    printf("%d \n", *(pArr+2)); // 증가되었던 pArr에(arr[3]) 2를 더합니다. 따라서 5.

    ★★★④,⑤번의 경우는 "*(pArr+n)"은 포인터 pArr이 가리키는 곳에서 n칸 건너편에 있는 요소의 값을 참조하라"는 뜻입니다.★★★








     오케이3





    커피한잔그림 보시면 훨씬 쉽게 이해되시겠죠~?아자




     ※주의사항

      배열을 다룰 때 범위를 넘어선 접근을 하지 않도록 주의해야합니다. 포인터 연산을 하다보면, 간혹 선언해 놓은 배열의 범위를 넘어서는 경우가 종종 발생합니다. 이러한 오류는 컴파일과정에서 발견되지 않습니다. 실행과정에서 잘못된 결과만 가져올 뿐입니다.


    (예시)

    arr[3]={10,20,30};

    int * pArr=arr;

    *pArr-4; // 범위초과





    하트3[2]중요한결론! arr[i]==*(arr+i) ::: 배열의 이름을 포인터처럼 사용할 수 있다.


    아까전에는 위에서 "포인터를 배열의 이름처럼 사용할 수 있다."고 했습니다.

    이번에는 역으로 "배열의 이름을 포인터처럼 사용할 수 있다"는 예제를 보여드리겠습니다!


    #include<stdio.h>

     

    int main(void)

    {

            int arr[2]={1, 2};

            int* pArr=arr;

     

            //배열이름을 통한 출력(배열 이름을 포인터처럼 사용)

            printf("%d, %d \n", arr[0], *(arr+1));

                          

     

            //포인터변수를 통한 출력(포인터를  배열이름처럼 사용)

            printf("%d, %d \n", pArr[0], *(pArr+1));

                         

        return 0;

    }



    <실행결과>


    실행결과를 보시면 포인터인 pArr을 사용하지 않고, arr배열만을 통해 포인터처럼 사용된 것을 보실 수 있습니다. 짱신기한듯..!하트3


    ★★★이를 공식화하면?! :   arr[i]==*(arr+i) ★★★


    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★


    ※따라서, i가 3이라면 arr[3]은 *(arr+3)과 같은 의미를 지니게 됩니다. arr이 배열이든 포인터이든 상관이 없습니다. 

    또한 arr배열이 1차원배열이든 2차원배열이든 위의 식은 항상 성립한다는것을 외워두세요!


    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★



    자~ 그럼 여기까지 배운 실력을 테스트해 볼 시간입니다!


    [연습문제13-1-1]

    크기가 5인 int형 배열 arr을 선언하고 1,2,3,4,5로 초기화 한 다음, 포인터 p를 선언해서 배열 arr의 첫 번째 요소를 가리키게 한다. 

    그 다음 포인터 p를 조작(포인터 연산을 의미함)해서 배열 요소의 값을 2씩 증가시킨 후, 전체 배열 요소를 출력하는 프로그램을 작성하자.


    <정답보기(클릭)>


    [연습문제13-1-2]

    1번 문제와 유사하다. int형 배열 arr을 선언하고 1, 2, 3, 4, 5로 초기화한 다음, 포인터 p를 선언해서 배열 arr의 첫 번째 요소를 가리키게 한다.

    그 다음에는 포인터 p를 이용해서 배열 요소의 순서를 바꾼 후, 그 결과를 출력하는 프로그램을 작성하자.


    <정답보기(클릭)>







    [C언어 다른 글 보기]


    반응형

    댓글

Designed by Tistory.