프로그래밍임베디드 개발자

C 언어에서 동적 데이터 구조(예: 연결 리스트)의 선언 및 사용에 대한 세부 사항을 설명해 주세요. 구현 시 특별히 주의해야 할 점은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

C에서 동적 데이터 구조(예: 연결 리스트, 트리)는 일반적으로 포인터 및 동적 메모리 할당(malloc, calloc, free)을 사용하여 수동으로 구현됩니다.

구현 시 주요 세부 사항:

  • 포인터를 반드시 초기화하세요: 초기화되지 않은 포인터의 쓰레기 값은 메모리 누수 또는 세그멘테이션 오류를 초래할 수 있습니다.
  • 메모리 할당 오류를 처리하세요: malloc/calloc의 결과를 확인하지 않으면, 프로그램이 유효하지 않은 포인터로 작업할 수 있습니다.
  • 메모리를 올바르게 해제하세요: 할당된 각 구조체에 대해 free를 호출해야 메모리 누수를 방지할 수 있습니다.
  • 해제 후 포인터를 널로 설정하여 덜 깔끔한 포인터를 피하세요.

예제: 단순 단일 연결 리스트의 생성 및 삭제

typedef struct Node { int value; struct Node* next; } Node; Node* create_node(int value) { Node* n = malloc(sizeof(Node)); if (!n) return NULL; n->value = value; n->next = NULL; return n; } void free_list(Node* head) { while (head) { Node* tmp = head; head = head->next; free(tmp); } }

함정 질문.

리스트 노드의 메모리를 현재 포인터만 사용하여 루프 내에서 해제할 수 있나요?

다음 노드를 미리 저장하지 않고 현재 노드를 해제하는 것은 올바르지 않습니다! free를 호출한 후에는 메모리가 덮어쓰여지거나 운영 체제에 반환될 수 있습니다.

올바른 접근법:

Node* curr = head; while (curr) { Node* next = curr->next; free(curr); curr = next; }

next를 저장하지 않으면 이미 해제된(및 잠재적으로 본인의 것이 아닌!) 메모리에 대한 접근이 발생합니다.


역사


한 작업에서 잘못 종료되었을 때 전체 리스트를(즉, free) 정리하지 않는 것을 잊어버려 10,000개의 추가/삭제 작업에서 메모리 사용량이 점차 증가했으며, 프로파일러는 큰 메모리 누수를 나타냈습니다.


개발자는 리스트의 마지막 노드에 대한 포인터를 저장했으나 모든 요소를 삭제한 후 이를 초기화하지 않아 다른 함수에서 이미 해제된 메모리를 참조하며 식별하기 어려운 세그멘테이션 오류를 발생시켰습니다.


트리 작업 시 모든 "서브트리"를 재귀적으로 삭제하는 것을 잊고 오직 루트 노드만 해제했습니다. 결과적으로, 불완전한 정리로 인해 메모리 구조가 더럽혀져 주기적인 오류가 발생했습니다.