C언어 공부

C언어 포인터 다시 공부

Bordercolli 2023. 7. 17. 09:58
728x90

포인터 개념

// 실행할떄마다 주소가 변경됨

// 영희네와 민수네 주소를 잘 알아냈다.

// 포인터 변수는 int/ char/ double 상관없이 주소값을 알고 있는 변수에 찾아가서 값도 직접 바꿀 수 있고 메모리 공간의 주소도 알아낼 수 있다.

이를 통해서 포인터 변수라는 것은 포인터 즉, 어떤 변수의 주소값을 가지는 포인터 자체가 그 변수의 값을 직접 바꿀 수 있다. 라고 알 수 있다.

 

그렇다면 미션맨의 주소는?

별로 멀리살지 않는다

 

포인터와 배열

#include <stdio.h>

int main(void)
{
    int arr[3]={5, 10, 15};
    int *ptr=arr;
    for(int i=0; i<3; i++)
    {
        printf("배열 arr[%d]의 값: %d\n", i, arr[i]);
    }
    for(int i=0;i<3; i++)
    {
        printf("포인터 ptr[%d]의 값: %d\n", i, ptr[i]);
    }

return 0;


}

난 이거 결과를 포인터의 값 아래 3개는 주소가 나올 거라고 예상했는데...웬 걸...?

왜 값이 똑같이 나오지...?

포인터라는 녀석은 배열이 가리키고 있는 이 값들, 즉 배열 하나하나의 주소 값을 그대로 가지고 있는 것이다.

똑같이 접속을 해서 값을 가지고 온 것이다.

 

#include <stdio.h>

int main(void)
{
    int arr[3]={5, 10, 15};
    int *ptr=arr;
    for(int i=0; i<3; i++)
    {
        printf("배열 arr[%d]의 값: %d\n", i, arr[i]);
    }
    for(int i=0;i<3; i++)
    {
        printf("포인터 ptr[%d]의 값: %d\n", i, ptr[i]);
    }
   
    ptr[0]=100;
    ptr[1]=200;
    ptr[2]=300;
    for(int i=0;i<3; i++)
    {
        printf("포인터 ptr[%d]의 값: %d\n", i, ptr[i]);
    }
     for(int i=0; i<3; i++)
    {
        printf("배열 arr[%d]의 값: %d\n", i, arr[i]);
    }
return 0; }

결과 포인터 자체 값과 배열 자체 값 또한 바뀌었다.

그렇다는 것은 포인터라는 녀석이 각각 배열 요소에 그대로 가서 값을 바꾸고 있었다.

즉, 이는 ptr과 arr이 똑같은 녀석이라고 볼 수 있다.

printf("배열 arr[%d]의 값: %d\n", i, *(arr+i));
printf("배열 ptr[%d]의 값: %d\n", i, *(ptr+i)");

이렇게 표현하면 arr이라는 것 자체는 arr배열이 처음 시작되는 주소 값을 가지고 있다. 그 주소로부터 i번쨰 해당하는 녀석의 값을 가져오는 것이라서 이렇게 사용할 수 있다. 그리고 지금 작성된 이 문법은 

printf("배열 arr[%d]의 값: %d\n", i, arr[i]);
printf("배열 ptr[%d]의 값: %d\n", i, ptr[i]);

이 문법과 완전이 똑같은 개념이다.

이런 결과가 나오게 된다.

즉!!
*(arr+i) == arr[i] 와 똑같은 표현

arr은 arr배열의 첫 번쨰 값의 주소와 동일하다.

즉 "arr == arr[0]"

#include <stdio.h>

int main(void)
{
    int arr[3]={5, 10, 15};
    int *ptr=arr;


printf("arr 자체의 값: %d\n",arr);
printf("arr 자체의 값: %d\n", &arr[0]);
return 0;}

 

?????????

arr변수명을 치면 5가 나올 줄 알았는데....

주소값이 나왔다.

 

#include <stdio.h>

int main(void)
{
    int arr[3]={5, 10, 15};
    /* int *ptr=arr; */


printf("arr 자체의 값: %d\n",arr);
//printf("arr 자체의 값: %d\n", &arr[0]);
return 0;}

이래도 

그냥 arr이라고 하면 주소 자체를 나타내는 것이라고 명심해야 한다.

arr[숫자]                    => 값이 나옴

arr==&arr[숫자]         => 주소가 나옴

 

포인터가 arr이라는 자체 값을 가지면 첫번쨰 주소의 값을 가지는 것

 

int main(void)
{
    int arr[3]={5, 10, 15};
    printf("arr 자체의 값이 가지는 주소의 실제 값: %d\n", *arr);
    return 0;
}

이러면 값이 

5가 나온다 

arr라는 이 자체 값을 주소를 가진다. 그 주소가 가지고 있는 실제 값을 찍어보는 것이다.

그래서 앞에 *을 붙였다. 

즉 arr==주소, *arr==값

 

printf("arr[0]의 실제 값: %d\n", *arr[0]);

이러면 오류가 발생한다.

수정하자.

#include <stdio.h>

int main(void)
{
    int arr[3]={5, 10, 15};
    printf("arr 자체의 값이 가지는 주소의 실제 값: %d\n", *arr);  // *(arr+0)과 같은 의미
    printf("arr[0]의 실제 값: %d\n", *&arr[0]);   // 

    return 0;
}

이러면 

 

이러한 결과가 나온다.

*&가 같이 있다는 의미는 앰퍼센트부터 해석해보자면, 이 변수의 주소의 값을 나타내는 것이라서 둘이 있으면아무것도 없는 것과 같다.

&는 주소이며, *는 그 주소의 값을 의미하는 것이라서 *&이렇게 붙어 있으면 상쇄가 된다.

 

#include <stdio.h>

int main(void)
{
   int i=0;

   printf("%d\n", &i);
   printf("%d\n", *&i);
   return 0;
}

배열처럼 일반변수도 마찬가지 결과

 

SWAP

#include <stdio.h>

void swap(int a, int b);

int main(void)
{
   int a=10;
   int b=20;
   // a와 b의 값을 바꾼다.
   printf("swqp함수 전에는 -> a: %d, b: %d\n", a, b);
   swap(a,b);
   printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
   
   return 0;

}


void swap(int a, int b)
{  
    int temp=a;
    a=b;
    b=temp;

}

이미 배웟던 거지만..함수에서만 원하는 결과가 호출될 수 있다.

void swap(int a, int b)
{  
    int temp=a;
    a=b;
    b=temp;
    printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);

}
 

대학교 다닐떄 이거 정말 이해하기 어려웠는데 머리가 크고 생각해보면

 

이런 구조

 

우리가 이를 값의 의한 복사라고 하는데(Call by value) 

 

main함수 안에  a의 주소와 b의 주소를 확인해보자.

#include <stdio.h>

void swap(int a, int b);

int main(void)
{
   int a=10;
   int b=20;
   // a와 b의 값을 바꾼다.


    printf("a의 주소 값: %d\n",&a);
    printf("b의 주소 값: %d\n",&b);
    //printf("swqp함수 전에는 -> a: %d, b: %d\n", a, b);
    swap(a,b);
    //printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
       
   return 0;

}


void swap(int a, int b)
{  
    int temp=a;
    a=b;
    b=temp;
    //printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
    printf("(swap함수 내)a의 주소 값: %d\n",&a);
    printf("(swap함수 내)b의 주소 값: %d\n",&b);
    printf("(swap함수 내)temp의 주소 값: %d\n", &temp);}

결과가 의외였다.

난 함수를 호출해도 그 이전과 같은 주소 값이 나올 줄 알았는데, 함수 내부의 a, b는 서로 다른 값이었다.

그렇다면 메모리 공간에 있는 주소값을 넘기게 되면 어떻게 될까???

#include <stdio.h>

void swap(int a, int b);
void swap_addr(int *a, int *b);

int main(void)
{
   int a=10;
   int b=20;
   // a와 b의 값을 바꾼다.


    printf("a의 주소 값: %d\n",&a);
    printf("b의 주소 값: %d\n",&b);
    printf("swqp함수 전에는 -> a: %d, b: %d\n", a, b);
    swap(a,b);
    printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
       

    printf("a의 주소 값: %d\n",&a);
    printf("b의 주소 값: %d\n",&b);
    printf("swqp함수 전에는 -> a: %d, b: %d\n", a, b);
    swap_addr(&a,&b);  //주소를 넘기는 거니까 a의 &를 붙여서 넘기고, 주소는 포인터변수를 선언
    printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
       
   return 0;

}


void swap(int a, int b)
{  
    int temp=a;
    a=b;
    b=temp;
    printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
    printf("(swap함수 내)a의 주소 값: %d\n",&a);
    printf("(swap함수 내)b의 주소 값: %d\n",&b);
    printf("(swap함수 내)temp의 주소 값: %d\n", &temp);
    }


void swap_addr(int *a, int *b)   //*a로 해서 주소값을 넘긴다.
{  
    int temp=*a;   //a는 주소 값을 가지는 거니까 실제 값인 *을 붙여서 집어넣고
    *a=*b;  //a의 값에도 b의 값을 집어넣도록
    *b=temp;   //b의 값에도 temp를 집어넣도록 처리한다.
    printf("swap함수 후에는 -> a: %d, b: %d\n", a, b);
    printf("(주소값 전달)SWAP함수 내 -> a:%d, b:%d\n", *a, *b);

    }

일일이 다 적어놓았으니 코드는 다시 리뷰하고 설명해보자면

주소값을 전달하기 전에는 a는 10, b는 20이었는데, 주소 값 전달하고 나서 a는 20, b는 10으로 변경되었다.

주소 값을 전달해서 그들이 가진 값을 바꾼 것

 

 

'C언어 공부' 카테고리의 다른 글

구조체  (0) 2023.07.24
다차원배열  (0) 2023.07.24
다차원 배열  (0) 2023.07.21
포인터2  (0) 2023.07.18
VSCode에서 c언어 시작하기1  (0) 2023.07.17