예습

[예습] 9월 23일 예습

k-codestudy 2024. 9. 23. 14:33

1. 주소 값

포인터를 알기전에 주소값을 먼저 이해해야한다.

변수는 데이터를 저장하기 위해 메모리에 공간을 할당받는데, 이때 데이터를 찾기 위해 필요한 정보가 바로 주소 값(메모리의 시작 주소)이다. 주소 값은 메모리에서 데이터가 저장된 위치를 가리키는데, 예를 들어, int형 변수는 4바이트의 메모리 공간을 할당받고, 해당 변수의 시작 주소를 주소 값이라고 한다

 

 

2. 포인터 (pointer)

포인터는 변수이다. 

일반적으로 우리가 데이터를 저장할때는 변수에 저장하게 되는데, 포인터의 경우 데이터가 저장되어있는 변수의 주소값을 저장한다.

실제 메모리의 위치는 아니지만 포인터 변수는 int변수의 시작 주소를 저장해 변수를 가리키고 있다고 생각하면 된다.

또한 포인터도 변수이기에 메모리 어딘가에 저장되기 때문에 포인터도 주소 값을 가지고 있다.

 

문법)

타입 변수명 = 데이터; (일반 변수 선언)

타입* 변수명 = &일반 변수명; (가리키고자 하는 변수명을 입력)

#include <iostream>

int main ()
{
    int a{};
    int* ptr{&a};

    a = 10;


    printf("%d", a);
    printf("%d", *ptr);
}

포인터 변수 ptr에 a변수의 주소 값을 저장해 a를 가리키고 있다.

 

3. 포인터 연산자

 포인터 변수를 이용하면서 2가지의 연산자가 사용된다.

 

& : 주소 연산자 ( 변수 이름 앞에 사용하여 해당 변수의 메모리 주소 값을 반환한다. )

* : 참조 연산자 ( 포인터의 이름이나 주소 앞에 사용하며 해당 주소를 참조하여 주소에 저장되어 있는 값을 반환한다. )

 

#include <iostream>

int main ()
{
    int a{};
    int* ptr{&a};

    a = 10;


    printf("%d", a);
    printf("%d", *ptr);
    printf("%d", *&a);
}

 

포인터는 가리키는 변수의 자료형과 일치해야 한다. 이는 참조할 때 해당 데이터를 올바르게 해석하기 위함이며 모든 포인터는 같은 크기를 가지며, 이는 CPU의 아키텍처에 따라 결정이 된다.

 

4. 이중 포인터

이중 포인터는 포인터를 가리키는 포인터입니다. 즉, 포인터 변수의 주소를 저장합니다.

#include <iostream>

int main ()
{
    int a{};
    int* ptr{&a};
    int** pptr{&ptr};

    a = 10;


    printf("%d", a);
    printf("%d", *ptr);
    printf("%d", **pptr);
}

이는 포인터를 가리키는 포인터라는 뜻으로 이중 포인터 변수 pptr안에는 포인터 변수 ptr의 주소 &ptr와 같은 값이 들어가 있는것을 확인. 따라서 **pptr은 2번 참조하여 p의 값 10이 나오게 되는 것인데 첫 잠조에 pptr이 가진 주소의 값의 데이터를 찾아게게 되어 a의 주소를 반환 거기서 한 번 더 참조하므로 a의 주소를 참조하게 되어 a의 데이터 값이 반환되는 것이다.

즉, **pptr => *(*ptr) => *(ptr의 주소) => a의 값으로 이해하면 된다.

 

5. 포인터 연산

  1. 포인터는 주소 값을 저장하기 때문에, 포인터 간의 덧셈, 곱셈, 나눗셈 연산은 의미가 없다. 다만, 뺄셈은 두 포인터 사이의 거리(주소 간 차이)를 나타낼 수 있다.
  2. 포인터에 정수 값을 더하거나 빼는 것은 가능하지만, 실수 값은 사용할 수 없다.
  3. 데이터 타입에 따라 포인터를 더하거나 뺄 때 증가하는 주소의 크기가 다르다. 예를 들어, int형 포인터에 +1을 하면 4바이트만큼, double형 포인터에 +1을 하면 8바이트만큼 주소가 증가한다.

 

6. 포인터와 배열

배열의 이름은 배열의 시작 주소를 가리키므로. 배열은 포인터처럼 사용할 수 있으며, 배열을 포인터처럼 다루는 것도 가능하다.

#include <iostream>

int main ()
{
    int arr[3] = { 10, 20, 30};
    int* pt_arr = arr;

    printf("%d, %d, %d", arr[0], arr[1], arr[2]);
    printf("%d, %d, %d", pt_arr[0], pt_arr[1], pt_arr[2]);
}

 

배열명을 이용하여 출력하는 것 처럼 포인터에 []를 붙혀 출력하면 배열명과 동일한 결과를 얻을 수 있다.

포인터를 배열처럼 이용하는 것이 가능하므로 배열을 포인터처럼 이용하는 것 또한 가능하다.

 

#include <iostream>

int main ()
{
    int arr[3] = { 10, 20, 30};
    int* pt_arr = arr;

    printf("%d, %d, %d", arr[0], arr[1], arr[2]);
    printf("%d, %d, %d", *(arr), *(arr + 1), *(arr + 2));
}

배열명으로 시작 주소 값을 호출하여 참조 연산자를 붙여 그 값을 호출한 결과 배열에 저장된 값이 호출되며, 배열의 연산에서 배열에 덧셈을 하는 것은 해당 데이터형의 크기만큼 증가되므로 배열의 다음 요소의 시작 주소를 가리키게 되어 *를 이용할 결우 값이 출력되는 것을 알 수있다.

 

[주의]

포인터를 역참조 하는 것은 포인터에 저장된 메모리의 주소를 이용하여 해당 주소의 메모리에 있는 내용을 반환하는 것이다.

따라서 우리가 작성한 프로그램이 운영체제에서 할당하지 않은 메모리를 임의로 참조하려 할 경우 보안상의 이유로 운영체제에서 프로그램을 중단시킨다.

'예습' 카테고리의 다른 글

[예습] 10월 7일 예습  (1) 2024.10.08
[예습] 9월 30일 예습 정리  (0) 2024.10.01
[예습] 9월 9일 예습  (0) 2024.09.10
[예습] 9월 2일 예습  (0) 2024.09.02
[예습] 8월 26일 예습  (0) 2024.08.26