포인터로 매개변수 넘겨서 메모리 할당 시 주의할 점

2019. 11. 15. 02:29PL/C++

대표적으로 연결리스트 구조로 큐를 만드려고 할 때, 보통 ref 코드를 보면 주소값을 반환하는 init 함수를 만들어서 할당하는 경우들이 대부분이다. 아래와 같이 말이다. 그러면 매개변수로 포인터 변수를 넘겨서도 가능하지 않나?

 

struct QNode* newNode(int k) 
{ 
    struct QNode* temp = (struct QNode*)malloc(sizeof(struct QNode)); 
    temp->key = k; 
    temp->next = NULL; 
    return temp; 
} 

void enQueue(struct Queue* q, int k) 
{ 
    // Create a new LL node 
    struct QNode* temp = newNode(k); 
    
    ....
}

 

가능은 하지만 주의할 점이 있다. C언어에서는 같은 레벨의 변수를 넘긴다면 복사해버린다. 즉 같은 레벨을 넘기다보니 실제로 스택에는 똑같은 변수들이 복사되어서 쌓이고 그 함수가 끝나면 사라져버리는 괴이한 현상을 보곤했다. 우리는 이 문제를 해결하기 위해서 포인터를 배웠고, 변경된 값을 받고 싶다면 주소값을 매개변수로 전달했다. 즉 포인터변수 레벨에서도 같은 포인터변수로 매개변수를 받는다면 복사가 이뤄지기 때문에 실제로는 엉뚱한 곳에 할당이 될 것이다

 

첫번째 코드는 Queue를 정적할당해서 주소값을 전달해 초기화하는 과정이다

 

#include <cstdlib>
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *next;
};
struct Queue {
struct Node *front;
struct Node *rear;
};
void EnQueue(struct Queue *q, int data) {
struct Node *tmp = (struct Node *)malloc(sizeof(struct Node));
tmp->data = data;
tmp->next = NULL;
if (q->front == NULL) {
q->front = q->rear = tmp;
return;
}
q->rear->next = tmp;
q->rear = tmp;
}
void PrintQueue(struct Queue *q) {
struct Node *ptr = q->front;
while (ptr != NULL) {
cout << ptr->data << ' ';
ptr = ptr->next;
}
cout << '\n';
}
int main(void) {
struct Queue q{NULL, NULL};
EnQueue(&q, 10);
EnQueue(&q, 20);
EnQueue(&q, 30);
EnQueue(&q, 40);
EnQueue(&q, 50);
PrintQueue(&q);
return 0;
}

 

두번째 코드는 Queue를 포인터변수로 선언해서 초기화하는 과정이다

 

#include <cstdlib>
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *next;
};
struct Queue {
struct Node *front;
struct Node *rear;
};
void InitQueue(struct Queue **q) {
*q = (struct Queue *)malloc(sizeof(struct Queue));
(*q)->front = (*q)->rear = NULL;
}
void EnQueue(struct Queue **q, int data) {
struct Node *tmp = (struct Node *)malloc(sizeof(struct Node));
tmp->data = data;
tmp->next = NULL;
if ((*q)->front == NULL) {
(*q)->front = (*q)->rear = tmp;
return;
}
(*q)->rear->next = tmp;
(*q)->rear = tmp;
}
void PrintQueue(struct Queue **q) {
struct Node *ptr = (*q)->front;
while (ptr != NULL) {
cout << ptr->data << ' ';
ptr = ptr->next;
}
cout << '\n';
}
int main(void) {
struct Queue *q = NULL;
InitQueue(&q);
EnQueue(&q, 10);
EnQueue(&q, 20);
EnQueue(&q, 30);
EnQueue(&q, 40);
EnQueue(&q, 50);
PrintQueue(&q);
return 0;
}

 

따라서 2번의 과정처럼 매개변수 전달이 귀찮다면 주소값을 반환하는 함수를 만들어서 할당하는 것이 맞고, 일반적으로 ref 코드에서 많이 사용되는 것 같다

 

 

'PL > C++' 카테고리의 다른 글

가상 소멸자가 필요한 이유  (0) 2019.11.16
큐 연결리스트로 구현하기  (0) 2019.11.15
C++ 위임생성자  (0) 2019.11.14
함수포인터  (0) 2019.11.13
함수포인터가 쓰이는 경우  (0) 2019.11.13