011. POINTERS & ARRAYS

Posted on by pkchan

011-01 // ONE DIMENSIONAL ARRAY

배열의 선언과 배열이 저장된 메모리에 할당되는 주소를 공부했습니다.

배열 a의 각각 원소에는 주소가 있고 배열 a의 원소는 각각 4bytes의 공간을 차지하고 있습니다. 배열의 전체 크기는 12bytes가 되겠네요. 그러면 배열의 이름인 a은 무엇을 가지고 있을까요? 전체 배열이 시작되는 주소를 가지고 있으며 동시에 첫번째 배열 원소의 주소를 가지고 있습니다.

arr 의 주소는 100 // 배열의 첫번째 원소의 주소
&arr 의 주소는 100 // 배열 전체의 시작 주소

배열의 이름은 그 자체가 포인터입니다. 그러나 포인터 변수를 선언하고 사용하는 것과는 조금 다릅니다. 포인터는 변수이므로 다른 주소를 다시 저장할 수 있지만 배열의 이름은 상수이므로 주소를 바꾸는 것은 불가능합니다.

/*
 example 011-01
 C language pointers & arrays
*/

#include <stdio.h>

int main(void){
          
          int arr[5] = {1,2,3,4,5};
          
          int* parr = arr; // 첫 번째 원소를 가리키는 포인터
          int (*parr2)[5] = &arr; // 배열 전체를 가리키는 포인터
          
          printf("arr address is %d\n",arr);
          printf("arr+1 address is %d\n",arr+1);
          printf("arr[1] is %d\n\n",arr[1]);
          
          printf("parr address is %d\n",parr);
          printf("parr+1 address is %d\n",parr+1);
          printf("parr[1] is %d\n",parr[1]);
          printf("*(parr+1) is %d\n\n",*(parr+1));
          
          printf("parr2 address is %d\n",parr2);
          printf("parr2+1 address is %d\n",parr2+1);
          printf("(*parr2)[1] is %d\n",(*parr2)[1]);
          printf("*(*parr2+1) is %d\n\n",*(*parr2+1));
          
          return 0;
          
}

예제와 같이 포인터 변수에 배열의 주소를 대입하는 방법은 두가지가 있습니다. 배열의 첫 번째 원소를 가리키게 하는 방법과 일차원 배열 전체를 가리키게 하는 방법입니다.

첫 번째 원소를 가리키는 포인터
선언 및 대입 : int* parr = arr;
참조하는 공간의 크기 : 4bytes
원소값을 참조할때 : parr[1]
원소값을 참조할때 : *(parr+1)

배열 전체를 가리키는 포인터 // 배열 포인터
선언 및 대입 : int (*parr2)[5] = &arr;
참조하는 공간의 크기 : 20bytes ( 4bytes * int 원소 5개 )
원소값을 참조할때 : (*parr2)[1]
원소값을 참조할때 : *((*parr2)+1)

포인터 변수에 덧셈 혹은 뺄셈을 하면 포인터 변수가 가리키는 자료형의 데이터 크기를 곱해서 연산합니다. 포인터 + (정수 * sizeof(자료형)) 이 되겠네요. 자료형이 int인 arr에 +2를 해주면 arr + (2 * sizeof(int))가 됩니다. 첫 번째 원소의 주소를 가진 arr이 가진 주소에 8이 더해지며 3번째 원소를 가리킵니다. arr[2]는 *(arr+2)와 같습니다. [ ] 연산자는 a[b] 일때 a와 b를 더해서 값을 참조하는 연산자입니다.

arr[2] == *(arr+2) == *(2+arr) == 2[arr]

배열의 이런 특징들을 조합하면 많은 응용이 가능해집니다. 포인터에 정수를 더하거나 뺄 수 있다면, 포인터끼리의 연산도 가능할까요? 곱하고 나누고 더하는 것은 불가능하지만 빼기는 거리를 구할 수 있으므로 가능합니다.

/*
 example 011-02
 C language pointers & arrays
*/

#include <stdio.h>

void enter_number(int *arr);

int main(void) {
          
          int classes[6],sum = 0;
          int* pc = classes;
          
          enter_number(classes);

          while( pc - classes < 6 ) {
                    
                    sum += *pc;
                    pc++;
            
          // 배열 이름은 주소를 가진 포인터이지만 값을 바꿀 수 없는 상수이기 때문에 classes++는 불가능합니다.          
                    
          }
          
          printf("Sum = %d\n", sum);
          printf("Avg = %f\n", sum/6.0);
          
          return 0;
          
}

void enter_number(int* arr){
          
          for(int i=0; i < 6; ++i) {
                    
                    printf("Enter number : ");
                    scanf("%d",(arr + i));
                    
          }
          
}

011-02 // TWO DIMENSIONAL ARRAY

1차원 배열이 변수의 모임이라면 2차원 배열은 1차원 배열의 모임입니다.
1차원 배열의 모임이라면 배열 이름이 가리키는 첫번째 원소는 1차원 배열인 첫번째 행이 됩니다. 1차원배열에서 배운 배열포인터를 사용하면 됩니다.

int (*p)[3] = arr;

배열 이름 arr은 첫번째 행의 시작주소를 가지고 첫번째 행 전체를 가리키고 있습니다. arr + 1 을 하면 두번쨰 행을 가리키겠네요. *을 사용하여 간접 참조를 하면 두번째 행의 보조 배열 이름이됩니다.

*(arr + 1) == arr[1]

2차원 배열에서 보조 배열이름은 각 행을 일차원 배열로 본다면 일차원 배열의 배열 이름과 같습니다.

*(*(arr + 1) + 2) == arr[1][2] == 60

정리해보면,

선언 및 대입 :int (*p)[3] = arr;
참조하는 공간의 크기 : 12bytes (low)
원소값을 참조할때 : p[1][2]
원소값을 참조할때 : *(*(p + 1) + 2)

/*
 example 011-03
 C language pointers & arrays
*/

#include <stdio.h>

void m_arr(int(* ma)[5]);

int main() {
          
          int ma[5][5];
          
          m_arr(ma);
          
          printf("ma : %d\n",ma);
          printf("ma+1 : %d\n",ma+1);
          printf("&ma+1 : %d\n\n",&ma+1);
          
          printf("ma[0] : %d\n",ma[0]);
          printf("ma[0]+1 : %d\n",ma[0]+1);
          printf("&ma[0]+1 : %d\n\n",&ma[0]+1);
          
          printf("ma[2][2] : %d\n",ma[2][2]);
          printf("*(*(ma+1)+2) : %d\n",*(*(ma+1)+2));
          printf("(*(ma+1))[3] : %d\n\n",(*(ma+1))[3]);

          return 0;
          
}

void m_arr(int(* pointer)[5]){
          
          int a = 2;
          
          for(int i=0;i<5;i++){
                    
                    for(int j=0;j<5;j++){
                              
                              pointer[i][j] = a;
                              a += 2;
                              
                    }
                    
          }
          
          printf("\n\nma[5][5] 배열의 주소와 값을 출력합니다.\n\n");
          
          for(int i=0;i<5;i++){
                    
                    for(int j=0;j<5;j++){
                              
                              printf("%d : %-5d",&pointer[i][j],pointer[i][j]);
                              
                    }
                    printf("\n");
                    
          }
          
          printf("\n");
          return;
          
}

011-03 // POINTER ARRAY

포인터 배열은 포인터 변수들을 원소로 가지는 배열입니다.

/*
 example 011-04
 C language pointers & arrays
*/

#include <stdio.h>

int main() {
          
          int a = 10, b = 20, c = 30;
          int *arr[3] = {&a, &b, &c};
          
          for(int i=0;i<3;i++){
                    
                    printf("%d번째 원소는 %d입니다.\n",i+1,*arr[i]);
                    
          }

          return 0;
          
}

1차원 배열을 가리키는 포인터의 배열을 만들어 2차원 배열처럼 사용할 수 있습니다. 이 경우 함수의 인자로 넘길때는 이중포인터를 사용해야합니다.

/*
 example 011-05
 C language pointers & arrays
*/

#include <stdio.h>

void view(void);

int main() {
          
          int array_one[3] = {31,4,67};
          int array_two[3] = {54,42,90};
          int array_three[3] = {65,23,37};

          int* pointer[3] = {array_one,array_two,array_three};
          
          view(pointer);
          
          return 0;
          
}

void view(int** po){
          
          for(int i=0;i<3;i++){
                    
                    for(int j=0;j<3;j++){
                              
                              printf("%5d",po[i][j]);
                              
                    }
                    
                    printf("\n");
                    
          }
          
}

REVIEW EXERCISES

1. 1~10까지의 정수를 5개이상 입력받는 함수와 chart를 만드는 함수를 제작하여 출력하세요.

                                                  *
                                                  *  *
                                                  *  *
                    *                      *  *
          *  *                      *  *
*  *  *  *            *  *  *
*  *  *  *  *  *  *  *
*  *  *  *  *  *  *  *
3  4  5  3  2  8  7  3

One Reply to “011. POINTERS & ARRAYS”

    #include <stdio.h>
    
    void en_num(int (*p)[3],int* sum);
    void pt_num(int (*p)[3],int* sum);
    
    int main (){
    	
    	int arr[3][3];
    	int sum = 0;
    		
    	en_num(arr,&sum);
    	pt_num(arr,&sum);
    	
    	return 0;
    	
    }
    
    void en_num(int (*p)[3],int* sum){
              int i,j;
              for(i=0;i<3;i++)
    		for(j=0;j<3;j++){
    			printf("enter number : ");
    			scanf("%d",&(*(*(p+i)+j)));
    			*sum += *(*(p+i)+j);
    		}
    }
    
    void pt_num(int (*p)[3],int* sum){
    	int i,j;
    	for(i=0;i<3;i++){
    		for(j=0;j<3;j++){
    			printf("%d ",*(*(p+i)+j));
    		}
    		printf("\n");
    	}
    	printf("sum = %d, avg = %.2f",*sum,*sum/9.0);
    }

Leave a Reply