[DataStructure] 자료구조를 위한 C언어 - 구조체

ego2·2022년 11월 19일
0
post-thumbnail

구조체


배열은 서로 같은 타입의 데이터를 묶는다면 구조체는 타입이 다른 데이터를 묶는 방법이다.

정의 및 선언


구조체의 멤버에 접근 하기 위해서는 멤버 참조 연산자(.)을 이용한다.

#include <stdio.h>
#include <string.h>

struct person{
	char name[10];
    int age;
    float height;
};

// 구조체 변수 선언
struct person a;

int main(){
    struct person a;
    strcpy(a.name, "tom");
    a.age = 20;
    a.height = 180.5;

    printf("%s %d %lf",a.name, a.age, a.height);

}

결과 : tom 20 180.500000

멤버 하나씩 초기화 할 경우 번거롭기 때문에 중괄호({})을 이용해 초기화 하는 방법도 있다.

struct person a = {.name = {"홍길동"}, .age = 24, .height = 180};
struct person a = {"홍길동", 24, 180};

구조체의 대입과 비교 연산


#include <stdio.h>
#include <string.h>

// 구조체 정의
 typedef struct person{
	char name[10];
    int age;
    float height;
} person; 

// 구조체 대입 검사 프로그램
void main(){
	person a = {"홍길동,", 24, 180};
    person b;
    
    
    b = a; // 하나의 구조체 변수의 내용을 다른 구조체에 대입할 수 있는지 여부 -> 가능

    printf("%s %d %lf ",b.name, b.age, b.height);
}

void main(){
	person a = {"홍길동,", 24, 180};
    person b = {"고길동", 30, 175};
    
    if(a>b){
        printf("A가 B보다 크다\\n");    //구조체 변수끼리 비교 => 불가능
                                      //구조체 멤버 변수 끼리 비교 => 가능
    }
}
  • 구조체 변수를 다른 구조체 변수로 대입 ⇒ 가능
  • 구조체 변수와 다른 구조체 변수를 비교 → 불가능
  • 구조체 멤버 변수 끼리 비교 ⇒ 가능

typedef을 이용한 구조체 선언


구조체 선언 할 때 sturct 구조체이름 {구조체 멤버 }; 형태로 선언하고 main함수 내에서 struct [구조체 이름] [변수 이름] 과 같이 선언

하지만 더 편리한 방법이있다. typedef 키워드를 사용해 구조체 이름을 생략 할 수 있다.

typedef 키워드는 C언어에서 자료형을 새로 정의 할 때 사용하는 키워드이다. typedef를 사용하면 main함수에서 구조체를 선언 할때 매번 struct 를 써줄 필요가 없다. typedef를 이용하면 구조체 별칭이 필요한데, 구조체 별칭은 구조체 정의 할 때 중괄호 뒤에 써주면 된다.

익명구조체 : typedef을 사용하면 구조체 이름을 생략 가능하다. 별칭만 사용하고 구조체 이름을 생략 할 수 있다.

typedef 사용 전

#include <stdio.h>

struct name
{
    char first[30];
    char last[30];
};

struct friends
{
    struct name friend_name;     //구조체 중첩
    char address[30];
    char job[30];
};

int main(){
    struct friends hong = {"길동", "홍", "서울시 강남구 역삼동", "학생"};

    printf("%s\\n\\n", hong.address);
    printf("%s%s\\n", hong.friend_name.last, hong.friend_name.first);
    
    return 0;
}

typedef 사용 후

#include <stdio.h>

typedef struct 
{
    char first[30];
    char last[30];
}name;

typedef struct 
{
    name friend_name;
    char address[30];
    char job[30];
}friends;

int main(){
    friends hong = {"길동", "홍", "서울시 강남구 역삼동", "학생"};

    printf("%s\\n\\n", hong.address);
    printf("%s%s\\n", hong.friend_name.last, hong.friend_name.first);
    
    return 0;
}

자체 참조 구조체


자체 참조 구조체(self-referential structure) : 특별한 구조체로 구성 요소 중에 자기 자신을 가르키는 포인터가 한개 이상 존재하는 구조체를 말한다.

왜 사용할까

  • 연결 리스트 or 트리를 구성할 때 사용
  • 항목의 개수를 미리 예측할 수 없는 경우 자체 참조 구조체를 정의해 놓고 동적으로 기억장소를 할당 받아 이들을 포인터로 연결하여 자료구조를 구성
struct list
{
    int data;
    struct list* next;
};

자기 참조 구조체에서 next와 같이 자기 자신의 구조체를 가르키는 포인터 변수를 링크(link)라고 한다.

자기 자신의 구조체를 가르치는 Next포인터를 통해 연결을 해보자

#include <stdio.h>

// 구조체 정의
typedef struct list{
    int data;
    struct list *next;
}list;

void main(){
    list a, b, c;

    a.data = 1;
    b.data = 2;
    c.data = 3;

    a.next = &b;
    b.next = &c;
    c.next = NULL;

    printf("%d\\n", a.data);
    printf("%d\\n",a.next->data);
    printf("%d\\n", a.next->next->data);
}

위와같이 자기 참조 구조체가 링크를 통해 차례로 연결되어 만들어진 구조를 연결 리스트(linked list)라 한다. 연결 리스트를 이루는 각 구조체를 노드(node)라고 한다.

반복문을 이용해 노드의 값을 출력하기

#include <stdio.h>

// 구조체 정의
typedef struct list{
    int data;
    struct list *next;
}list;

void main(){
    list a, b, c, d;

    list *head;  //맨처음을 가르키는 구조체가 무엇인지 저장하는 구조체 

    head = &a;  //맨 처음 구조체인 구조체의 시작 주소 값
    a.data = 1;
    b.data = 2;
    c.data = 3;
    d.data = 4;

    a.next = &b;
    b.next = &c;
    c.next = &d;
    d.next = NULL;

    while(head){
        //head의 뜻=> "만약 head값이 NULL이 아닐경우 계속 반복"

        printf("%d\\n", head->data);

        head = head -> next;    //head를 다음 포인터의 주소를 저장하는 next값으로 바꿈
    }
}

구조체 크기에 대하여


일반적으로 구조체 크기는 멤버 변수들의 크기에 따라 결정된다. 그러나 구조체의 크기가 언제나 멤버 변수들의 크기 총합과 일치하는 것은 아니다.

why? 구조체안 변수들은 연속된 공간을 가지는데 구조체를 메모리에 할당할 때 컴파일러는 프로그램의 속도 향상을 위해 바이트 패딩(byte padding)이라는 규칙을 사용하기 때문에

바이트 패딩 : 메모리의 접근을 쉽게 하기 위해 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞춘다. 이것을 바이트 패딩이라고 하며, 이때 추가되는 바이트를 패딩 바이트(padding byte)라 한다.

#include <stdio.h>

typedef struct
{
    char a;
    int b;
    double c;
}TYPESIZE;

int main(){
    puts("구조체 TypeSize의 각 멤버 크기는 다음과 같습니다.");
    printf("%d %d %d\\n", sizeof(char), sizeof(int), sizeof(double));

    puts("구조체 TypeSize의 크기는 다음과 같습니다.");
    printf("%d\\n", sizeof(TYPESIZE));

    return 0;    
}

double형 타입의 크기가 가장 크므로 8byte가 기준이 된다.

맨처음 char 형 멤버 변수가 8byte에 할당되고 int형 멤버 변수가 할당된다.

마지막 double형 멤버 변수는 8byte인데 남은 공간은 3byte이므로 다시 8byte가 할당 된다.

1byte와 4byte가 할당되고 남은 3byte가 패딩 바이트(padding byte)가 된다.

references


profile
Talk is cheap. Show me the code.

0개의 댓글