본문 바로가기
Programming/C++

구조체와 사용자 정의 자료형2

by OKOK 2017. 7. 26.

구조체를 보다 쉽게 용이하게 사용하는 방법에 대해 이야기하겠습니다. 더욱이 구조체 이외의 사용자 정의 자료형에 대해서도 이야기 하겠습니다. 


구조체 변수의 전달과 리턴

함수 호출 시 구조체 변수를 인자로 전달하거나 리턴하는 과정에서 일어나는 모든 일은 기본 자료형 변수와 완전히 동일합니다. 구조체 변수를 함수 호출 시 전달하는 방법은 일반 변수를 전달하는 방법과 마찬가지로 두 가지 입니다. 값에 의한 전달과 레퍼런스에 의한 전달입니다. 


#include <stdio.h>


struct simple {

int data1;

int data2;

};


void show(struct simple ts);

void swap(struct simple* ps);


int main()

{

struct simple s = { 1,2 };


show(s);

swap(&s);

show(s);

return 0;

}


void show(struct simple ts)

{

printf("data1:%d, data2:%d\n", ts.data1, ts.data2);

}


void swap(struct simple* ps)

{

int temp;

temp = ps->data1;

ps->data1 = ps->data2;

ps->data2 = temp;


t선언한 함수 show는 구조체 변수를 값에 의해 전달 받습니다. 따라서 첫 번째 함수 호출 시 전달되는 변수 s 가 지니고 있는 값을, 매개 변수 ㅅts에 복사하게 됩니다. 매개 변수이자 show 함수의 지역 변수인 ts는 main 함수 내에 존재하는 변수 s와 같은 값을 지니게 됩니다. 다음으로 swap 함수는 구조체 변수의 포인터를 인자로 전달받습니다. 그리고 전달받은 구조체 변수의 멤버 값을 서로 바꿔주고 있습니다. 포인터에 의한 전달이므로 함수 내에서의 변수에 대한 조작은 실제 변수에 영향을 미치게 됩니다.


구조체 변수의 연산


기본 자료형 변수들은 사칙 연산을 비롯해서 비교 연산 등 다양한 형태의 연산이 가능합니다. 그러나 구조체 변수는 기본 자료형에 비해 제한된 연산만이 허용됩니다. 가장 대표적으로 허용되는 연산은 대입 연산입니다. 그 이외의 연산들은 (사칙 연산, 비교 연산) 적용 불가능합니다. 다음 예제는 구조체 변수의 대입 연산 결과를 보여줍니다.

#include <stdio.h>


struct simple {

int data1;

int data2;

};


void show(struct simple ts);


int main()

{

struct simple s1 = { 1, 2 };

struct simple s2;


s2 = s1;

show(s2);

return 0;

}


void show(struct simple ts)

{

printf("data1:%d, data2:%d\n", ts.data1, ts.data2);


simple 구조체의 변수 s1, s2를 선언하고 있습니다. s1은 선언과 동시에 멤버를 1, 2로 초기화 시키는 반면, s2는 초기화하지 않고 있습니다. 따라서 s2의 멤버들은 쓰레기값으로 초기화될 것입니다. s2와 s1을 가지고 대입 연산을 진행하고 있습니다. s1을 s2에 대입하는 형태입니다. 구조체 변수도 대입연산 이외에 sizeof 연산이나 포인터와 관련된 연산(*, &, ->)은 가능합니다. 


구조체 변수의 리턴

#include <stdio.h>


struct simple {

int data1;

int data2;

};


void show(struct simple ts);

struct simple getdata(void);


int main()

{

struct simple s = getdata();

show(s);


return 0;

}


void show(struct simple ts)

{

printf("data1:%d, data2:%d\n", ts.data1, ts.data2);

}


struct simple getdata(void)

{

struct simple temp;

scanf_s("%d %d", &temp.data1, &temp.data2);

return temp;


정의된 함수는 구조체 변수를 하나 선언한 후, 사용자로부터 입력받은 값을 이용해서 변수의 멤버들을 초기화합니다. 그리고 이 변수를 리턴합니다. 리턴형이 구조체 simple로 선언되어 있음을 주의합니다. 구조체 변수 s를 선언과 동시에 초기화하고 있습니다. 초기화할 대상은 getdata 함수 내에서 반환하는 구조체 변수입니다. 컴파일러는 구조체 변수 s 를 선언하고 있군, 근데 변수 s를 초기화할 대상이 와야할 장소에 함수 호출 문장이 와 있네 그렇다면 함수 호출 시 리턴되는 값을 가지고 초기화를 진행하라는 뜻이군. 따라서 컴파일후 실행 시, 첫째로 함수가 호출되고, 둘쨰로 getdata라는 함수 내에서 temp 라는 구조체 변수의 복사본이 리턴되어, 셋째로 대입 연산이 진행됩니다. 최종적으로 새로 생성되는 구조체 변수 s의 멤버 값은 리턴되는 구조체 변수의 멤버 값으로 초기화됩니다.  


지금까지 구조체 변수가 함수의 인자로 전달과 대입이 가능하고, 함수 내에서 리턴도 가능하다는 것을 이야기하였습니다. 



구조체의 유용함에 대한 두 가지 이야기

관련 있는 데이터를 하나의 자료형으로 묶을 경우, 관리하기가 편리해지고, 프로그램의 코드도 한결 간결해집니다. 구조체는 함수가 값을 리턴하는 경우, 둘 이상의 값을 동시에 리턴할 수 있는 기능도 제공을 한다. 기본적으로 함수는 한번에 하나의 데이터만을 리턴할 수 있다. 이러한 구조체의 특징은 다양한 분야에서 유용하게 사용되는데, 특히, 본인이 네트워크 프로그래밍을 공부할 기회가 생긴다면, 이러한 구조체의 특징이 얼마나 유용하게 사용되는지 알게 될 것이다. 



구조체를 포함하는 구조체


구조체를 정의할 때 멤버로서 구조체 변수를 포함하는 것을 두고 구조체가 구조체를 포함한다라고 표현한다. 구조체를 포함하는 구조체를 간략하게 중첩된 구조체라 표현한다. 


#include <stdio.h>


struct point {

int x;

int y;

};


struct circle {

struct point p;

double radius;

};


int main()

{

struct circle c1 = { 10, 10, 1.5 };

struct circle c2 = { {30, 30}, 2.4 };


printf("[circle] \n");

printf("%x:%d, y:%d\n", c1.p.x, c1.p.y);

printf("radius:%f \n", c1.radius);


printf("[circle2]\n");

printf("x:%d, y:%d\n", c2.p.x, c2.p.y);

printf("radius:%f \n", c2.radius);


return 0;


중첩된 구조체의 정의 중첩된 구조체 circle의 정의를 보여준다. 구조체 circe 내에 point 구조체의 변수가 멤버로 포함되어 있음을 확인하였나요? 물론 정의하는 순서는 예제에서 보여주듯이 point 구조체를 먼저 정의한 다음에 circle 구조체를 정의해야 합니다.