728x90

배열 포인터 : 배열을 가리키는 포인터. 연속적인 메모리만 가리킬 수 있다.

포인터 배열 : 배열에 메모리 주소 값을 저장할 수 있는 배열. 즉 포인터들이 배열이다.


 - 배열명은 변수가 아니라 상수로 시작주소를 갖고 있다. 따라서 값을 변경할 수 없다.

 - 포인터는 값을 변경할 수 있다.

 - 배열은 내부적으로 포인터다.

 - 배열과 포인터는 서로 호환된다.

 - 배열명은 a = a + 1; 불가능하다.

 - 포인터는 p = p + 1; 가능하다.



예제1.

#include <stdio.h>
#include <iostream> //  C++에선 <iostream>에 정의되어 있는 std::를 이용해서 입출력을 사용한다.

int main() {
    // 배열 포인터 : 배열을 가리키는 포인터. 연속적인 메모리만 가리킬 수 있다.
    // 포인터 배열 : 배열에 메모리 주소 값을 저장할 수 있는 배열. 즉 포인터들이 배열이다.

    /*
        1. ptr == &ptr[0]
        2. *ptr = ptr[0]
        3. ptr + 1 = ptr 에 sizeof(*ptr)을 더한 값
    */

    int arr[5] = {1,2,3,4,5};

    int(*ptr_arr)[5]; // int형 타입의 인덱스를 5개 가지고 있는 배열을 가리키는 배열 포인터를 선언
    ptr_arr = &arr;

    printf("\n***** 배열 포인터 *****\n");

    // 배열의 주소를 가진 포인터는 +1 / -1 연산으로 어느 원소든 쉽게 접근이 가능하다.
    // 포인터에 1을 더했지만 주소는 배열의 단위인 int(4byte) 만큼 더해진 것을 확인할 수 있다.
    std::cout << "arr[0] 주소 값 :: " << *ptr_arr << "\n";
    std::cout << "arr[1] 주소 값 :: " << *(ptr_arr + 1) << "\n";
    std::cout << "arr[2] 주소 값 :: " << *(ptr_arr + 2) << "\n";
    std::cout << "arr[3] 주소 값 :: " << *(ptr_arr + 3) << "\n";
    std::cout << "arr[4] 주소 값 :: " << *(ptr_arr + 4) << "\n\n";

    // 입력은 std::cin >> "변수" ,  출력을 std::cout << "변수 or 문자열", 문자열 변경은 std::endl;로 사용

    for (int i = 0; i < 5; i++) {
        printf("arr[%d] 주소 값 :: %p\n",i, ptr_arr[i]);
    }
    printf("\n");

    for (int i = 0; i < 5; i++) {
        printf("%d\n", (*ptr_arr)[i]);
    }

    // 포인터 배열
    int* ptr[5]; // 포인터 배열 선언

    for (int i = 0; i < 5; i++) {
        ptr[i] = &arr[i];
    }

    printf("\n***** 포인터 배열 *****\n");
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] 주소 값 :: %p\n", i, ptr[i]);
    }

    for (int i = 0; i < 5; i++) {
        printf("arr[%d] 값 :: %d\n", i, *ptr[i]);
    }
    printf("\n");


    printf("\n***** 2차원 배열을 포인터에 넣기 *********\n");
     
    // 2차원 배열을 포인터에 넣기

    int Arr[2][3] = { {1,2,3},{4,5,6} };

    // 포인터 선언 : 자료형 (*포인터이름)[가로크기]
    int (*Ptr)[3] = Arr; // Ptr 은 행 전체를 가리키는 포인터 (가로크기가 4인 배열을 가리키는 포인터)

    printf("%p\n", *Ptr);
    printf("%p\n", *Arr);
    printf("%d\n", Ptr[1][1]);
    printf("%d\n", sizeof(Arr)); // 결과 : 4 X 5 = 20
    printf("%d\n", sizeof(Ptr));  // 결과 : 4
    printf("\n");

    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", Ptr[i][j]);
        }
        printf("\n");
    }

    printf("**************\n");
    for (int(*row)[3] = Arr; row < Arr + 2; row++) {
        for (int *col = *row; col < *row + 3; col++) {
            printf("%d ", *col);
        }
        printf("\n");
    }
 
}



아래 코드는 https://dojang.io/mod/page/view.php?id=317 에 있는 걸 Visual Studio 2019 Community 로 테스트해서 에러나는 부분은 수정했다.


배열의 크기를 동적으로 할당받는 걸 시도해보면...

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    int size;
    scanf("%d", &size);  // 배열의 크기를 입력받음

    int Arr[size];    // Visual Studio 2019에서는 컴파일 에러
}

에러가 발생한다.

C에서 배열의 크기를 동적으로 할당하는 방법은

포인터에 메모리를 동적으로 할당하여 배열처럼 사용하는 방법으로는 가능하다.

포인터에 malloc 함수로 메모리를 할당해주면 된다.


예제2.

#include <stdio.h>
#include <stdlib.h>  // malloc, free 함수가 선언된 헤더 파일

int main()
{
    // 포인터에 할당된 메모리를 배열처럼 사용하기

    // 자료형 *포인터이름 = malloc(sizeof(자료형) * 크기);

    int* numPtr = (int*)malloc(sizeof(int) * 10);    // int 10개 크기만큼 동적 메모리 할당
    // malloc 함수 : 동적으로 메모리를 할당하는 함수 (힙(Heap) 영역에 메모리를 할당)
    // malloc은 메모리만 할당하는 함수이기 때문에 개발자가 어떠한 데이터 형을 저장하는지 예측할 수 없다.
    // int형 데이터를 저장하기 위해서는 리턴되는 void*을 int*로 변환해야 한다.


    numPtr[0] = 10;    // 배열처럼 인덱스로 접근하여 값 할당
    numPtr[9] = 20;    // 배열처럼 인덱스로 접근하여 값 할당

    printf("\n**** 메모리 동적 할당 ****\n");
    printf("%d\n", numPtr[0]);    // 배열처럼 인덱스로 접근하여 값 출력
    printf("%d\n", numPtr[9]);    // 배열처럼 인덱스로 접근하여 값 출력

    free(numPtr); // 동적으로 할당한 메모리 해제
    // 동적할당 후 더 사용할 이상 필요가 없다면 꼭 free함수로 메모리를 해제 시켜주어야 한다.

    return 0; // 굳이 적어주지 않아도 된다.

}


힙(heap)은 C 언어나 자바와 같은 프로그래밍 환경에서 원시 자료형이 아닌 보다 큰 크기의 데이터를 담고자 동적으로 할당하는 메모리 공간을 지칭한다.

- 장점: 상황에 따라 원하는 크기만큼의 메모리가 할당되므로 경제적이며,

         이미 할당된 메모리라도 언제든지 크기를 조절할 수 있다.
- 단점: 더 이상 사용하지 않을 때 명시적으로 메모리를 해제해 주어야 한다.


C++ 에서는 new 연산자를 통해 동적 할당하고, delete 연산자를 통해 메모리를 해제한다.


C++ 배열 및 포인터에 대한 예제다.

char myString[255];

cin >> myString  으로 입력 받으면 공백 이후 입력값은 무시된다.

cin.getline(myString, 255); 로 입력을 받으면 공백도 입력이 된다.


예제3.

#include <iostream>

using namespace std;

void ShowArray(int arr[]) {
    cout << "function size : " << sizeof(arr) << endl; // 4
    cout << "function value : " << *arr << endl; // 배열의 첫번째 값 반환
    cout << endl;
}

int main() {

    int arr[5] = { 1, 2, 3, 4, 5 };

    for (int i = 0; i < sizeof(arr)/sizeof(int); i++) {
        cout << arr[i] << endl;
    }
    cout << endl;

    int* ptr = arr; // 포인터 선언 및 주소 할당

    cout << "arr 값 : " << *arr << endl; // 배열의 첫번째 값 반환
    cout << "ptr 값 : " << *ptr << endl; // 배열의 첫번째 값 반환
    cout << endl;

    cout << "arr 주소 : " << arr << endl; // 배열명이 배열의 첫번째 요소의 주소 반환
    cout << "arr[0] 주소 : " << &arr[0] << endl; // 배열의 첫번째 요소의 주소 반환
    cout << endl;

    cout << "arr[0] 주소 : " << (uintptr_t)&arr[0] << endl; // 10진수 주소 반환
    cout << "ptr 주소 : " << uintptr_t(ptr) << endl; // 10진수 주소 반환
    cout << endl;

    cout << "ptr1 주소 : " << uintptr_t(ptr + 1) << endl; // 10진수 주소 반환
    cout << "ptr2 주소 : " << uintptr_t(ptr + 2) << endl; // 10진수 주소 반환
    cout << "ptr3 주소 : " << uintptr_t(ptr + 3) << endl; // 10진수 주소 반환
    cout << endl;

    // 포인터 연산
    for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
        cout << "ptr" << i << " 값 : " << *(ptr + i) << " , 주소 : " << (uintptr_t)(ptr + i) << endl;
    }
    cout << endl;

    cout << "arr size : " << sizeof(arr) << endl; // 4 X 5 = 20
    cout << "ptr size : " << sizeof(ptr) << endl; // 4
    cout << endl;

    ShowArray(arr);

    char name[] = "GilDong, Hong"; // 문자 배열로 마지막에 NULL 값이 들어가 있다.
    char* ptr_n = name; // 배열명이 주소를 반환하므로, 포인터 변수 선언 및 주소 할당

    cout << name << endl; // 값을 반환. 주소를 출력할 것으로 생각되는데 값을 반환한다.
    cout << (uintptr_t)&name << endl; // 주소 반환

    const int n_name = sizeof(name)/sizeof(char);

    for (int i = 0; i < n_name; i++) {
        cout << *(ptr_n + i); // 마지막 NULL 값까지 반환됨
    }

    return 0;
}
 



참조하면 좋은 강좌

https://www.youtube.com/watch?v=H-FfGUwSU-U&t=296s


블로그 이미지

Link2Me

,