728x90
반응형

구조체

  • 구조체

구조체란 하나 이상의 변수를 묶어서 새로운 자료형을 정의하는 도구이다. 예를 들어, 기존의 자료형과 별개로 3바이트짜리 자료형을 만들어내는 것, 이러한 예처럼 새로운 자료형을 기본 제공 자료형으로 추가하는 것은 불가능 하지만 기존의 자료형들을 이용하여 생성하는 변수들을 묶어서 새로운 자료형을 정의하는 것은 가능하다.

다음은 이름과 학번을 저장하는 새로운 자료형을 정의한 예를 나타낸 것이다.

학생을 관리하는 시스템에서는 학번과 이름은 함께 처리되어야 의미가 있는 자료들이다. 그렇기 때문에 위와 같이 학생의 이름을 나타내는 name 변수와 해당 이름의 학생의 번호를 의미하는 stdNum을 한데 묶어서 관리할 수 있도록 새로운 자료형을 정의한 것이다.

 

  • 구조체의 정의

구조체의 정의는 다음과 같다

왼쪽은 구조체의 정의를 나타낸 것이다. 오른쪽의 예는 구조체를 정의한 예인데, 20 바이트 문자형 배열과, 4바이트 정수를 저장할 수 있는 변수들로 구성되어 있는 PersonalInfo라는 자료형을 하나 새로 만든 것이다. PerosonalInfo라는 자료형은 int, float, double 등처럼 자료형의 이름이 될 수 있다. 이 이름을 통해서 사용자 정의 자료형 변수를 만들게 되는 것이다.

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

구조체 변수의 선언

 

정의한 사용자 정의 자료형(구조체)을 통해 변수를 선언하는 방법은 왼쪽과 같다. 그리고 오른쪽 13, 14번 라인은 구조체 변수를 선언한 예를 나타내고 있다.

 

구조체 변수를 통한 멤버 변수 직접 접근과 간접 접근

선언된 구조체 변수를 통해 멤버 변수에 접근할 수 있다. 아니, 해야만 한다. 그러기 위해 만든 구조체이기 때문이다.

왼쪽과 같이 구조체 변수 이름과 ‘ . ‘ (직접 접근 연산자)와 멤버 변수의 이름을 명시함으로써 구조체의 멤버 변수에 직접 접근하여 값을 넣거나 값을 출력 혹은 수정까지 할 수 있다.

위의 예에서는 16번 라인과 17번 라인을 통해 멤버 변수에 접근하고, 대입 및 다른 곳으로의 참조를 시키는 등의 작업이 이루어진다. 중요한 것은 구조체_변수_이름 . 구조체의 멤버 변수 형식을 갖추어 직접 접근한다는 것.

구조체(사용자 정의 자료형) 또한 일반 자료형과 같은 취급을 하기 때문에 포인터로 선언하고 주소 값을 받는 모든 행위들은 허용된다. 다음의 예가 가능하다.

위의 예에서 13번 라인에서 일반 구조체 변수를 선언하고, 15번 라인에서는 구조체 포인터 변수를 선언한다. 그리고 나서 16, 17번 라인을 통해서 직접 접근 연산자 ‘.’을 이용하여 구조체 멤버에 직접 접근을 통해서 값을 대입한다. 그리고 19번 라인에서 구조체 변수에 기존에 선언했던 일반 구조체 변수의 주소 값을 대입한다. 중요한 것은 21번 라인의 참조 방식인데, ‘->’(간접 접근 연산자)를 통해서 접근하는 형태를 볼 수 있다. 이렇듯 구조체 포인터 변수를 통해서 가리키고 있는 변수의 멤버에 접근할 때에는 간접 접근 연산자(->)를 통해서 접근한다. 이를 간접 접근 이라고 한다.

참조를 통한 직접 접근 또한 가능하다.

22번 라인과 같이 구조체 포인터가 가리키는 대상에 대해서 접근 연산이므로 직접 접근 연산이 맞다. 포인터를 이용해서 참조한 후 직접 접근 연산자를 통해 멤버에 접근할 수 있는 방법이 제시된 예이다.

 

 

  • 구조체 변수의 초기화

생성과 동시에 초기화

배열의 초기화와 매우 유사하다.

5번 라인에 해당하는 구조체 정의를 두고, 13번 라인에서 구조체 변수를 선언하면서 생성과 동시에 초기화를 진행하고 있는데 그 초기화 방식은 다음과 같다.

중괄호로 감싼 후, 초기화할 값들을 콤마 연산자를 통해 구분하며 나열하는데 구조체 정의 시 멤버 변수의 선언 순서대로 나열을 한다.

 

일반 초기화(값의 대입)

다음의 예와 같이 선언 이후에 값의 대입을 통하여 초기화를 진행할 수 있다.

  • 구조체 배열

구조체 배열 또한 일반 변수의 배열과 마찬가지로 다를 바가 없다. 다음은 이전의 예제를 조금 변형한 구조체 배열에 대한 예제이다.

먼저, 15번 라인에서 구조체 배열을 선언한다. 두 명의 학적 정보를 저장할 수 있도록 배열로 선언한다. 그런데 배열을 선언과 동시에 초기화를 이루고 있다. 이 경우 2차원 배열의 초기화와 크게 다를 바가 없다. 구조체 정의 시 나열한 멤버 변수의 순서대로 값들을 나열하고, 그러한 나열을 행 별로 다시 구분 지어 나열한다. 그리고 20번 라인에서는 선언만 이루어졌고, 22~ 26번 라인에서 대입을 통한 초기화가 이루어지고 있다. 그리고 29번 라인부터는 인덱스를 이용하여 구조체 배열의 각 요소들을 출력하는 것을 볼 수 있다.

 

  • 구조체 포인터 및 구조체 첫 멤버 변수의 주소 / 구조체 변수의 주소 / 구조체 이름

구조체 포인터 또한 일반 변수의 포인터와 다를 바가 없다. 다만 다른 부분은 아래에 제시한다.

위의 결과로 미루어 보았을 때 구조체의 첫 멤버 변수의 주소와 구조체 변수의 주소는 같지만 구조체 이름은 다른 것임을 알 수 있다. (배열 이름과는 다름)

 

l  구조체와 typedef 연산을 통한 자료형 재정의

Typedef 는 자료형을 다른 이름으로 재정의하는 연산자이다. 다음과 같은 형식으로 재정의를 진행한다.

typedef 기존_자료형 새로운_자료형_이름;

다음은 기존 자료형을 통한 자료형 재정의의 예이다.

11, 12번 라인에서 int 자료형과 char 자료형에 대해서 새로운 이름으로 재정의가 일어났다.

다음으로는 사용자 정의 자료형에 대해서 typedef 연산을 통해 재정의가 일어난 몇 가지 경우를 표현했다. 아래에서 제시하는 모든 경우에 대한 결과는 다음과 같다.

14번 라인과 같이, 일반 자료형을 통한 변수 선언 하듯, struct 키워드를 포함하지 않더라도 구조체 변수의 선언이 가능하다. 밑에서 11번 라인에 들어가는 다양한 경우의 typedef 선언을 제시.

 

  • 함수 구조체 인자 전달

 

  • 구조체를 대상으로 가능한 연산

구조체 변수를 대상으로 하는 연산은 제한적으로 대입(=), sizeof, 주소(&) 연산만이 허용된다. 특히 구조체의 변수 간 대입 연산을 진행하게 되면 멤버 대 멤버의 복사가 이루어진다.

15번 라인에서 대입 연산을 진행하고 있고 그 결과, pi1pi2의 멤버들이 지니는 값은 모두 같은 것으로 미루어 보았을 때, 값의 복사가 이루어지고 배열의 경우에도 모조리 값의 복사가 일어나는 것을 확인할 수 있다.

  •  구조체의 정의 이유와 중첩된 구조체의 선언

구조체의 정의가 필요한 이유

구조체를 통해서 연관 있는 데이터를 하나로 묶을 수 있는 자료형을 정의하면, 데이터의 표현 및 관리가 용이해지고, 합리적인 코드를 작성할 수 있다.

구조체를 정의하지 않고 구현한 경우 문제가 되는 점 : 인자 전달 시 매개 변수가 늘어남, 묶어서 하나의 인덱스에 대해서 관리가 불편해짐. 높은 차원의 배열이 계속 생성됨.

 

중첩된 구조체의 정의와 변수 선언

구조체 내에 구조체 변수를 선언할 수 있다. 이때 초기화 할 경우에는 순서에 주의하고, 중첩된 구조체 변수에 대한 초기화 시 중괄호를 통해 구분한다.

  • 공용체(union)

공용체는 구조체와 유사한 개념이긴 하나, 다른 점은 멤버 변수들이 하나의 공간을 공유하는지의 차이가 있다.

위의 예제는 구조체와 공용체의 차이를 나타내는 예제이다. 공용체의 정의나 선언 방법은 구조체와 완전히 똑같다고 보면 된다. 그러나 차이는 24~ 28번 라인에서 볼 수 있다.

24번 라인에서는 구조체의 멤버의 각 주소 값을 출력하는데 결과를 보면 자료형 별 차이만큼 주소 값이 잘 할당되어 있는 것을 확인할 수 있는데 25번 라인에서 공용체의 멤버의 각 주소를 출력하는데 결과를 보니 모두 같은 주소(공용체의 시작 주소) 값을 가지고 있었다. 게다가 이상한 것은 이 뿐만이 아니다. 27번 라인에서 sData의 크기는 멤버 변수들의 메모리 공간 할당 크기들을 합한 결과 값이 나오는데, uData의 크기는 멤버 변수 중 가장 할당 크기가 큰 자료형의 길이 값이 나왔다.

< 구조체 멤버 변수의 할당 구성 >
< 공용체 멤버 변수의 할당 구성 >

위의 그림은 구조체와 공용체의 멤버 변수들의 할당 구성을 나타낸 것이다. 굵은 검정 칸이 실제로 할당된 메모리 공간이 된다. 구조체 할당 구성에서는 각 멤버 변수 별로 크기만큼 할당이 되어 있는 것을 볼 수 있는데 공용체 할당 구성에서는 가장 큰 double 자료형의 크기만큼만 공간을 할당하고 모든 멤버 변수가 이 공간을 공유하는 형태로 할당 구성이 이루어진다.

이러한 공용체는 다음과 같은 예제에서 유용하게 사용될 수 있다.

 

정수 하나를 입력 받고, 입력 받은 정수의 상위 2바이트와 하위 2바이트의 값을 양의 정수로 출력하고, 상위 1바이트와 하위 1바이트에 저장된 아스키 문자 출력하기

 

  • 열거형

구조체나 공용체는 자료형을 명시함으로써 멤버에 저장할 값의 유형(type)을 결정하였다면, 열거형의 경우는 저장이 가능한 값 자체를 정수의 형태로 결정한다.

0, 1, 2, 3, 4, 5, 6 값들을 저장 가능한 color형 자료형

Color 자료형으로 선언되는 모든 변수들은 enum Color 정의에서 정의해 둔 상수들을 값으로 갖을 수 있다. 또한 정의된 상수들은 어디서든 지역 범위를 고려하여 사용할 수 있다. enum 정의 및 변수 선언은 구조체, 공용체와 완전히 똑같다. 그리고 상수 정의 시, 어떤 값도 넣지 않으면 순서대로 0 값부터 값이 1씩 올라가는 형태로 값의 배정이 이루어진다.

다음의 예에서 특이한 점을 발견할 수 있다.

위에서는 정의된 상수들에서 RED에 값을 지정하지 않았으므로 0부터 시작하는데 YELLOW10이라는 값을 지정했다. 그리고 그 결과 YELLOW 이후 부터는 10부터 1씩 증가한 값들로 배정된다.

열거형은 위와 같이 활용될 수 있다.

열거형의 유용함은 이름있는 상수의 정의를 통한 의미의 부여에 있다. 둘 이상의 연관이 있는 이름을 상수로 함께 같이 묶어서 선언함으로써 프로그램의 가독성을 높인다.

728x90
반응형

'컴퓨터 언어 정리 > C 언어' 카테고리의 다른 글

18 동적 메모리 할당  (0) 2020.10.15
17 파일 입출력  (0) 2020.10.13
15 문자와 문자열  (0) 2020.09.29
14 함수 포인터와 void 포인터  (0) 2020.09.23
13 다차원배열 및 포인터의 관계  (0) 2020.09.21

+ Recent posts