카테고리 없음2017. 12. 23. 01:47


구조체 배열

배열의 요소가 될 수 있는 타입에는 제한이 없다. 따라서 구조체도 배열의 요소가 될 수 


있다.

tag_Friend arJuso[10];

크기 10의 정수형 배열을 선언하는 것과 형식상 다를 바가 전혀 없다

구조체를 구성하는 멤버는 타입이 모두 다르지만 배열을 구성하는 요소는 모두 구조체라


는 같은 타입이므로 배열이 될 수 있다

배열속에 구조체가 있고 구조체 속에는 멤버들이 있다


첨자 연산자 [ ]와 멤버 연산자 .은 둘 다 1순위이고 왼쪽 우선의 결합 순서를 가지므로 


arJuso[2]가 먼저 연산되어 배열에서 2번째 구조체를 찾는다. 다음으로 멤버 연산자에 


의해 2번째 구조체의 Age 멤버를 찾을 것이다. arJuso.Age[2]=30; 이 아님을 유의하자.


반대의 경우를 보자. 구조체가 배열의 요소가 될 수 있는 것과 마찬가지로 배열도 구조


체의 멤버가 될 수 있다.

다음 코드는 Friend 구조체의 멤버인 Name 배열의 첫 번째 요소에 문자 상수 'K'를 대입


한다.

tag_Friend Friend;

Friend.Name[0]='K';

이번에는 멤버 연산자가 먼저 실행되어 Friend 구조체의 Name 멤버를 먼저 찾으며 다음


으로 첨자 연산자가 실행되어 Name 배열의 첫 번째 요소를 참조하게 된다. 


tag_Friend *pJuso[10];

★pJuso는 일단은 크기 10의 배열이되 tag_Friend형의 구조체를 가리킬 수 


있는 포인터를 배열 요소로 가진다.이 배열의 각 요소인 pJuso[0], pJuso[1], pJuso[2] 


등은 tag_Friend형의 구조체를 가리킬 수 있으며 이런놈이 10개 있다.

((((( 그림 )))))

이 상태에서 pJuso 배열에 저장된 포인터가 가리키는 구조체의 한 멤버를 참조하고 싶다


면 다음과 같이 한다.

pJuso[3]->Age=40;

[ ] 연산자가 제일 먼저 실행되어 pJuso 배열의 네 번째 요소값을 먼저 읽는데 이 값은 


tag_Friend 구조체를 가리키는 포인터이다. 이 포인터가 가리키는 곳에 저장되어 있는 


tag_Friend 구조체를 먼저 읽고 이 구조체의 멤버인 Age를 참조했다. 


#include <Turboc.h>


void main()

{

     struct tag_Friend {

          char Name[10];

          int Age;

          double Height;

     };

     // 구조체 배열 사용예

     tag_Friend arJuso[10];

     arJuso[5].Age=30;

     // 구조체에 속한 배열 사용예

     tag_Friend Friend;

     Friend.Name[0]='K';

     // 배열에 속한 구조체에 속한 배열 사용예

     arJuso[1].Name[2]='J';

     // 구조체 포인터 배열 사용예

     tag_Friend *pJuso[10];

     int i;

     for (i=0;i<10;i++) {

          pJuso[i]=(tag_Friend *)malloc(sizeof(tag_Friend));

     }

     pJuso[3]->Age=40;

     for (i=0;i<10;i++) {

          free(pJuso[i]);

     }

}

예제에서는 구조체 포인터 배열 pJuso를 초기화하기 위해 malloc 함수를 사용하여 동적


으로 할당했다. pJuso 배열의 모든 요소가 tag_Friend 구조체를 가리키도록 초기화해야 


하는데 동적 할당이 가장 쉬운 방법이기 때문이다. 동적할당된 구조체는 프로그램을 종료


하기 전에 반드시 해제해야 한다.

Posted by 넓스
카테고리 없음2017. 12. 23. 01:34

멤버연산자                                                              


구조체가 선언되어 있는 상태라면, 컴파일러는 읽으면서 각 멤버의 *오프셋과 타입을 기억한다.

멤버를 참조하라는 멤버연산자 . 을 만나면, 구조체 시작번지로부터 오프셋을 더한만큼을 이동한다. 그리고 이 위치에서 멤버의 타입 크기만큼을 읽는 기능을 수행한다.

구조체 소속일 뿐, 멤버는 일반 변수와 완전히 같다.


*오프셋(offset) :  시작 번지로부터 멤버까지의 거리

tag_People People;

People.Age = 5(임의); 라고 했을 때 과정을 그림으로.



포인터 멤버 연산자 (->)                                              


struct tag_People 

{

     char Name[10];

     int Age;

     double Height;

};

int main()

{

tag_People People;

tag_People *pPeople; // tag_People 타입을 가지는 변수(구조체's 시작박스)를 가르키는 pPeople 포인터변수.

pPeople=&People;

(*pPeople).Age=24; // People.Age=24과 같다고 할 수 있다

}

컴파일러가 코드를 해석할 때, 멤버연산자는 1순위이고 포인터 연산자는 2순위이다.

따라서 (*pPeople).Age와 같이 괄호가 반드시 포함되어야된다. 그렇지 않으면 *(pPeople.Age)로 잘못해석되기 때문이다. 

또 멤버연산자의 왼쪽에는 반드시 구조체여야하는데, 괄호가 빠지면 pPeople을 마주하게된다.  구조체가 아니라, 구조체를 가르키는 포인터기 때문에 이는 오류이다.


(*pPeople).Age의 직관적인 표현을 위해 포인터 멤버 연산자 -> 가 등장한다.

포인터 멤버 연산자(->)를 기준으로 좌변은 구조체 포인터, 우변은 멤버이름을 취한다.

(*pPeople).Age는 pPeople->Age와 동일하다.

 pPeople 이 People구조체를 가리키는 포인터이고 Age가 멤버.


Posted by 넓스
카테고리 없음2017. 12. 22. 18:57

구조체태그                                                              

태그정의란? 타입을 만들어주는 것 (사용자 정의 타입)

> 사용자 정의란 또 뭔가? int double long 과 같이 C 자체에서 주어지는 타입이 아닌 사용자가 만든 타입


■ 태그 정의하는 방법 ①


struct tag_People {

     char Name[10];

     int Age;

     double Height;

};                               // 끝에 세미콜론이 있어야 함 ,, 세미콜론을 빼먹는 실수 주의하기


태그정의(타입 생성)의 목적(왜 굳이 변수를 바로 선언안하고 타입을 생성해주는가?)

=> 이 타입으로 같은 형의 변수를 여러 번 선언할 수 있기 때문에

즉, 변수를 만들 때마다 멤버 목록을 작성해야하는 번거로움을 줄여준다.

※ struct tag_People People;           --> C형

tag_People People;                      -->C++형 

구형 C 컴파일러는 구조체 태그라는 것을 명시해주기 위해서 태그명 앞에 struct를 붙여준다.

그러나 C++ 에서는 태그 자체가 하나의 타입으로 인정되기 때문에 굳이 struct를 안붙여줘도 된다.

최근 컴파일러들은 모두 C++ 이다.


 태그 정의하는 방법 ②

typedef문을 이용하기.


typedef struct {

     char Name[10];

     int Age;

     double Height;

} PeopleType;

PeopleType People;



정리해서 한눈에보기                                                              

struct {

     char Name[10];

     int Age;

     double Height;

} People;

// 태그 정의안하고 바로 위 구조체타입의 People 변수 생성


struct tag_People {

     char Name[10];

     int Age;

     double Height;

};

tag_People People;

// 태그를 정의한것


typedef struct {

     char Name[10];

     int Age;

     double Height;

} PeopleType;

PeopleType People;

// 태그를 정의한것 (typedef이용)


1.

만약 태그정의 기능이 없었다면 구조체변수를 선언할 때마다 구조체멤버 목록을 작성해야하는 귀찮음이 따랐을 것. 

2.

태그를 정의 해놓으면, 이 타입으로부터 파생되는 유도형 변수 선언이 가능해진다.

tag_People 형의 구조체를 가리키는 포인터 변수를 선언하고 싶다거나, 이 타입의 구조체 여러 개를 모아서 배열을 구성하고 싶다면, 일단 그 구조체의 타입이 존재해야된다.

tag_People *pPeople;

tag_People arPeople[100];

포인터나 배열은 타입으로부터 유도되는 것이지 변수로부터 유도되는 게 아니기 때문에 포인터나 배열 변수를 선언하려면 먼저 구조체 타입이 태그 정의를 통해 생성되어 있어야 한다. 다른 구조체를 포함할 때도 마찬가지다.

3.

태그를 정의하지 않으면 "요렇게 요렇게 생긴 구조체를 전달하라"는 선언 자체가 불가능하다

구조체를 함수의 인수나 리턴값으로도 사용할 수 있으려면 태그정의를 해야한다.



부연설명)

사용자정의타입(태그정의)은 main함수 이전에 해야 모든 함수에서 이 타입을 사용할 수 있다.(마치 int나 double처럼)

실제로 사용자정의타입 정의는 변수선언이 아니라서, 굳이 main 함수 내에 작성하여 범위를 제한시킬 이유가 없다.

가급적 앞쪽에 선언하여, 컴파일러가 바로 인식할 수 있게끔 하기.



Posted by 넓스