C 프로그래밍 · 2 min read · Nov 20, 2025

리눅스 C 프로그래밍 튜토리얼 21부: 문자 포인터, 포인터 배열 및 포인터의 포인터

포인터의 개념은 C 프로그래밍 언어에서 매우 중요한 개념 중 하나입니다. 지금까지 우리는 C에서 포인터의 여러 측면에 대해 논의했습니다. 이를 확장하여 이번 튜토리얼에서는 몇 가지 더 포인터 개념에 대해 논의할 것입니다.

C에서의 문자 포인터, 포인터 배열 및 포인터의 포인터

다음 코드 줄을 사용하여 문자 포인터부터 시작하겠습니다:

char p[] = "I like HowtoForge"  
char *p = "I like HowToForge"

첫 번째 줄은 큰따옴표 안의 문자 수와 같은 크기의 배열 ‘p’를 정의합니다. 그러나 다음 줄은 문자열 상수를 가리키는 포인터 ‘p’를 정의합니다.

여기서의 차이점은 첫 번째 ‘p’가 배열이기 때문에 배열의 내용을 쉽게 수정하거나 변경할 수 있다는 것입니다. 그러나 두 번째 ‘p’는 문자열 상수를 가리키고 있으므로 문자열 내용을 변경할 수 없습니다.

예를 들어, 다음 코드는 문자열 상수를 수정하려고 시도합니다:

#include   

int main()  
{  
   char *p = "I like HowToForge";  
   
   p[0] = 'U';  
   
   return 0;  
}

그리고 이 코드가 내 시스템에서 생성한 출력은 다음과 같습니다:

Segmentation fault

이 오류는 프로그램 실행이 갑자기 종료되었음을 나타내며, 이는 우리가 상수인 것을 변경하려고 시도했기 때문입니다.

또한 포인터 ‘p’가 다른 문자열을 가리키도록 만들 수 있지만, 배열 ‘p’의 기본 주소는 변경할 수 없다는 점을 기억하세요(이 점은 이전 튜토리얼 중 하나에서 이미 논의한 바 있습니다).

이제 포인터 배열로 넘어가겠습니다. 정수, 문자 및 기타 유형의 배열을 본 것처럼 포인터 배열도 있을 수 있습니다. 예를 들어, 다음 프로그램은 정수 포인터의 배열 ‘arr’를 정의하고 여기에 값을 할당합니다.

#include   

int main()  
{  
 int *arr[3];  
 int a = 0, b = 1, c = 2;  
   
 arr[0] = &a;  
 arr[1] = &b;  
 arr[2] = &c;  
  
 return 0;  
}

배열에 할당된 값은 주소라는 점에 유의하세요. 이는 ‘arr’이 포인터의 배열이기 때문이며, 포인터는 주소 외에는 아무것도 저장하지 않습니다. 이제 이러한 주소에 저장된 값을 액세스하려면 * 연산자를 사용해야 합니다.

다음 예제(이전 예제의 확장에 불과함)는 이를 보여줍니다:

#include   

int main()  
{  
   int *arr[3];  
   int a = 0, b = 1, c = 2;  
   
   arr[0] = &a;  
   arr[1] = &b;  
   arr[2] = &c;  
   
   for(int i=0; i < 3; i++)  
      printf("\n arr[%d] is: %d",i,*(arr[i]));  
  
 return 0;  
}

출력은 다음과 같습니다:

arr[0] is: 0   
arr[1] is: 1   
arr[2] is: 2 

정수 포인터 배열(여기서 논의한 것과 같은)과 유사하게, 문자 포인터 및 기타를 저장하는 배열도 가질 수 있습니다.

이제 포인터의 포인터로 넘어가겠습니다. 지금까지 여러 번 반복했듯이, 포인터는 주소를 저장합니다. 지금까지 진행된 C 프로그래밍 튜토리얼 시리즈에서는 포인터가 비포인터 변수를 가리키는 것만 보았지만, 사실 포인터는 다른 포인터를 가리킬 수도 있습니다.

즉, 포인터는 다른 포인터의 주소를 저장할 수 있습니다. 예를 들어, 다음은 이중 포인터 또는 포인터의 포인터입니다:

int **ptr;

다음은 이중 포인터를 활용한 코드입니다:

#include   

int main()  
{  
   int *ptr;  
   int p;  
   
   int a = 10;  
   
   ptr = &a;  
   
   p = &ptr;  
   
   printf("\n Pointer 'p' points to pointer 'ptr' which further points to value: %d", p);  
   
   return 0;  
}

출력은 다음과 같습니다:

Pointer 'p' points to pointer 'ptr' which further points to value: 10

이것이 이중 포인터의 예입니다. 유사한 방식으로 포인터의 포인터의 포인터를 가질 수 있으며, 예를 들어 int *ptr로 정의됩니다. 이러한 ‘포인터의 포인터의 포인터……’ 수준의 최대 수는 구현에 따라 다릅니다(경우에 따라 제한이 12인 경우도 있습니다).

실제로는 포인터의 포인터는 최대 3단계까지 만나는 경우가 많으며, 더 많은 단계가 있으면 논리가 이해하고 유지하기 더 복잡해집니다.

결론

우리는 여기에서 세 가지 중요한 포인터 관련 개념을 논의했습니다. 여기서 논의한 예제와 개념을 시스템에서 시도하여 이러한 것들이 어떻게 작동하는지에 대한 더 나은 아이디어를 얻는 것이 좋습니다. 의문이나 질문이 있는 경우 아래에 댓글을 남겨주세요.

Share: X/Twitter LinkedIn

새 게시물을 받은 편지함에서 받기

스팸은 없습니다. 언제든지 구독 해지 가능합니다.