C - 구조체 응용

구조체 재정의

struct만을 활용해 구조체를 정의할 수 있지만 typedef를 활용하면 구조체를 데이터 타입과 같이 활용할 수 있다.

// typedef struct (구조체_이름) { 구조체_필드 } 구조체_자료형_이름;

typedef struct {
	int num;
	char string[5];
} NewStruct;

int main(void)
{
	NewStruct var;
	return 0;
}

구조체 포인터

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

typedef struct {
	int x;
	int y;
} Point;

void InitStruct(Point*);

int main(void)
{
	Point* p = (Point*) malloc(sizeof * p);
	if (p == NULL) return -1;

	InitStruct(p);
	printf("(%d, %d)\n", p->x, p->y);
	free(p);

	return 0;
}

void InitStruct(Point* p)
{
	(*p).x = 3;
	p->y = 7;
}

구조체를 복사해 함수로 전달할 수도 있지만, 구조체가 큰 경우 메모리 공간이 낭비된다는 단점이 있다. 따라서 구조체의 포인터를 넘겨 구조체를 조작할 수 있다. 

#include <stdlib.h>

// 구조체* 포인터_변수 = (구조체*) malloc(메모리_)
Point* p = (Point*) malloc(sizeof * p);
if (p == NULL) return -1;
free(p);

구조체 포인터를 선언하기 위해서는 <stdlib.h>malloc을 이용한 동적 할당이 필요하다. 만약 정상적으로 할당이 되지 않으면 NULL 포인터를 가리킨다. 포인터를 사용한 후 free를 통해 해제할 수 있다. 

void InitStruct(Point* p)
{
	(*p).x = 3;
	p->y = 7;
}

포인터를 통해 접근할 때 1) '간접참조(*) + 멤버 접근(.)'을 통해 접근하거나 2) '포인터->맴버'를 통해 접근할 수도 있다. 


연결 리스트

#include <stdio.h>

typedef struct list {
	int item;
	struct list* next;
} Node;

int main(void)
{
	Node a = { 1, 0 }, b = { 2, 0 }, c = { 3, 0 };
	
	a.next = &b;
	b.next = &c;

	Node* head = &a;
	Node* current = head;

	while (current != NULL) {
		printf("%d ", current->item);
		current = current->next;
	}

	return 0;
}

초기 상태는 위와 같은 형태로 각각의 Node가 독립적으로 선언되어 있다. 하지만 포인터를 연결시키면 연결 리스트와 같은 형태로  만들 수 있다.