포인터(1)

이준호·2022년 9월 25일
0

C/C++

목록 보기
1/1
post-thumbnail

서론

알고리즘 문제를 풀 때 주로 C++의 STL을 사용하다보니 포인터를 잘 안쓰게 된 것 같다.
그러다 학교 알고리즘 수업에서 STL을 사용하지 않고 직접 필요한 자료구조를 구현하여 문제를 풀어보라는 교수님의 말씀에 포인터 개념을 다시 정리하기로 했다.

포인터란?

포인터는 두 가지 의미가 있다.

  • 포인터 타입
  • 포인팅할 때의 포인터
int main() {
	int a = 10;
	int *p = &a;	// 이 때의 '*'는 포인터 타입을 말한다.
    printf("%d", *p); // 이 때의 '*'는 포인팅하는 포인터를 말한다.
}

포인터는 왜 필요한가?

여러가지 이유가 있을 것 같다. 그 중에서 이번 포스트에서는 두 가지 케이스를 다뤄볼 것이다.

  • 동적으로 배열을 할당하고 싶은 경우
  • 함수에서 call by reference 방식으로 사용하고 싶은 경우
void swap(int *a, int *b)
{
	int tmp = *a;
  	*a = *b;
  	*b = tmp;
}

int main()
{
  	int a = 10, b = 20;
  	cout << a << ' ' << b << '\n';
  	swap(&a, &b);
  	cout << a << ' ' << b << '\n';

  	int size;
  	cin >> size;
  	int *arr = (int *)malloc(sizeof(int) * size); // 입력 받은 size 값 만큼 동적으로 배열의 크기가 할당
}

심화

2차원 배열 만들기

const int ROWSIZE = 4;
const int COLSIZE = 5;
void printArr(int **arr)
{
    for (int i = 0; i < ROWSIZE; i++)
    {
        for (int j = 0; j < COLSIZE; j++)
        {
            cout << arr[i][j] << ' ';
        }
        cout << '\n';
    }
}

int main()
{
    int **arr = (int **)malloc(sizeof(int *) * ROWSIZE);
    for (int i = 0; i < ROWSIZE; i++)
    {
        arr[i] = (int *)malloc(sizeof(int) * COLSIZE);
    }
    int cnt = 0;
    for (int i = 0; i < ROWSIZE; i++)
    {
        for (int j = 0; j < COLSIZE; j++, cnt++)
        {
            arr[i][j] = cnt;
        }
    }
    printArr(arr);
    for (int i = 0; i < ROWSIZE; i++)
    {
        delete arr[i];
    }
    delete arr;
}

자료구조 (node) 만들기

typedef struct Node
{
    int data;
    Node *left;
    Node *right;
} node;

void insert(node **root, int data)
{
    if (*root == NULL)
    {
        *root = (node *)malloc(sizeof(node));
        (*root)->data = data;
        (*root)->left = NULL;
        (*root)->right = NULL;
        return;
    }
    if ((*root)->data > data)
        insert(&(*root)->left, data);
    else
        insert(&(*root)->right, data);
}

void preOrder(node *root)
{
    if (root == NULL)
        return;
    cout << root->data << '\n';
    preOrder(root->left);
    preOrder(root->right);
}

void destruct(node **root)
{
    if (*root == NULL)
        return;
    destruct(&(*root)->left);
    destruct(&(*root)->right);
    delete *root;
    *root = NULL;
}

int main()
{
    node *root = NULL;
    insert(&root, 20);
    insert(&root, 10);
    insert(&root, 30);
    preOrder(root);
    destruct(&root);
}

여기서 insert 함수와 destruct 함수의 파라미터에는 왜 투포인터를 사용해야 할까?

  • 함수에서 malloc 하는 경우
  • 함수에서 root 값을 변경해야 하는 경우
void insert(node **root, int data)
{
    if (*root == NULL)
    {
        *root = (node *)malloc(sizeof(node)); // 여기에 브레이크 포인트를 걸었다고 합시다
        (*root)->data = data;
        (*root)->left = NULL;
        (*root)->right = NULL;
        return;
    }
    if ((*root)->data > data)
        insert(&(*root)->left, data);
    else
        insert(&(*root)->right, data);
}

int main() {
	node *root = NULL;
    insert(&root, 20);
    ...
}

브레이크 포인트 걸린 초기 모습

malloc으로 할당 한 후의 모습

만약 insert 함수 파라미터에 포인터를 두개 붙이지 않고 한개만 붙이고 브레이크 포인트에 걸린 초기 모습

만약 insert 함수 파라미터에 포인터를 두개 붙이지 않고 한개만 붙이고 malloc으로 할당 한 후의 모습

잘 못된 부분이나 이해가 안되는 부분은 댓글 달아주세요!

profile
코딩 조아

0개의 댓글