F.R.I.D.A.Y.

지식인 : 리스트 자료구조 포인터 본문

외부활동/지식in

지식인 : 리스트 자료구조 포인터

F.R.I.D.A.Y. 2019. 3. 6. 01:42
반응형



A.

 먼저 코드를 봅시다.

 HEARD1.h



#ifndef __HEAD1_H__
#define __HEAD1_H__

#define TRUE 1
#define FALSE 0

typedef int LData;

typedef struct _node
{
LData data;
struct _node *next;
}Node;

typedef struct _linkedList
{
Node*head;
Node*cur;
Node*before;
int numOfData;
int(*comp)(LData d1, LData d2);
}LinkedList;

typedef LinkedList List;

void LinstInit(List plist)
{
plist.head = (Node*)malloc(sizeof(Node));
plist.head->next = NULL;
plist.comp = NULL;
plist.numOfData = 0;
}
#endif




 main.c


#include <stdio.h>
#include "HEARD1.h"
int main(void)
{
List L;
LinstInit(L);
}

 입니다. 위 코드를 실행하면 아래와 같은 오류와 경고가 발생합니다.



malloc은 stdlib.h 헤더를, NULL은 stdio 헤더를 인클루드 해야합니다. 사용하는 곳은 HEARD1.h이므로, main.c에서 인클루드 하였더라도 HEARD1.h와 stdio.h 헤더는 연관성이 존재하지 않아 오류가 일어납니다.

#include <stdio.h>
#include <stdlib.h>

 위 코드를 HEARD1.h 파일의 가장 앞에 선언함으로써 C4013, E0020 문제를 해결할 수 있습니다.


 C4700의 경우 main.c의 문제입니다.



 선언이 되어있지만, L이라는 변수에 어떤 값이 들어가있는지 알 수 없습니다. 이 경우 프로그램이 예기치 못한 문제가 발생할 수 있기 때문에 오류를 일으킬 수 있습니다. 따라서 예측 가능한 값을 넣어 변수를 초기화하는 과정이 필요합니다.

 원래대로라면 구조체의 멤버 변수를 일일이 다 값을 대입하거나 구조체 초기화를 이용해 처리하는 것이 정석이지만, 이번에는 초기화를 하는 과정이 필요함을 보이기 위함이므로 편법으로 값을 초기화하겠습니다.



 memset 함수를 이용해 L 변수를 모두 0으로 초기화 했습니다. memset 함수는 string.h 헤더를 추가해야 사용할 수 있습니다.


 출력하는 함수가 존재하지 않은 프로그램이기 때문에 출력을 보여드릴 수는 없지만 위 과정을 거치시면 정상적으로 동작함을 알 수 있습니다. 그러나 논리적인 오류가 존재합니다.



논리적 오류가 있다.

 HEARD1.h 헤더의 LinstInit(List plist) 함수를 봅시다.



 List 타입의 plist 변수가 매개변수로 설정되어 있습니다. 아마도 main.c의 L 변수의 주소를 가져와서 값을 넣으려고 한 듯 한데, plist 변수를 List 타입으로 설정하면 제대로 동작하지 않습니다. List 로 전달을 하게 되면 main.c에 존재하는 L 변수의 값이 전달되기 때문에 plist를 변경한다고 main.c의 L 변수가 변경되지는 않습니다.


 파라미터인 plist 또한 함수의 지역변수 개념으로 보시면 됩니다. 이러한 경우, plist의 자료형을 List *로 작성하여 처리해야합니다. 매개변수 자료형이 List *로 변경되었기 때문에 main.c에 작성된 LinstInit(L) 또한 LinstInit(&L)으로 변경해주어야합니다.



 그런데 plist를 사용하는 곳에 오류가 났다며 빨간 밑줄이 발생합니다. 포인터 변수는 직접 값에 접근할 수 없기 때문에 간접참조 연산을 한 후에 접근이 가능합니다.



 plist를 (*plist)로 변경하면 정상적으로 실행되는 모습을 볼 수 있습니다. *plist로 작성하면 안됩니다. " . " 연산자가 " * " 연산자보다 연산 우선 순위가 높기 때문에 꼭 괄호로 우선순위를 재지정 해주셔야합니다. 그런데 이렇게 매번 괄호로 우선순위를 재지정하는 것은 번거롭습니다. 이러한 문제를 해결하기 위해 ->(화살표) 연산자가 생겼습니다. 위 코드는 아래 이미지와 같이 작성할 수 있습니다.



 여기까지 작성하면 프로그램을 운영하는데는 문제가 없습니다.



그래도 문제가 남다.

 그래도 아직 남은 문제가 있습니다. malloc으로 동적할당한 메모리는 프로그램이 종료되기 전까지 자동으로 해제되지 않고 계속해서 유지됩니다. 따라서 free로 사용하지 않는 부분은 해제해주어야합니다. 이경우에는 각 프로그램마다 어디를 free해주어야하는지가 다르기때문에 정확히 어느 위치에서 해야한다! 라고 장담드리기 어렵습니다. 그러나, 질문의 코드를 제가 제시해드린 방법처럼 고친 후에 최종적으로 free 해주어야하는 곳은 main.c의 LinstInit(&L); 코드 다음이라고 말씀드립니다.



 이 때, free의 대상은 L변수가 아니라 L 변수 구조체의 멤버 변수인 head입니다. head에 동적할당된 메모리 주소를 담기 때문입니다.


 이제서야 정말 끝입니다.

728x90
반응형
Comments