본문 바로가기
자료구조

[자료구조 3장] - 배열과 구조체(3)

by jyppro 2024. 1. 14.

배열과 구조체(3)

 

구조체

필드 : 어떤 객체를 표현하는 속성

레코드 : 필드들의 모임

구조체 : 여러 개의 레코드를 테이블로 저장하여 처리하는 관계형 데이터베이스 시스템 처럼 레코드 데이터를 위해 마련된 C 프로그램의 자료구조

 

구조체의 정의와 응용

구조체는 다양한 자료형의 연관된 자료를 묶어 새로운 자료형을 만들어 준다.

키워드 struct를 이용하여 member를 구초제 태그 이름으로 정하여 중괄호 사이에 연관된 자료를 다음과 같이 선언하면 struct member라는 새로운 타입이 생긴다.

struct member {
    int id;
    char name[20];
    float score;
};

 

구조체가 마련되었다면, 다음과 같은 선언문으로 프로그램에서 변수로 사용하게 된다.

struct member onep, exmember[20];

 

위 선언으로 1개의 레코드를 저장할 수 있는 변수 onep와 20개를 저장할 수 있는 struct member 타입의 배열 exmember를 그 안의 구성원 변수를 나타낼 수 있는 멤버 연산자(.)에 의하여 다음과 같이 사용할 수 있다.

 

구조체의 각 멤버변수에 값을 배정하는 배정문

onep.id = 2102;
strcpy(onep.name, "hong Gildong");
onep.score = 4.23;

 

구조체 배열 exmember 안의 데이터 중 성적이 4.0 이상인 학생의 id를 출력하는 문장

for(k = 0; k < 20; k++)
    if(exmember[k].score >= 4.0) printf("%d\n", exmember[k].id);

 

이와 같은 구조체는 형 정의문(typedef)에 의하여 하나의 타입으로 선언하여 사용할 수 있다. 다음 선언문에 의하여 struct member 타입은 example로도 정의되어 둘 다 같은 구조체 타입으로 사용할 수 있게 된다. 이 경우 example을 구조체 타입명으로 사용한다면 구조체 태그이름 member는 생략할 수 있다.

typedef struct member {
    int id;
    char name[20];
    float score;
} example;

 

구조체의 멤버로 중첩해서 구조체를 가질 수도 있다. 구조체 타입 date를 구조체의 멤버로 포함시켜 다음과 같은 sstruct라는 타입을 만들었다.

typedef struct {
    int year;
    int month;
    int day;
} date;
typedef struct member {
    int id;
    char name[20];
    float score;
    date eday;
} sstruct;

 

다음과 같이 struct로 선언된 변수 student는 중첩된 멤버 연산자(.)를 사용할 수 있다.

sstruct student;
student.id = 1107;
strcpy(student.name, "Kim Dokyung");
student.score = 4.21;
student.eday.year = 2021;
student.eday.month = 3;
student.eday.day = 2;

 

또한 다음에 학습하게 될 자기 자신과 같은 구조체의 포인터를 멤버로 가지고 연결리스트를 구성하는 자기참조구조체도 있다.

 

파일과 구조체의 배열

대부분의 많은 데이터는 레코드들의 모임으로 여러 형식의 파일로 제공된다. 이러한 파일에 저장된 데이터를 처리하기 위한 구조체의 배열은 자주 사용되는 자료구조이다.

ex) 테이블을 기본으로 하는 관계형 데이터베이스에서의 쿼리 처리도 구조체의 배열을 사용한다.

 

파일 안의 데이터에 적합한 구조체 타입의 정의와 파일 안의 데이터를 읽어오기 위한 구조체 배열 cdb를 다음과 같이 선언한다.

typedef struct course {
    char courseid[10];
    char tname[20];
    unsigned snum;
    unsigned roomnum;
} cinform;

cinform cdb[50];

 

파일 타입을 선언하는 방법 fopen, fscanf, fprintf의 사용법을 이해한다.

 

파일타입의 선언

FILE *fp, *coursedb;

 

함수 fopen()의 사용

파일을 열어 프로그램에서 그 파일을 다룰 수 있는 파일 포인터를 리턴해 주는 함수로, <stdio.h>에 정의되어 있다.

fopen()에는 두 개의 매개변수가 있다. 첫번째는 오픈할 파일의 위치를 알려주고, 두 번째는 이 파일이 어떤 용도로 프로그램에서 접근하는 지 알려준다.

 

다음 예시는 첫 번째 매개변수 argv[1]은 외부 인터페이스를 통하여 지정된 위치에 있는 파일을 입력용(r)으로 오픈하여 파일 포인터를 coursedb에 대입하는 문장이다.

coursedb = fopen(argv[1], "r")

 

다음은 지정된 파일 포인터 coursedb가 가리키는 파일로부터 지정된 형식의 데이터를 차례대로 읽어 EOF(End Of File)까지 배열 cdb에 저장하는 C언어 문장이다. 파일의 데이터를 읽으면서 배열 cdb의 인덱스를 하나씩 증가시키면 while문을 빠져 나올 때 i의 값이 읽은 데이터의 수가 된다.

while (fscanf(coursedb, "%s %s %u %u", cdb[i].courseid,
    cdb[i].tname, &(cdb[i].snum), &(cdb[i].roomnum)) != EOF)
    i++;

 

프로그램을 작성한다.

 

실습 프로그램

주어진 수강신청 입력파일을 구조체의 배열 cdb에 저장하고 처리하는 과정을 프로그래밍으로 익히자.

- 구조체의 배열을 이용한 파일의 처리 예

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CNUM 50

typedef struct course {
    char courseid[10];
    char tname[20];
    unsigned snum;
    unsigned roomnum;
} cinform;

void main(int argc, char *argv[])
{
    int i = 0, dnum;
    char sprof[20];
    unsigned sroomnum;
    cinform cdb[MAX_CNUM];
    FILE *coursedb;
    
    if((coursedb = fopen(argv[1], "r")) == NULL) {
        printf("데이터 파일을 열 수 없습니다. \n");
        exit(1);
    }
    
    while(fscanf(coursedb, "%s %s %u %u", cdb[i].courseid,
    cdb[i].tname, &(cdb[i].snum), &(cdb[i].roomnum)) != EOF)
        i++;
        
    dnum = i;
    
    printf("수강인원이 40명 이상인 강좌 코드 번호를 출력하시오.\n");
    for(i = 0; i < dnum; i++)
        if(cdb[i].snum >= 40) printf("%s\n", cdb[i].courseid);
        
    printf("검색하고자 하는 교수이름 입력: ");
    scanf("%s", sprof);
    printf("%s 교수가 강의하는 강좌 코드와 강의실 번호를 출력하시오.\n", sprof);
    for(i = 0; i < dnum; i++)
        if(!strcmp(cdb[i].tname, sprof))
            printf("%s\t%u\n", cdb[i].courseid, cdb[i].roomnum);
            
    printf("검색하고자 하는 강의실 번호 입력: ");
    scanf("%u", &sroomnum);
    printf("%u 강의실에서 수업하는 강좌 코드와 담당 교수를 출력하시오. \n", sroomnum);
    
    for(i = 0; i < dnum; i++)
        if(cdb[i].roomnum == sroomnum)
            printf("%s\t%s\n", cdb[i].courseid, cdb[i].tname);
    fclose(coursedb);
}

 

실행결과(임의의 데이터 파일이 있다고 가정)

수강인원이 40명 이상인 강좌 코드 번호를 출력하시오.
amath
bs01
algo03
webb
검색하고자 하는 교수이름 입력 : JYPPRO
JYPPRO 교수가 강의하는 강좌 코드와 강의실 번호를 출력하시오.
bs01    1307
algo03  1305
bs02    1307
algo04  1305
검색하고자 하는 강의실 번호 입력 : 1109
1109 강의실에서 수업하는 강좌 코드와 담당 교수를 출력하시오.
arch03    HSRLEE
arch04    HSRLEE