본문 바로가기

Programming/C

C언어 포인터와 배열(C언어 pointer and array)

반응형

1편 2020/10/17 - [Programming/C] - C언어 포인터 기본(C언어 basic pointer)

2편 2020/10/17 - [Programming/C] - C언어 포인터 활용(C언어 use of pointer) feat. swap함수



1편에서 했던 포인터 타입들의 크기가 모두 동일한데 여러개의 포인터 타입이 존재하는 이유가 무엇인지 살펴보았다.

(포인터 타입의 크기는 32bit machine에서는 4byte, 64 bit machine에서는 8byte이다)


결론을 다시 말하자면, 온전한 데이터를 읽으려면 지정된 주소부터 몇 byte를 

읽어야 하는지 알려주기 위해서 포인터 타입이 존재한다 했다.


1
2
3
int b = 0xffffffff
int *pointerB = &b;
 
cs


위 코드를 그림으로 그려보면, pointerB를 통해 b에 있는 값을 읽기 위해서는

시작주소 &b(0x1500) 부터 4byte를 읽어야 온전한 b의 값을 읽을 수 있다.



아래 코드는 포인터타입의 특징을 확인할 수 있는 또 다른 코드다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
        int a;
        short b;
        double c;
 
        int *intPointer = &a;
        short *shortPointer = &b;
        double *doublePointer = &c;
 
        printf("int type size : %d,\
                 short type size : %d,\
                 double type size : %d\n",\
                 sizeof(int), sizeof(short), sizeof(double));
 
        printf("&a : %x, &b : %x, &c : %x \n"&a, &b, &c);
        printf("intPointer : %x, shortPointer : %x, doublePointer : %x\n",\
                                 intPointer, shortPointer, doublePointer);
        printf("intPointer+1 : %x, shortPointer+1 : %x, doublePointer+1 : %x\n",\
                                 intPointer + 1, shortPointer + 1, doublePointer + 1);
        printf("intPointer+2 : %x, shortPointer+2 : %x, doublePointer+2 : %x\n",\
                                 intPointer + 2, shortPointer + 2, doublePointer + 2);
 
        return 0;
}
 
cs

위 코드를 실행한 결과 다음과 같이 출력된다.

그림으로 그려보면, 

(int *) 타입의 포인터 pointerInt 는  *pointerInt로 

가리키는 공간의 데이터를 읽어보면 시작주소로 부터 4byte를,


(short *) 타입의 포인터 pointerShort 는  *pointerShort로 

가리키는 공간의 데이터를 읽어보면 시작주소로 부터 2byte를,


(double *) 타입의 포인터 pointerDouble는  *pointerDouble로 

가리키는 공간의 데이터를 읽어보면 시작주소로 부터 8byte를


읽게 된다. 



여기까지는 1편에서 다루었던 내용이며, 

우리가 오늘 보려하는 부분은 각 타입의 포인터변수에 + @ 를 해주는 부분이다.

결과를 다시 정리해서 보자면

변수명결과비고
(int *) 포인터intPointer0xe5cf1aa8base1
intPointer + 10xe5cf1aacbase1로부터 4가 증가했다
intPointer + 20xe5cf1ab0base1로부터 8이 증가했다
(short *) 포인터shortPointer0xe5cf1aa6base2
shortPointer + 10xe5cf1aa8base2로부터 2가 증가했다
shortPointer + 20xe5cf1aaabase2로부터 4가 증가했다
(double *)포인터doublePointer0xe5cf1a98base3
doublePointer + 10xe5cf1aa0base3으로부터 8이 증가했다
doublePointer + 20xe5cf1aa8base3으로부터 16이 증가했다

포인터변수와 + 연산을 진행하면, 

자료형의 크기를 곱한 만큼 증가 한다.



만약 아래와 같은 코드가 있다면 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
  
int main()
{
        short arr[3= { 123};
        short *pShort = arr;
 
        printf("arr[i] : %d, %d, %d \n", arr[0], arr[1], arr[2]);
        printf("*(pShort + i) : %d, %d, %d \n"*(pShort), *(pShort+1), *(pShort+2));
        printf("pShort[i] : %d, %d, %d \n", pShort[0], pShort[1], pShort[2]);
        printf("*(arr + i) : %d, %d, %d \n"*(arr), *(arr+1), *(arr+2));
        printf("arr : 0x%x, pShort : 0x%x, &arr[0] : 0x%x\n", arr, pShort, &arr[0]);
 
        return 0;
}
cs

다음 그림과 같이 된다.


여기서 알아야 할 포인트는

1. 배열의 이름도 포인터다. (단 포인터 변수가 아닌 값을 바꿀 수 없는 포인터 상수이다)

즉 arr[i] 로 이제까지 값을 참조했지만, *(arr + i) 로 똑같은 값을 출력할 수 있음. 

(배열 이름은 첫 번째 index의 주소 값을 나타냄, 위 그림에서는 0x10, 코드12번째 줄)

(다만 포인터 상수이기에 arr의 값을 바꿀 수는 없음!)


2. 1차원 배열은 인덱스가 증가할 때마다 데이터 자료형 크기만큼 증가한다. 

   --> 우리가 포인터변수에 + 연산 한 것과 동일하게 증가한다. 

   --> 즉, 1차원 배열은 우리가 이제까지 배운 포인터와 동일하다. 

   short arr[3] 에서 arr은 (short *p) 타입 포인터며, 

   int arr[3] 에서 arr은 (int *p) 타입 포인터이다.


3. 포인터를 배열 이름처럼 사용할 수 있다.   (위 코드 10, 11번째 줄 결과값은 동일하다)


4. 배열의 이름은 포인터처럼 사용할 수 있다.

    즉, arr[i] == *(arr + i) 이다. (코드 11번째 줄)






반응형