본문 바로가기
휴지통/C 프로그래밍

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

by 신재권 2021. 1. 21.

1. 구조체란 무엇인가?

구조체는 프로그램 개발에 있어서 매우 중요한 요소이다.(없어서는 안되는 요소이다).

- 구조체의 정의

'구조체(Structuer)라는 것은 하나 이상의 변수(포인터 변수와 배열포함)를 묶어서 새로운 자료형을 정의하는 도구이다. 즉 구조체를 기반으로 우리는 새로운 자료형을 정의할 수 있다. 물론 이렇게 정의되는 자료형은 기본 자료형과 그 성격에 있어서 조금만 차이가 있다.

프로그램상에서 마우스의 좌표정보를 저장하고 관리해야 한다고 가정한다. 그러면 다음과 같이 두 개의 변수를 선언해야 한다.

int xpos;

int ypos;

그런데 이 둘은 항상 함께하기 마련이다. 이 둘은 서로 독립된 정보를 표현하는 것이 아니라, 마우스의 위치라는 하나의 정보를 표현하기 때문이다. 예를 들어서 마우스의 현재 위치정보를 출력하는 함수가 있다면 이 함수는 위의 두 변수에 저장된 값을 동시에 참조해야 한다. 그리고 마우스가 움직이기 시작했다면, 그래서 마우스이 위취정보를 갱신해야 한다면, 위의 두 변수에 저장된 값이 동시에 갱신이 되어야 한다.

더 단순하게 말하면, 이 둘은 함께 있을 때 의미를 지니며, 이 중 하나가 어떠한 이유로 인해서 소멸된다면 나머지 하나도 의미 없는 변수가 되어버린다. 이러한 이유로 등장한 것이 구조체이며, 다음과 같이 구조체를 정의함으로써 두 변수를 하나로 묶을수 있게된다.

struct point{
int xpos;
int ypos;
};

위의 정의는 point라는 이름의 구조체를 정의한 결과이다. 이 때 point라는 이름이 int나 double 과 같은 자료형의 이름이 되는 것이다. 물론 이는 기본자료형은 아니다. 기본 자료형 변수를 묶어서 새로운 자료형을 만든 것이다. 그래서 이를 가리켜 '사용자 정의 자료형(User defined data type)'이라고 한다.

struct person{
char name[20];
char phoneNum[20];
int age;
}

위의 구조체의 정의에서 보이듯이 배열도 값의 저장이 가능한 , 사실상 변수의 성격을 띄기 때문에 구조체의 멤버가 될수 있다.

-구조체의 변수의 선언과 접근

앞서 point라는 이름의 구조체와 person이라는 이름의 구조체를 정의하였다. 즉 두 개의 자료형을 정의한 것이다 .따라서 이 자료형들을 대상으로 변수를 선언할 수있다. . 그리고 이렇게 선언되는 변수를 가리켜 '구조체 변수'라 한다.

struct type_name val_name; //구조체 변수선언의 기본 형태

위의 문장에서 보이듯이 구조체 변수를 선언할 때에는 맨 앞에 struct 선언을 추가해야 하며, 이어서 구조체의 이름과 구조체 변수의 이름을 선언해야 한다. 즉 앞서 정의한 point구조체의 변수 pos를 선언하고자 하는 경우에는 , 그리고 앞서 정의한 person구조체의 변수 man을 선언하고자 하는 경우에는 각각 다음과 같이 문장을 구성해야 한다.

struct point pos;

struct person man;

구조체 변수 pos에는 int형 변수 xpos, ypos가 존재하며, 구조체 변수 man에는 char형 배열 name, phoneNum과 int 형 변수 age가 존재한다. 구조체 변수안에 존재하는 멤버에 접근방법은 다음과 같다.

구조체 변수의이름. 구조체 멤버의 이름

예를 들어서 위의 구조체 변수 pos의 멤버 xpos에 20을 저장하려면 다음과 같이 문장을 구성해야 한다.

pos.xpos = 20;

유사하게 구조체 변수 man의 멤버 name에 저장된 내용을 출력하려면 다음과 같이 문장을 구성해야 한다.

printf("%s \n, man.name);

이렇듯 구조체 변수의 멤버에 접근할 때에는 .연산자를 사용한다.

무엇을 함수로 정의할 것인가?

일반적으로 처음 C언어를 접하면서 고민하게 되는 것 중 하나는 다음과 같다.

무엇을 함수로 정의할 것이며, 또 그 크기는 어느 정도로 둘것인가?

그런데 이를 공식화해서 설명하는 것은 불가능하다.

"하나의 함수는 하나의 기능을 지녀야한다"

이것이 함수의 크기를 결정짓는 최소한의 기준이 된다. 하나의 함수가 둘 이상의 기능을 지니는 경우에는 이를 두 개의 함수로 나눠야 한다.

구조체의 멤버로 배열이 선언되면 배열의 접근방식을 취하면 되고, 구조체의 멤버로 포인터 변수가 선언되면 포인터 변수의 접근방식을 취하면 된다.

위의 문장에서 말하듯이 구조체의 멤버로 포인터 변수도 선언이 가능하다.

struct person {... 생략}
int main(){
strucdt person man1, man2;
strcpy(man1.name, "안성준"); //안성준 문자열을 man1.name에 복사한다.
struct point{
int xpos;
int ypos;
}pos1, pos2, pos3;
//이는 point 구조체를 정의함과 동시에 point형 변수 pos1, pos2, pos3을 선언하는 문장이다.
=================================
struct point{
int xpos;
int ypos;
};
struct point pos1, pos2, pos3; 
//위문장과 동일하다.

-구조체 변수의 초기화

int형 변수를 선언과 동시에 초기화 할 수 있듯이 구조체 변수도 선언과 동시에 초기화할 수이있따. 그리고 초기화 방법은 배열의 초기화와 유사하다(동일하다). 즉 멤버의 순선대로 초기화할 대상을 나열하면 된다.

struct person man = {"이승기", "010-xxxx-xxxx", 23"};

초기화 과정에서는 문자열 저장을 위해서 strcpy함수를 호출하지 않아도 된다. 구조체의 멤버에 문자열을 저장하기 위해 strcpy함수를 호출해야만 했다. 하지만 초기화 과정에서는 멤버에 저장할 데이터를 단순히 나열만 하면 된다.

2. 구조체와 배열 그리고 포인터

-구조체의 배열의 선언과 접근

다수의 int형 변수를 선언할 때 int형 배열의 선언을 고려하듯이, 다수의 구조체 변수를 선언할 때에는 구조체 배열의 선언을 고려해야한다. 구조체 배열의 선언방법은 일반적인 배열의 선언방법과 동일하다.

int형 변수의 선언과 int형 배열선언의 관계가 다음과 같듯이.

int 형 변수 :int num -> int형 배열 : int arr[10];

point형 구조체 변수의 선언과 point형 배열 선언의 관계는 다음과 같다.

point형 변수 struct point pos -> point형 배열 : struct point arr[10];

point형 구조체 배열을 선언하게 되면

각 배열마다 int xpos, int ypos의 값이 들어가게된다.

접근은

arr[0].xpos

arr[i].멤버변수 로 접근하게 된다.

구조체 배열의 선언방법과 접근방법은 새로운것이 아니다.

-구조체 배열의 초기화

구조체 변수를 선언과 동시에 초기화할 떄에는 다음과 같이 중괄호를 통해서 초기화 할 값을 명시한다.

struct person man={"이승기", "010xxxx", 21};

따라서 구조체 배열을 선언과 동시에 초기화 할 때에는 다음과 같이 배열의 길이만큼 중괄호를 이용해서 초기화를 진행하면 된다.

struct person arr[3]= {

{ "이승ㄱ ㅣ ~~~},

{ ~~~~},

{~~~~}

};

-구조체 변수와 포인터

구조체 배열의 선언 및 접근 방법이 일반적인 배열의 선언 및 접근 의 방법과 다르지 않듯이, 구조체 포인터 변수의 선언 및 연산의 방법도 일반적인 포인터 변수의 선언 및 연산의 방법과 다르지 않다. 즉 다음과 같이 int형 포인터 변수를 선언하고 초기화하듯이

int num=10;

int *ptr = #

point형 구조체의 포인터 변수도 다음과 같이 선언하고 초기화 한다.

struct point pos= {11, 12};

struct point *pptr =&pos;

그리고 위의 int형 포인터 변수 ptr을 이용하여 다음과 같이 변수 num에 접근 하듯이

*ptr =20;

위의 point형 포인터 변수 pprt을 이용해서 다음과 같이 구조체 변수 pos에 접근할 수 있다.

(*pptr).xpos =10;

(*pptr).ypos=20;

접근을 위해서 포인터 변수 대상으로 *연산을 하는 것은 동일하다. 다만 구조체 포인터 변수의 경우 접근하고자 하는 멤버의 선택을 위해서 . 연산을 추가로 했을 뿐이다. 그리고 위의 두문장은 다음과 같이 쓸수도 있다.

pptr->xpos =10;

pptr->ypos =10;

즉 *연산과 .연산을 하나의 ->연산으로 대신할 수 있는 것이다. 물론 의미도 100% 동일하다.

pptr->xpos +=1; / /pptr이 가라키는 변수의 멤버 xpos의 값을 1증가

-포인터 변수를 구조체의 멤버로 선언하기

배열이 구조체의 멤버로 선언될 수 있듯이, 포인터 변수도 구조체의 멤버가 될 수 있다.

type형 구조체 변수의 멤버로 type형 포인터 변수를 둘 수 있따.

즉 다음과 같은 선언이 가능한 것이다.

struct point{

int xpos;

int ypos;

struct point *ptr;

}

위를통해 세점의 연결관계도 표현이 가능하다.

-구조체 변수의 주소 값과 첫 번쨰 멤버의 주소값

구조체 변수의 주소값은 구조체 변수의 첫 번째 멤벌의 주소 값과 동일하다.

'휴지통 > C 프로그래밍' 카테고리의 다른 글

파일 입출력  (0) 2021.01.23
구조체와 사용자 정의 자료형2  (0) 2021.01.22
문자와 문자열 관련 함수  (0) 2021.01.21
함수 포인터와 void 포인터  (0) 2021.01.21
다차원 배열과 포인터의 관계  (0) 2021.01.21