Post

C 언어 포인터

C언어 포인터 이해하기

◼︎ C언어 포인터

2024년 4월 2일 2024년 4월 12일

C언어 포인터를 알고는 있으나, 정확히 숙지되지 않은 것 같아서 다시 정리 해본다.

C언어 포인터와 배열

배열의 요소에 접근하는 여러 방법들이다.

1
2
3
4
5
6
7
8
char  ary[100];

ary[0]       = 'a'; // 배열의 첫 번째 요소에 'a'를 저장
1[ary]       = 'b'; // 배열의 두 번째 요소에 'b'를 저장
*(ary+2)     = 'c'; // 배열의 세 번째 요소에 'c'를 저장
*(&ary[0]+3) = '\\0'; // 배열의 네 번째 요소에 NULL 문자를 저장

printf( "%s\\n", ary); // 배열에 저장된 문자열을 출력

내가 처음에 이해가 안 되었던 것은

ary[0] , arr, *arr+0, 0[ary] 등 C 언어에서 동일한 값을 표현하는 방식이었다.


C언어 배열 특성

포인터를 이해하려면 변수의 주소부터 이해해야 한다.

주소를 쉽게 설명하면, 컴퓨터는 메모리의 집합체이고, 변수는 특정 메모리에 자리를 잡은 위치이며 그 위치를 주소라고 한다.

인덱스0123
abc\0
&a[0]&a[1]&a[2]&a[3]
주소100101102103

ary를 주소로만 따진다면, 다음과 같이 해석할 수 있다.

  • ary[0]은 첫 번째 요소의 주소 100에 0을 더한 100
  • ary[1]은 두 번째 요소의 주소 100에 1을 더한 101

C언어 포인터 특성

1
2
char ary[] = "abc";
char *ptr = ary;

먼저, char ary[] = "abc"; 라는 배열이 있다고 가정했을 때,

인덱스0123
‘a’‘b’‘c’‘\0’
주소1000100110021003

이렇게 메모리에 저장된다.

여기서 ‘a’, ‘b’, ‘c’, ‘\0’는 ary 배열의 각 원소이고, 1000, 1001, 1002, 1003은 각 원소의 메모리 주소이다.

그 다음으로, char *ptr = ary; 라는 포인터 변수가 있을 때 포인터 *ptr은 무엇을 가리키는가?

포인터 변수값 (가리키는 주소)값(메모리 주소)
ptr1000999

이렇게 메모리에 저장된다.

여기서 ptr는 포인터 변수의 이름이고, 1000은 ptr이 가리키는 주소, 즉 ary 배열의 첫 번째 원소 ‘a’의 주소이다.


포인터가 가리키는 값

처음 오히려 어렵게 생각해서 더 이해가 안 갔는데, 단순히 생각했다.

  • 메모리에서 주소는 숫자이므로, 포인터 변수는 단지 숫자가 들어가는 정수 변수일 뿐이다. 포인터 변수 ptr은, ary라는 배열의 주소값 자체를 저장하고 있는 것 뿐이다.
  • 그렇다면, ptr의 주소(자기 주소)는 999고, ptr이 가리키는 값은 1000인 것이다.
  • 그리고 조금 더 생각해보자면, 포인터 변수 ptr 앞에 * 연산자를 놓으면 ptr 변수가 갖고있는 정수 값의 → 값을 구할 수가 있다.
    • ptr 변수 값은 1000이고, 그 주소의 값을 구하면 ‘b’가된다.

풀어서 설명하자면

  • ptr의 값은 ary[0]의 주소이며, *ptr은 ary[0]의 값이다.
  • ptr+2의 값은 ary[2]의 주소이며, *(ptr+2)는 ary[2]의 값이다.

아직도 포인터를 보면 조금은 생각해야 하지만, 메모리에 어떻게 할당 되는지에 대한 이해가 있으면 조금은 쉽다. 그리고 메모리를 조금 더 공부해보면 좋을 듯 하다.


‘**’ ? 더블 포인터

1
2
3
4
5
6
char* st[] ={1,2,3,4};
char** q;
q = st;

printf("%c", **q);
printf("%c", *(*(q+1)));

더블 포인터는 포인터의 포인터로, 포인터 변수가 가리키는 주소 자체가 또 다른 포인터의 주소인 경우 사용된다. 기본적인 포인터가 변수의 주소를 저장하는 것과 달리, 더블 포인터는 다른 포인터의 주소를 저장한다.

예를 들어, char* st[] ={1,2,3,4}; char** q; q = st;라는 코드에서, qst 배열의 첫 번째 요소인 st[0]의 주소를 가리키는 더블 포인터이다.

따라서 **q를 출력하면 st[0]의 값인 1이 출력된다.


► 추가 포인터 예제

포인터와 문자열 예제로 조금 더 이해해보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main()
{
    char *p = "KOREA"; // 포인터 p 선언, 문자열 KOREA로 초기화
    // p는 전체 문자열  "KOREA"의 시작 주소를 가리키게 됨

    printf("%s\n", p); // p는 KOREA 문자열의 시작 주소를 가리키는 포인터
    printf("%s\n", p + 3);

    printf("%c\n", *p); //%c로 출력한다면 출력 불가
    printf("%c\n", *(p + 3));

    printf("%c\n", *p + 2);
}
// p, *p
// *p는 p가 가리키는 주소에 있는 값
// p가 가리키는 문자열 "KOREA"의 시작 주소이므로, *p는 KOREA의 첫 번째 문자 K를 나타냄

C언어에서 문자열이 어떻게 메모리 저장 되는지?

  • 마지막의 \0 Null 문자.
    • C 언어에서 문자열은 문자의 배열로 표현되며, 문자열의 끝을 나타내기 위해 마지막 문자에 NULL 문자(‘\0’)를 추가한다.
    • 이 NULL 문자는 문자열의 끝을 가리키며, 문자열을 처리하는 함수들이 어디까지가 유효한 문자열인지를 파악할 수 있게한다.
인덱스012345
‘K’‘O’‘R’‘E’‘A’‘\0’
주소100010011002100310041005
  1. printf("%s\\n", p)는 p가 가리키는 문자열, 즉 “KOREA”를 출력한다.
  2. printf("%s\\n", p + 3)는 p가 가리키는 주소에서 3을 더한 위치에 있는 문자열을 출력한다. C 언어에서 문자는 1바이트를 차지하므로 p + 3은 문자열 “KOREA”의 네 번째 문자 ‘E’를 가리킨다. 따라서 “EA”가 출력된다.
  3. printf("%c\\n", *p)는 p가 가리키는 주소에 있는 문자를 출력한다. 여기서 p는 “KOREA”의 시작 주소를 가리키므로 ‘K’가 출력된다.
  4. printf("%c\\n", *(p + 3))는 p가 가리키는 주소에서 3을 더한 위치에 있는 문자를 출력한다. 이는 “KOREA”의 네 번째 문자인 ‘E’를 출력한다.
  5. 마지막으로 printf("%c\\n", *p + 2)는 p가 가리키는 문자에 2를 더한 문자를 출력한다. ‘K’의 ASCII 값은 75이므로 2를 더하면 77이 되며, 이는 ASCII에서 ‘M’을 나타낸다. 따라서 ‘M’이 출력된다.

This post is licensed under CC BY 4.0 by the author.