포인터 배열 C - pointeo baeyeol C


배열은 사실 첫 번째 요소의 주솟값만 담고 있습니다.

그림 33‑2 배열과 주솟값
포인터 배열 C - pointeo baeyeol C

즉, 배열은 주솟값이기 때문에 포인터에 넣을 수 있습니다. 따라서 다음과 같이 포인터에 배열을 넣은 뒤 포인터에서 인덱스로 요소에 접근할 수 있습니다.

pointer_to_array.c

#include <stdio.h>

int main()
{
    int numArr[10] = { 11, 22, 33, 44, 55, 66, 77, 88, 99, 110 };    // 크기가 10인 int형 배열

    int *numPtr = numArr;       // 포인터에 int형 배열을 할당

    printf("%d\n", *numPtr);    // 11: 배열의 주소가 들어있는 포인터를 역참조하면 배열의 
                                // 첫 번째 요소에 접근

    printf("%d\n", *numArr);    // 11: 배열 자체를 역참조해도 배열의 첫 번째 요소에 접근

    printf("%d\n", numPtr[5]);  // 66: 배열의 주소가 들어있는 포인터는 인덱스로 접근할 수 있음

    printf("%d\n", sizeof(numArr));    // 40: sizeof로 배열의 크기를 구하면 배열이 메모리에 
                                       // 차지하는 공간이 출력됨

    printf("%d\n", sizeof(numPtr));    // 4 : sizeof로 배열의 주소가 들어있는 포인터의 크기를 
                                       // 구하면 포인터의 크기가 출력됨(64비트라면 8)

    return 0;
}

실행 결과

11
11
66
40
4

int *numPtr = numArr;처럼 배열을 포인터에 바로 할당할 수 있습니다. 단, 자료형이 같아야 하며 1차원 배열이라면 *가 한 개인 단일 포인터라야 합니다.

배열을 포인터에 할당한 뒤 포인터를 역참조해보면 배열의 첫 번째 요소의 값이 나옵니다. 마찬가지로 배열 자체도 역참조해보면 배열의 첫 번째 요소의 값이 나옵니다. 즉, 실제로는 배열도 포인터라 할 수 있습니다.

printf("%d\n", *numPtr);    // 11: 배열의 주소가 들어있는 포인터를 역참조하면 배열의 
                            // 첫 번째 요소에 접근

printf("%d\n", *numArr);    // 11: 배열 자체를 역참조해도 배열의 첫 번째 요소에 접근

배열의 주소가 들어있는 포인터는 인덱스를 통하여 요소에 접근할 수 있습니다.

printf("%d\n", numPtr[5]);    // 66: 배열의 주소가 들어있는 포인터는 인덱스로 접근할 수 있음

배열과 포인터가 다른 점은 sizeof로 크기를 계산했을 때입니다. 배열에 sizeof 연산자를 사용하면 배열이 차지하는 전체 공간이 출력되지만 sizeof로 배열의 주소가 들어있는 포인터의 크기를 구해보면 그냥 포인터의 크기만 나옵니다(32비트라면 4, 64비트라면 8).

printf("%d\n", sizeof(numArr));    // 40: sizeof로 배열의 크기를 구하면 배열이 메모리에 
                                   // 차지하는 공간이 출력됨

printf("%d\n", sizeof(numPtr));    // 4 : sizeof로 배열의 주소가 들어있는 포인터의 크기를 
                                   // 구하면 포인터의 크기가 출력됨(64비트라면 8)


포인터 배열이란?

  • 포인터 들의 배열이다.

  • 배열의 요소가 포인터들로 이루어져 있는 배열

선언 방법

  • char* arr [3];

  • 배열 요소의 자료형이 char* (포인터)인 배열

  • 그 배열의 요소의 개수가 3개 

arr [0], arr [1], arr [2]은 어떤 메모리를 가리키고 있다.

char* arr [3]은 메모리 3곳을 가리키고 있는 배열입니다.  


포인터 배열 예제 

#include <stdio.h>

int main(void){
	const char* arr[3]; //포인터 배열 선언. 
	int i;
	
	arr[0] = "Block";
	arr[1] = "someting";
	arr[2] = "like";
	
	for(i = 0; i < 3; i++)
	{
		printf("arr[%d] -> %s\n", i, arr[i]);
	 } 
	 
	 return 0;
}
포인터 배열 C - pointeo baeyeol C

포인터 배열 예제 2 (동적 할당)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
	char* arr[3];
	char tmp[30]; 
	int len, i;
	
	for(i = 0; i < 3; i++) 
	{
		printf("[%d] : ", i);
		scanf("%s", tmp);
		len = strlen(tmp) + 1;
		printf("[%d] : tmp \t주소 : %p\n", i, &tmp);
		
		arr[i] = (char *)malloc(sizeof(char) * len);
		printf("[%d] : arr[%d]\t주소 : %p\n\n", i, i, &arr[i]);
		
		strcpy(arr[i], tmp);
	}
	
	printf("\n");
	for(i = 0; i < 3; i++)
	{
		printf("arr[%d] : %s\t주소 : %p\n", i, arr[i], &arr[i]);
	}
	
	for(i = 0; i < 3; i++)
	{
		free(arr[i]);
	}
	
	return 0;
}
포인터 배열 C - pointeo baeyeol C

배열 포인터란?

특정 사이즈의 배열만을 가리킬 수 있는 하나의 포인터이다. 

선언 방법

타입 이름 (*변수명)[N]

포인터가 타입 쪽에 붙는 게 아니라 변수 이름 쪽에 소괄호 안에 붙게 됩니다.

ex) char (*arr)[3];

char 타입의 인덱스를 3개 가지고 있는 배열을 가리키는 포인터입니다.

int* pNum; 은 int 타입을 가리키는 것이고, arr은 char타입의 배열 사이즈[3]인 배열을 가리키는 것입니다. 

배열 포인터 예제

#include <stdio.h>

int main(void)
{
	char (*arr)[3];
	int i;
	char tmp1[3] = {'a', 'b', 'c'};
	char tmp2[3] = {'d', 'e', '\0'};
	char tmp3[4] = {'p', 'o', 'q', 'r'};
	
	printf("tmp1[3] 주소 :  %p\n", tmp1);
	printf("tmp2[3] 주소 :  %p\n", tmp2);
	printf("tmp3[3] 주소 :  %p\n", tmp3);
	
	printf("\n");
	printf("\n");
	
	arr = &tmp1; //arr은 tmp1의 주소를 가르킵니다. 
	printf("arr의 주소 : %p\t 문자열 : ", arr);
	for(i = 0; i < (int)sizeof(*arr); i++)
	{
		printf("%c", (*arr)[i]);
	 } 
	
	printf("\n");
	
	arr = &tmp2; //arr은 tmp1의 주소를 가르킵니다. 
	printf("arr의 주소 : %p\t 문자열 : ", arr);
	for(i = 0; i < (int)sizeof(*arr); i++)
	{
		printf("%c", (*arr)[i]);
	 }
	 
	 printf("\n"); 
	 
	 return 0;
 } 
 
 
포인터 배열 C - pointeo baeyeol C

"포인터 배열"은 포인터가 여러 개 모여서 배열로 있는 것이고

"배열 포인터"는 배열 타입을 가리키는 하나의 포인터라는 것입니다.