~06.18 까지의 공부 일지 - 포인터

2020. 6. 19. 01:49

누군가 말하기를, 포인터가 C에서 공부하기 제일 어렵고 모호한 개념이랬다.

며칠에 걸쳐서 내용을 보니, 뭐, 틀린 말은 아니였다. 

C의 다른 내용을 보면 눈에 보이지 않는 '추상적'인 개념이 아닌, 눈에 직접적으로 보이는 형태를 띄고 있었으니까 말이다.

 

포인터는 가리킨다는 뜻의 동사 'point'에 'er'을 붙인 것이다. 따라서 가리킨다는 뜻이다. 포인터는 변수의 주소를 가지고 있는 변수이다. 포인터가 저장하고 있는 것은 값이 아니라 변수의 주소이다. 정수가 가리키는 포인터는 다음과 같이 정의된다.

int *p;

 

─ 'C언어 콘서트' 책 내용 일부 발췌

 

나는 포인터의 개념을 완벽하게 이해하기 위해 여러 개의 사이트와 책을 참고하였다. 

 

 포인터는 메모리의 한 지점, 간단히 말해 번지값을 가지는 변수이다. 어떠한 형태의 변수든지(register형만 제외하고) 반드시 메모리에 보관되며 모든 메모리는 번지를 가지고 있다.

출처 : http://soen.kr/lecture/ccpp/cpp1/10-1-1.htm

 

혼자 연구하는 C/C++ by WinApi

이 장에서는 포인터에 대해 본격적으로 다루며 다음 장은 배열과 함께 포인터를 같이 다룬다. 앞에서도 이미 포인터에 대해서 기본적인 개념을 다룬 바 있는데 3장에서 포인터 타입에 대해 간단

soen.kr

나는 이렇게 이해했다. '변수가 메모리에 저장될 때, 그 변수가 저장된 주소(위치)를 읽어오는 것이 포인터다' 라고.

 

포인터는 사용하기 전에 반드시 초기화를 해주어야 한다.

포인터에는 변수의 주소가 저장되어야 하므로, & 연산자를 사용하여 변수의 주소를 계산해 포인터에 대입한다.

 

예를들면, 

1
2
3
4
5
int number = 10;
int *Ptr;
Ptr = &number;
 
printf("%d\n"*Ptr);
cs

 

여기서 number은 정수형 변수로서 10이라는 값을 저장한다.

그리고 정수형 포인터 Ptr을 선언한 다음, number가 가리키는 메모리 번지 값을 Ptr로 불러온다는 의미로 Ptr = &number;를 적어준다.

그리고, *Ptr을 printf함수로 출력하면 (형식 지정자는 %d 사용) 변수 number가 갖는 메모리 번지 값의 참조하니깐 10이 출력된다.

 

 

 

포인터의 연산은 덧셈과 뺄셈만 가능하다. 포인터 p의 값이 1000이라고 가정하자. 즉 포인터 p는 1000번지를 가리키고 있다. 만약 p를 하나 증가시키면 p의 값은 어떻게 될까? 일반적으로는 1001이 될 것 같지만 p가 어떤 자료형을 가리키는 포인터인가에 따라서 그럴 수도 있고 아닐 수도 있다.

 

포인터 변수에 대한 일반적인 변수에 대한 연산과는 조금 다르다. 포인터에 증가연산인 ++을 적용하였을 경우, 증가되는 값은 '포인터가 가리키는 객체의 크기'이다. 즉, char형 포인터를 증가시키면 char형 크기인 1바이트만큼 증가시킨다는 것이다.

int형은 4바이트, double형은 8바이트만큼 증가한다. 감소도 마찬가지.

 

char    : 1바이트

short   : 2바이트

int      : 4바이트

float    : 4바이트

double : 8바이트

 

 

포인터를 사용할 때의 주의점.

 

① 초기화하지 않고 사용하면 안 된다.

② 널 포인터의 사용 // 포인터가 아무것도 가리키고 있지 않을때는 NULL(0)으로 설정하는 것이 바람직함

③ 포인터 자료형과 변수의 자료형은 일치하여야 한다.

 

배열과 포인터

 

배열과 포인터는 밀접한 관계를 가지고 있다. 배열 그 이름 자체가 포인터이기 때문. 배열 이름은 첫 번째 배열 원소의 주소와 같다.

 

 

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
 
int main()
{
    int a[] = { 1020304050 };
 
    printf("배열의 이름 : %u\n", a);
    printf("첫 번째 원소의 주소 : %u\n"), &a[0]);
 
    return 0;
}
cs

 

이렇게 하면 동일한 값이 출력된다.

 

포인터를 배열처럼 사용할 수도 있다.

 

int a[] = { 10, 20, 30, 40, 50 };

int* p;

p = a;

 

하면 p에 정수형 배열인 {10,20,30,40,50}이 초기화된다.

 

예제도 풀어보았다.

 

1. 1차원 배열을 받아서 배열 요소들의 합을 계산하는 함수 int get_array_sum(int *A, int size)을 구현하고 int data[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 을 가지고 테스트하라.

 

 

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
27
28
29
30
31
32
#include <stdio.h> 
int get_array_sum(int* A, int size);
 
int main()
{
    int arr[10= { 123456789 };
    int result = get_array_sum(arr, 10);
 
    printf("print_array()\n");
    for (int i = 0; i < 10; i++)
        printf("%d ", arr[i]);
    
    printf("\n");
 
    printf("배열 요소의 합 : %d \n", result);
 
    return 0;
    
}
 
int get_array_sum(int* A, int size)
{
 
    int sum = 0;
 
    for (int i = 0; i < size; i++)
    {
        sum += A[i];
    }
 
    return sum;
}
cs

 

어렵진 않았다. 애초에 문제에서 함수의 형태가 주어졌고, 변수명에서도 알수 있듯이 포인터와 배열의 크기를 가지고 함 수를 어떻게 짜는 지도 쉽게 알 수 있기 때문에.. 

 

2. 포인터를 이용하여서 크기가 5인 1차원 정수 배열에 저장된 값을 역순으로 출력해보자.

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
27
28
29
30
#include <stdio.h>
 
int main()
{
 
    int arr[5];
 
    printf("5개의 정수를 입력하라 : ");
    for (int i = 0; i < 5; i++)
    {
        scanf_s("%d"&arr[i]);
    }
 
    int* ptr;
    ptr = arr;
 
    printf("역순 : ");
 
    for (int i = 4; i >= 0; i--)
    {
        printf("%d ", ptr[i]);
    }
 
 
 
    printf("\n");
 
    return 0;
}
 
cs

 

이건 개인적으로 궁금한 건데, 이 문제는 5개의 정수만 입력받도록 해서, 사이즈가 5개로 제한되었다.

근데 사이즈를 사용자가 할당해서 만들 수는 없을까 ? 한 번 만들어보려고 했는데 scanf_s를 어떤 조건에서 몇 번만 탐색하는 지에서 막혔다. 내가 배우지 않은 무언가가 있는 것 같다. (처음에 printf("몇 개의 정수를 입력하시겠습니까? : ");로 갯수를 선입력 받는 것 말고, 입력받은만큼 scanf_s를 돌리는 걸 모르겠다. 뒤에 문자열 파트 배우면 한 번 해봐야겠다.

 

 

3. 실수 3.14를 보내면 정수부 3과 소수부 0.14를 나누어서 보내주는 함수 

void(double value, int *i_part, double *f_part)을 구현해보자. 매개변수로 포인터를 사용하면 함수가 2개 이상의 값을 반환할 수 있다.

 

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
#include <stdio.h>
void get(double value, int* i_part, double* f_part);
 
int main()
{
    double flt;
    double f_part;
    int i_part;
 
    printf("실수를 입력하여라 : ");
    scanf_s("%lf"&flt);
    
    get(flt, &i_part, &f_part);
 
    printf("정수부 : %d\n", i_part);
    printf("실수부 : %f\n", f_part);
 
    return 0;
}
 
void get(double value, int* i_part, double* f_part)
{
    *i_part = (int)value;
    *f_part = value - *i_part;
}
cs

'공부 > C' 카테고리의 다른 글

배열을 이용한 문제풀이  (0) 2020.06.26
문자열 1  (0) 2020.06.24
재밌는 문제 (while문) : 더하기 사이클  (0) 2020.06.23
배열 프로그래밍 예제 마지막 문제 학습  (0) 2020.06.10

BELATED ARTICLES

more