본문으로 이동

미디어위키 1.45 안정화가 거의 끝났습니다. 다만 Flow 확장 기능 관련 이슈가 있어서 대체하는 작업을 수행할 계획입니다.

  1. 큰숲백과:청사진에서 위키 발전의 대략적인 방향성을 제시했습니다. 의견이 있으신 분은 큰숲백과토론:청사진에서 의견을 남겨주시면 좋겠습니다.
  2. 기능상의 오류로 지원하지 않고 있는 기능에 대해서는 큰숲백과토론:이슈 트래커에 요약했습니다. 참고하시기 바랍니다.
  3. 데이터베이스 덤프 받고싶으신 분은 큰숲백과 가입 후에 사용자토론:Bigforest에 의견 남겨주시면 ftp 주소, 계정, 비밀번호를 특수:EmailUser를 통해서 공개할 예정입니다.

작은숲:위키노트/초보자를 위한 C 언어 강의/구조체

큰숲백과, 나무를 보지 말고 큰 숲을 보라.

구조체(Structure)라는 것은 프로그래머가 만들어내는 새로운 데이터 형(Data type)이라고 할 수 있다. 구조체는 배열(Array)과 비슷하게 하나의 테두리 안에 여러 개의 변수들이 있는 형태이다. 예를 들어, 복소수(Complex number)를 표현하는 방법을 생각해보도록 하자. 복소수라는 것은 실수부와 허수부로 구성되어 있다. 이 복소수라는 하나의 테두리 안에 실수부와 허수부 두 개의 값이 있는 것이다. 이런 복소수를 표현하기 위해서는 두 값을 저장시킬 수 있어야 한다. 그렇다면, 하나의 복소수를 표현하기 위해 두 변수가 필요할 것이다. 하지만, 이것은 그렇게 보기 좋은 형태는 아니다.

/* 복소수 3 + 2i 를 표현하기 위해 */
int real = 3, image = 2;

이처럼 두개의 변수를 사용한다면 아무래도 이 두 변수가 하나의 값, 즉 하나의 복소수를 나타내기 위해 사용된다는 것을 나타내기가 힘들다. 아마 자기가 짠 프로그램이 아닌 이상, 쉽게 이 두 변수가 하나의 값을 표현하다고 생각하는 것은 주석을 달아두지 않는 한 알아보기 힘들 것이다. 이럴 때 사용할 수 있는 것이 구조체이다. 이 구조체라는 것은 배열과 비슷하게 하나의 테두리에 여러 개의 변수들이 들어있을 수 있다. 하지만, 배열은 같은 데이터형의 변수들의 묶음이고 인덱스를 이용해 접근할 수 있지만, 구조체의 경우는 다른 데이터 형의 여러 변수들을 하나의 묶음으로 만들 수 있고 이것으로 하나의 값을 표현할 수 있다. 그리고 구조체의 각 원소들은 '멤버'(Member)라고 부른다. 다음은 구조체 템플릿을 정의하는 것이다. 템플릿을 정의한다는 것은 한마디로 새로운 데이터 형을 만들어내는 것을 말한다. 우리가 원하는, 우리의 입맛에 맞게 기존의 데이터 형을 이용해서 새로운 데이터 형을 만들어내는 것이다. 이 구조체 템플릿을 정의함으로서 우리는 우리가 원하는 구조체 데이터 형을 만들어내는 것이다.

struct struct_tag
{    int i_member;
    float f_member;
    char c_member;
};

위에서 보인 것과 같이 구조체 템플릿을 선언하기 위해서는 먼저 struct라는 키워드를 사용한다. 이는 이제부터 구조체 템플릿을 정의하겠다는 말이다. 그리고, 다음에 나오는 것은 이 구조체 데이터 형을 대표할 이름이다. 우리는 이것을 태그라고 부른다. 그런 다음 하나의 블럭을 표현하고 안에 이 구조체에 들어갈 멤버들을 나열해 준다. 이 멤버들은 어떠한 데이터 형을 가지던지 상관 없다. 즉, 우리가 알고 있는 어떠한 데이터 형이든 올 수 있다. 심지어 구조체 자신도 들어올 수 있다. 그리고 마지막에는 ;을 찍어준다. 하나의 문장이 끝났으니 반드시 찍어야 한다. 이제 이 구조체는 세개의 멤버를 갖는다. int 형, float 형, char 형 멤버를 갖고 있다. 이 멤버들은 각각 이름을 가지고 있다. 개별 변수와 비슷하게 각 멤버들은 자신의 이름을 갖고 있다. 이렇게 구조체 템플릿을 정의한 후 실제로 구조체를 써보도록 하자. 구조체도 결국은 변수를 선언해줘야 쓸 수 있다. 다른 데이터 형과 마찬가지로 데이터 형만 가지고는 값을 저장시킬 수 없다. 어떤 값을 저장하고 활용하기 위해서는 반드시 변수가 필요하다. 구조체 변수를 선언하기 위해 우리는 다음과 같이 사용한다.

struct struct_tag struct_var;

구조체 변수를 선언하기 위해 struct 키워드와 구조체 태그를 함께 사용한다. 마지막에 나오는 struct_var은 변수의 이름이다. struct struct_tag가 하나의 데이터 형과 같은 것이다. 즉, struct_var 변수는 struct struct_tag 데이터 형을 갖는 것이다. 이것은

int i;

변수 iint 형을 갖는 것과 마찬가지이다. int와 같은 개념이 struct struct_tag이다. 여기에서 태그 자체로만으로는 아무런 일도 못한다. 앞에 struct 키워드가 함께 붙어서 이것이 데이터 형을 표현한다. 이제 구조체 변수도 선언했다. 그렇다면 구조체 안에 있는 멤버를 써먹어야 한다. 구조체 변수 자체에는 어떠한 값도 저장할 수 없다. 이것은 배열의 이름과 비슷한 개념이다. 배열의 이름은 배열 원소들의 집합을 대표하는 이름일 뿐이다. 구조체 변수도 구조체 멤버들의 묶음을 대표하는 이름이다. 결국 각각의 멤버들에 값을 저장하든지 그 멤버의 값을 읽어야 한다. 이 구조체 멤버에 접근하는 방법은 다음과 같다.

struct_var.i_member = 5;

이와 같이 구조체 변수 다음에 .을 찍고, 그 다음에 멤버의 이름을 적는다. 결국 이 말은 구조체 변수 struct_var의 멤버 i_member에 값을 저장하겠다는 것이다. 이와 같이 구조체 변수에 어떠한 값을 저장할 때는 그 변수의 멤버에 값을 저장해야 한다. 구조체도 하나의 데이터 형이므로 포인터 변수와 배열도 만들 수 있다. 구조체 포인터 변수의 경우 주의할 것이 있는데 그것은 멤버에 접근하는 방법이다. 보통 구조체 변수와는 다르게 구조체 포인터 변수의 멤버에 접근하기 위해서는 ->을 이용한다. 즉, 다음과 같다.

struct struct_tag struct_var, *p_struct;
p_struct = &struct_var;
...
p_struct->i_member = 3;

이와 같이 일반 데이터 형에서와 마찬가지로 일반 변수의 주소를 포인터 변수에 저장하고 그 값을 이용할 수가 있다. 단, 구조체 포인터 변수의 경우는 일반 구조체 변수와는 다르게 ->로 접근한다는 것만 다르다. 이제 간단한 예제를 보며 구조체에 대해 이해해보도록 하자.

#include <stdio.h>
/**
 * 구조체 템플릿을 정의한다.
 * 이 구조체는 복소수를 표현할 구조체이므로,
 * 실수부와 허수부를 저장할 두 멤버를 가진다.
 */
struct complex
{    int real;
    int image;
};
/**
 * typedef 문을 이용해서 struct complex 형을
 * Complex 형으로 정의한다.
 */
typedef struct complex Complex
/* 함수 원형 선언 */
Complex sum(Complex x, Complex y);
/* 메인 함수 시작 */
int main()
{    Complex x = { 4, -1 };
    Complex y = { -2, 4 };
    Complex z;
    z = sum(x, y);
    printf("%d + %din", z.real, z.image);
    return 0;
}/**
 * 이 함수는 구조체 complex 데이터형으로 선언된 두 변수를
 * 매개변수로 받아 적절한 계산을 한 후에,
 * 즉 두 복소수의 합을 구한 다음 결과를 구조체 변수에
 * 저장하고 그 구조체 변수를 반환한다.
 */
Complex sum(Complex x, Complex y)
{    Complex z;
    z.real = x.real + y.real;
    z.image = x.image + y.image;
    return z;
}
이 작은숲 문서의 출처는 위키노트의 위키노트: 문서입니다.