[C] 구조체

C에서 구조체란?


  • 구조체는 사용자 정의 자료형이다.
  • 구조체 정의 시 struct 키워드를 쓴다.
  • 구조체 정의 끝에는 반드시 세미콜론(‘;’)을 쓴다.
  • 구조체 멤버 접근 시 도트(‘.’)연산자를 쓴다.
  • 구조체 내에 선언한 자료형들 만큼 메모리가 할당된다.

뭔가 느낌이 파이썬에서의 class랑 비슷한 느낌이 난다.

하지만 결정적 차이점이라면 파이썬에서는 self를 이용해서 선언과정에서 계산도 가능했지만
C에서는 아쉽게도 불가능하다.


구조체 선언 예시 (학생)

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

#define NAME_LEN 20 // 매크로 상수
#define PHONE_LEN 20 // 매크로 상수

struct student {
    int no;
    char name[NAME_LEN]; //한글은 한글자당 2바이트! 김성욱 저장하려면 최소 7바이트 필요!
    char phone[PHONE_LEN]; // 용도가 다르면 값이 같더라도 매크로상수는 다르게 해주자
    int score;
}; // 구조체 정의 끝에는 세미콜론을 쳐줘야한다.


이렇게 정의하면 학생이라는 자료형에 번호(no), 이름, 전화번호, 점수가 기록이 가능해진다.

이제 데이터를 저장하고 출력해보자.

void remove_enter(int len, char* in) {
    // fgets 사용으로인해 입력된 \n을 \0으로 변환하기 위한 코드
    in[len - 1] = '\0';
}

int main() {

    int a;
    struct student st1, st2; // 구조체에 대한 변수 선언

    st1.no = 1;

    printf("학번 : %d\n", st1.no);
    
    printf("이름을 입력하세요 : ");
    fgets(st1.name, NAME_LEN - 1, stdin);

    remove_enter(strlen(st1.name), st1.name);

    printf("전화번호를 입력하세요 : ");
    fgets(st1.phone, PHONE_LEN - 1, stdin);
    // gets_s함수는 \n 을 \0으로 바꿔주는 역할을 한다. gets_s를 쓴다면 remove_enter을 만들 필요가 없다.

    remove_enter(strlen(st1.phone), st1.phone);


    printf("점수를 입력하세요 : ");
    scanf("%d", &st1.score);
    
    puts("");

    //학생정보 출력
    printf("\n\n\t*** 학생정보 출력 ***\n\n");
    printf("%4s %-20s %-20s %8s\n", "번호", "이름", "전화번호", "점수");
    printf("------------------------------------\n");
    printf("%4d %-20s %-20s %8d\n", st1.no, st1.name, st1.phone, st1.score);

    return 0;
}

이렇게 하면 학생들에 대한 정보를 표로 출력할 수 있다.

여기서 잠깐,

void remove_enter(int len, char* in) {
    // fgets 사용으로인해 입력된 \n을 \0으로 변환하기 위한 코드
    in[len - 1] = '\0';
}

gets_s함수를 사용하지 못해서 fgets() 함수를 사용하고 있는데,
fgets()함수는 입력과정에서 ‘\n’ 문자까지 받아버리기 때문에 이를 없애주거나
null (‘\0’)으로 바꿔주는 작업을 해야한다. 그 기능을 하는 함수이다.

번호 이름               전화번호           점수
------------------------------------
   1 우키               010-9999-6666              95

위와 같이 코드가 출력된다.

구조체 배열


그러면 구조체가 너무 많이 입력될 때에는 어떻게 해야할까?

구조체도 하나의 자료형이기 때문에 배열로 저장이 가능하다.

#include <stdio.h>
#include <stdlib.h> //system
#include <string.h>
#define NAME_LEN 20
#define PHONE_LEN 20
#define STUDENT_NUM 5   //학생수

// typedef int SIZE_t; 자료형 재정의 (자료형의 이름으로 SIZE_t를 쓸 수 있게 됨.)
// 재정의를 하는 이유 : 조금 더 명시적으로 쓰거나 사람이 자료형의 의미를 받아들이기에 편하다.
// 또한, 자료형의 이름이 긴 경우 짧게 사용하기 위해서.

typedef struct student
{
    int no;
    char name[NAME_LEN]; //한글은 한글자당 2바이트! 김성욱 저장하려면 최소 7바이트 필요!
    char phone[PHONE_LEN]; // 용도가 다르면 값이 같더라도 매크로상수는 다르게 해주자
    int score;
}student;

여기서 typedef int SIZE_t가 나오는데, 자료형의 이름을 다시 재정의하는 것이라 생각하면 된다.

즉, SIZE_t라는 자료형이 있는데 int의 한 종류로 선언이 되는 것이다.

그리고 구조체 자료형을 배열에 사용하는데 결정적인 역할을 한다.

이렇게 한 다음에

void remove_enter(int len, char* in) {
    // fgets 사용으로인해 입력된 \n을 \0으로 변환하기 위한 코드
    in[len - 1] = '\0';
}

int main()
{
    //student st1, st2, st3, st4, st5; //구조체 변수 선언
    student s[STUDENT_NUM]; //구조체 배열
    int i;
     
    //학생정보 입력
    for(i=0; i<STUDENT_NUM; i++)
    {
        system("clear");  //화면지우기
        printf("\n\n\t\t***학생정보 입력***\n\n");
        s[i].no = 1111 + i;
        printf("학번 : [%03d]\n", s[i].no);
       
        printf("이름 : ");
        fgets(s[i].name, NAME_LEN - 1, stdin);
        remove_enter(strlen(s[i].name), s[i].name);

        printf("전화번호 : ");
        fgets(s[i].phone, PHONE_LEN - 1, stdin);
        remove_enter(strlen(s[i].phone), s[i].phone);

        printf("점수 : ");
        scanf("%d", &s[i].score);
        while (getchar() != '\n'); // scanf가 buffer가 \n을 가지고 있으면 넘어가는 것을 방지.
    }
  
    //학생정보 출력
    system("clear");
    printf("\n\n\t*** 학생정보 출력 ***\n\n");
    printf("%4s %-20s %-20s %8s\n", "번호", "이름", "전화번호", "점수");
    printf("------------------------------------\n");
 
    for(i=0; i<STUDENT_NUM; i++)
    {
        printf("%4d %-20s %-20s %8d\n", s[i].no, s[i].name, s[i].phone, s[i].score);
    }
          
    return 0;
}

student s[배열의 길이] 형태를 만들어주고
for문을 통해서 코드를 입력해주면 구현이 가능해진다.

여기서 잠깐,

  • system(“clear”) : 터미널에서 자료를 입력할 때 화면을 초기화 해주는 역할을 한다.

  • while (getchar() != ‘n’)의 역할 : scanf 함수가 정수를 받을 때 \n을 받으며 입력과정에서 오류가 발생할 수 있는데 이를 방지한다.

  • %-20s 와 같은 코드 : 길이를 맞춰서 줄맞추는 용도인데 필자의 컴파일러(VSCode)는 잘 안먹힌다.. 비주얼 스튜디오 에서는 잘 먹힌다고..

이렇게 해주고 프로그램을 실행해주면

        *** 학생정보 출력 ***

번호 이름               전화번호           점수
------------------------------------
1111 나나               010-5555-6666              99
1112 사랑해요         010-4444-4444              44
1113 마트               010-8888-8888              55
1114 해피해피         010-4234-1234              95
1115 호박고구마      010-3223-9999              66

위와 같이 결과가 잘 출력된다.


© 2022.07. by Wookey_Kim

Powered by Hydejack v7.5.2