본문으로 바로가기

C언어_(상수,변수)포인터의 이해

category 개발자/C 언어 2015. 4. 17. 16:33

- (상수,변수) 포인터 기본형 준비 -


#include <stdio.h>  //다차원 배열과 포인터의 관계, 상수포인터와 변수포인터란?

int main(void)    // 다시 정리하자면 값< *(A+1) , A[1] >에 &붙이면 주소로 쓰이고 주소< A+1 , &A[1] >에서 *만 붙이면 다 값으로 쓸 수 있다.
{
  int A[5= {12345};  // 배열도 포인터
  int B[5= {12345};
  int* p1 = A;  //포인터도 배열처럼 쓸 수 있다.
  intconst p2 = B;  // const를 사용함으로써 p2는 주소값을 지니는 상수가 되었다.
  int constconst p3 = B;  //*이 안변합니다. 라는 소리 즉 도착하는 목적지를 변경할 수 없다. 라는 소리가 된다. *(p2 + 2) = 1000; 이것이 성립이 안 된다 라는 뜻이다.
          //즉, 정리 하자면 도착한 주소 값을 수정할 수 없다, 도착한 주소의 메모리 값을 수정할 수 없다. 
  *(A+2= 100;  //A[2] = 100

  printf("배열 A의 A[2]의 값은? : %d\n",A[2]);
  printf("포인터 p의 p1[2]의 값은? : %d\n\n",p1[2]);

  p1 = B;    //가르키는 곳을 바꿀 수 있다 라는 예를 보여주고자 선언했다.

  printf("포인터 p의 p1[2]의 값은? : %d\n\n",p1[2]);  // 가르키는 곳을 바꿨기에 거기있는 값을 출력한다. 값 : 3

  //A = 100;  (주소)상수 = (정수형)상수, 컴파일이 안된다. 배열의 타입은 int[] 이다. 포인터의 타입은 int*  , 사용방법은 같지만 가르키고 안되고의 차이가 있다.
  
  //B = A;  (주소)상수 = (주소)상수, 배열에서 배열로 복사를 하려면 하나하나 for문으로 집어넣는 방법과 위에서 초기화할때 직접 집어넣는 방법. 또는 구조체를 선언 후 대입 시키는 방법.

  //p2 = A;  (주소)상수 = (주소)상수, l-value 는 대입 할 수 없다라는 에러이다. const p2 하면 p2가 상수입니다. 라는 뜻이다. 즉, 이제 p2를 변수가 아닌 상수로 사용하겠다라는 뜻이니까 변경을 불가능하게끔 하는 작업인 것이다. const 사용 방법

  *(p2 + 2= 1000;  //const를 했어도 그 주소에 있는 값을 따라갔을 시 값은 수정이 가능 하다. 즉, 지금 막아놓은 것은 가르키는 포인터 이다.

  printf("배열 A의 B[2]의 값은? : %d\n",B[2]);
  printf("배열 A의 p[2]의 값은? : %d\n\n",p2[2]);

  printf("배열 A의 p[2]의 값은? : %d\n\n",p3[2]);

  //*(p3 + 2) = 10000;  현재 p3를 상수화 시키고 *까지 상수화를 시켰기 때문에 이것은 대입 할 수 없다라는 뜻인 l-value 에러가 뜬다.

  return 0;
}

/*
배열 A는 이름 자체가 주소기에 바뀔 수 없는 상수 이다. < (상수)주소[0] > --> 이름 자체를 뭐 어찌 할 수가 없다(상수) 라는 뜻이다.
포인터 p는 주소값이 바뀔 수 있는 변수 이다. < (변수)주소[0] >    --> 이름 자체를 다른 곳을 가르키도록 바꿀 수(변수) 있다.
사용면에서는 포인터나 배열은 같지만 차이점은 배열은 가르킬 수 없고 포인터는 가르킬 수 있다라는 것이다.
*/




- 다차원 배열의 심화 이해 -

#include <stdio.h>

int main(void)
{
  int A[2][3= 
  {
    {123},
    {456}
  };//배열의 저장을 이미지화, 실제로 메모리에는 이렇게 저장이 안되어 있다.    
  int iCnt1;
  int iCnt2;

  for(iCnt1 = 0; iCnt1 < 2; ++iCnt1)  //메모리 값 출력
  {
    for(iCnt2 = 0; iCnt2 < 3; ++iCnt2)
    {
      printf("[%d]",A[iCnt1][iCnt2]);
    }

    putchar('\n');
  }

  for(iCnt1 = 0; iCnt1 < 2; ++iCnt1)  //주소 값 출력, 4바이트씩 변한다. 3열까지 하고 나면 그 다음줄 1행에 오게되면 12바이트 차이가 나는 것이다.
  {
    for(iCnt2 = 0; iCnt2 < 3; ++iCnt2)
    {
      printf("[%08X]",&A[iCnt1][iCnt2]);
    }

    putchar('\n');
  }

  printf("[%d]\n",A[0][0]);  //1  
  printf("[%d]\n",*(A[0]+0));  //1
  printf("[%d]\n\n",*(*(A+0)+0));  //1 출력. 2차원 배열을 1차원 배열처럼 점차 분해해 가는 과정. 

  printf("[%d]\n",*(A[0]));  
  printf("[%d]\n",*A[0]);
  printf("[%d]\n",*(*(A+0)));
  printf("[%d]\n",*(*A));
  printf("[%d]\n\n",**A);    //0,0 일 때만 이렇다. 다 1 값 출력. 논리적으로 풀어쓴 과정이다.

  printf("[%d]\n",A[1][2]);  //2차원 배열의 끝 값인 6을 출력하는 3가지 방법이다. 논리적으로 풀어 써보면
  printf("[%d]\n",*(A[1]+2));  //*을 빼면 주소 값이 십진수로 출력된다.
  printf("[%d]\n",*(*(A+1)+2));  //

  return 0;
}
/*
KEY WORD : 차원에 갯수만큼 대괄호가 없으면 주소가 된다.
2차원 배열에서의..
[][]  ->  값
[]    -> 주소 (값을 출력하려면 *[]  ==  값, 즉 *이 []를 대신 한다. []가 하나 없어지면 *이 하나 있어야 []를 대신하여 값을 출력시키는 것이다.)
      -> 주소 ( 값으로 표현하려면 * 2 개 필요)

1차원 배열에서의..
[]    ->  값
      -> 주소 (값을 출력하려면 *이 붙어야 된다. 여기서 유추할 수 있는건 *의 갯수로 몇차원의 배열인지 알 수 있다.)

이제 이것으로 말미암아

3차원 배열에서의..
[][][]->  값
[][]  -> 주소 ( 값으로 표현하려면 * 1 개 필요)
[]    -> 주소 ( 값으로 표현하려면 * 2 개 필요)
      -> 주소 ( 값으로 표현하려면 * 3 개 필요)

내일은 교환법칙에 대해 알아 볼 것이다.
*/