C 프로그래밍 입문/구조체와 유니온 데이터: 두 판 사이의 차이

내용 삭제됨 내용 추가됨
Joshuajh (토론 | 기여)
(차이 없음)

2010년 10월 29일 (금) 17:15 버전

구조체와 유니온 데이터

구조체를 설명하기 위해, 성적표를 출력하는 프로그램을 작성하는 과정을 생각해 보자. 한 사람의 성적 데이터라는 것은 실제로 여러 정보를 포함한다. 성적표에 들어가는 정보는 학생의 이름, 학년, 반, 번호, 각 과목의 점수, 총점 그리고 평균 등이 될 것이다. 실제로 프로그램을 작성할때 이러한 성적표를 출력하는 프로그램을 만들때 한 반의 정보 전체를 넘겨 받아서 각 사람의 정보를 성적표로 출력해주는 프로그램을 만드는 것 보다. 한 사람의 정보를 받아서 프린터로 인쇄하는 프로그램을 만든 후 다시 그 프로그램으로 반 전체의 성적 리스트 중에 인쇄하려는 사람의 성적표 정보를 뽑아서 넘겨주는 프로그램 두 개를 만드는 편이 개념적으로도 이해하기 쉽고 나중에 프로그램을 변형해야 하더라도 좀 더 쉽게 작업을 할 수 있게 될 것이다. 이 경우, 정수를 저장할 수 있는 데이터 타입이 있는 것 처럼 한 사람의 정보를 저장할 수 있는 데이터 타입이 있다면 프로그램을 작성 할 때에도 편리 할 것인데, 이렇게 관계있는 데이터들을 하나로 묶어서 관리할 수 있도록 제공해주는 자료 구조가 바로 '구조체와 유니온'이다. 구조체와 유니온은 사용되는 개념에서 약간의 차이가 있지만 기본적인 개념의 시작은 동일하고, 유니온에는 구조체가 갖는 특성 위에 다른 특성이 부가 된다.[1]

구조체 (Structure)

C 스펙에 있는 구조체의 정의는 '동일하지 않은 데이터 타입을 갖는 일련의 데이터의 집합'이다. 그에 비해 배열의 정의는 '동일한 데이터 타입을 갖는 일련의 데이터의 집합' 이다. 두 정의에 들어있는 '일련의(sequential)'이란 단어의 의미는 '연달아 놓여있는'의 의미 이다. 위에서 배열의 정의에 관해 정확하게 이해 했다면 '연달아 놓여있는 데이터의 집합'이라는 말의 의미를 정확하게 이해할 수 있을 것이다.구조체는 배열과 마찬 가지로 데이터들이 연달아 놓여 있는데 배열과의 차이점 이라면 구성 요소가 되는 데이터의 타입이 다르다는 말이다. 여기에서 '변수'의 정의를 다시 한 번 기억해 보도록 하자. 변수는 '메모리 공간'이었고, 배열은 같은 종류의 변수가 여러개가 메모리상에 연달아 존재 한다. 배열의 특성상 같은 종류의 메모리가 여러개 연달아 놓여있기 때문에 배열 내 n 번째 메모리 공간을 사용하고 싶으면 '(n - 1) * 배열내 요소 하나의 크기'라는 간단한 계산식으로 사용하고자 하는 메모리 공간의 주소를 얻을 수 있기 때문에 배열에서는 인덱스(index)라는 개념을 이용해서 배열 멤버를 다룰 수 있었다. 그러나 구조체의 경우에는 '동일하지 않은 데이터 타입'이라는 전제 조건이 있기 때문에 구조체 내의 멤버를 다루기 위해 멤버가 위치하는 메모리내 위치를 계산하기 위해서는 위에서 배열내 멤버의 위치를 계산하는 방법을 사용할 수 없다. 그렇기 때문에 구조체는 인덱스가 아닌 멤버의 이름을 일일히 지정하고 그 이름을 사용하는 방법을 사용한다.

다음은 구조체를 사용하는 프로그램의 간단한 예 이다.

#include <stdio.h>
struct articles_type {
    int korean, english, math;
};

structure score_card_type {
    int year, grade, seq;
    struct articles_type scores;
    int total;
    double average;
};

int print_a_scorecard (struct score_card_type sc) {
    printf ("%2d 학년 %2d 반 %3d 번\n", sc.year, sc.grade, sc.seq);
    printf ("=========");
    printf ("국어: %4d    영어: %4d    수학: %4d\n", sc.scores.korean, sc.scores.english, sc.scores.math);
    printf ("총점: %5d   평균: %5.1f\n", sc.total, sc.average);

    return 0; 
}

int main (int argc, char *argv[]) {
   structure score_card_type a_student;

   /*  여기에 전체 데이터 베이스에서 한 학생의 성적을 추출해 내는 프로그램 코드가 있다고 가정 합니다.
       나중에 포인터를 배운 후에 이해될 수 있는 부분이기 때문에 이 내용은 잠시 비워둡니다. */

    print_a_scorecard (a_student);

    return 0;
}

구조체를 사용하기 위해서는 구조체의 형태를 먼저 정의하고, 정의된 형태의 구조체 타입의 변수를 만들어서 사용한다. 좀 다른 표현으로 설명하자면, 여러개의 데이터가 들어가는 새로운 변수의 타입을 하나 만든 다음에 그 타입의 변수를 만들어서 사용한다.[2] 배열의 경우 동일한 타입의 변수가 반복되는 것 이기 때문에 다로 그 내용에 대한 타입을 별도로 정의해 줄 필요가 없지만, 구조체의 경우에는 포함되는 데이터의 타입이 다르다는 전제가 있으므로 먼저 어떤 내용이 들어갈지를 정의해 주는 작업을 거쳐야 한다. 위의 코드를 보면 2번 라인에서 11번 라인까지의 프로그램 코드에 구조체의 구조를 정의 했다(혹은 struct articles_type 타입과 struct score_card_type 타입을 만들었다). 그리고 23번 라인에서 struct score_card_type 타입의 변수를 하나 만든 것 이다.

위 코드에서 주의할 점이 두 가지가 있는데, 첫째, 구조체의 끝에는 반드시 세미콜론(;)을 찍어 주어야 한다. 아직 설명되지 않았지만 구조체의 닫힘 중괄호(}) 다음에는 생략 가능한 내용이 있으며(실제로 위의 프로그램에서는 두 구조체 모두 생략했다), C 컴파일러는 그 생략가능한 내용이 생략된 것 인지 아닌지 확인할 방법이 없기 때문에 중괄호 다음에 더이상 내용이 없다면 반드시 세미콜론을 찍어서 문장이 더 이상 없다는 것을 표시해 주어야 하는 것 이다. 둘째, articles_type과 score_card_type은 변수 이름이 아니고 타입 이름의 일부 일 뿐이다. 많은 초보 C 프로그래머들이 쉽게 실수하는 내용이므로, 아무리 당연하다고 생각 되어도 헷갈리지 않도록 주의할 필요가 있다.

만들어진 구조체 변수내의 멤버를 액세스 하는 방법은 구별자인 마침표(.;dot, full stop)를 이용한다. 기본 형태는 '구조체변수.멤버변수'의 형태와 같이 구조체변수와 그 멤버이름 사이에 점을 찍음 으로서 두 변수가 포함 관계에 있음을 표시해 준다. 위 프로그램의 8번 라인을 보면 struct subjects_type scores 라는 구조체 멤버 변수를 볼 수 있을 것이다. 이 샘플 코드에서 볼 수 있듯이 일단 한번 만들어진 구조체는 그 자체로도 하나의 데이터 타입으로서 다루어 지므로 다른 구조체의 멤버 변수로 선언 될 수 있다. 구조체 변수 내의 구조체 멤버의 멤버를 액세스 할 때도 동일한 방법을 반복하여 사용해 주면 된다. 16번 라인을 보면 sc.scores.korean 라는 변수를 볼 수 있는데, 이는 'sc구조체 변수 내 멤버 구조체 변수인 scores의 멤버 변수 korean'이라는 의미로 액세스 하게 된다. 다차 배열에서 단순한 규칙을 이용해 다차 변수를 액세스 했듯이 다중 구조의 구조체(nested structure)를 액세스 할 때역시 기본 구조체 액세스 방법을 반복해 줌으로서 포함되어 있는 구조체 변수의 멤버 변수를 액세스 할 수 있다.

구조체 타입의 변수 역시 변수 임에는 변함이 없으므로 기본형의 데이터타입을 배열로 만드는 것과 같은 방법으로 구조체의 배열 역시 만들 수 있다. 다음 코드는 한반에 최대 60명까지 있을 수 있는 반 전체 성적표 데이터를 저장할 수 있는 배열의 선언이 된다.

 struct score_card_type a_class[60];

위와 같이 선언된 구조체 배열은 일반 배열과 동일하게 액세스 할 수 있으며, 배열내 n번째 구조체 변수의 멤버 변수를 액세스 하는 방법에 대해서는 해당 구조체 변수 배열이 메모리에 저장되어 있는 방식을 잠시 생각해 보면 쉽게 유추해 볼 수 있을 것이다. 전체 구조를 컨테이너라 가정한다면 가장 외부의 컨테이너는 배열이 된다. 그러므로 배열 컨테이너에 있는 구조체 변수 컨테이너 하나를 꺼낸 다음, 다시 구조체 안에 있는 내용물인 변수를 끄집어 내 주면 되는 것 이다.


아래 내용을 설명할 샘플 코드가 여기에 삽입 됩니다. 여기에 구조체를 선언함과 동시에 구조체 타입이름의 정의 없이 변수를 정의하는 방법에 대해 설명할 계획입니다.

아래 내용을 설명할 샘플 코드가 여기에 삽입 됩니다. 여기에 구조체 선언문 안에 다른 구조체 선언이 포함될 수 있다는 점을 설명합니다.

!포인터를 이용한 구조체 멤버 액세스 방법에 대해서는 포인터에서 설명할 것 입니다!

유니온 (Union)

주석 및 참고자료

  1. 실제로 구조체와 유니온 이라는 개념은 객체지향 언어에서의 객체 개념이나 데이터의 다형성 개념의 뿌리가 되는 개념 이기도 합니다.
  2. 실제로 정수형, 실수형등의 데이터 타입을 기본형(base type)이라고 부르고 배열, 구조체, 유니온 등을 딜리버드 타입(delivered type;유도형 이라는 표현을 사용하는 경우도 있습니다.)혹은 사용자 정의 타입(user define type)이라고 부릅니다.