013. STRUCTURE

Posted on by pkchan

변수의 자료형, 같은 자료형 변수의 모임인 배열에는 한계가 있습니다. 배열에 모인 변수들은 모두 자료형이 같아야 합니다. 이름(string), 나이(int), 키(int), 몸무게(double)가 모인 배열은 불가능합니다. 이것을 가능하게 해주는 것이 구조체입니다. 구조체는 사용자 정의 자료형으로 최상단에 자료형을 정의해야 합니다.

013-01 // STRUCTURE DEFINITION

struct structure_name {
	
          data_type member1;
          data_type member2;
          .
          .
          data_type member;
          
};

구조체를 정의하는 부분에서 구조체에 포함된 변수는 멤버라고 부르며, 바로 초기화할 수 없습니다. 그리고 정의가 끝나면 세미콜론을 붙여줘야 합니다.

013-02 // STRUCTURE VARIABLE DECLARATION

구조체가 정의되었다면 사용자 정의 자료형을 만든 것입니다. 구조체 변수를 선언하기 전까지는 메모리에 할당되지 않습니다. 구조체 변수를 선언하는 방법은 두 가지가 있습니다.

/*
 example 013-01
 C language structure variable
*/

#include <stdio.h>

struct students {
          
          char name[20];
          int age;
          int height;
          double weight;
          
};

int main(){
          
          struct students person;
          
          return 0;
          
}

또 다른 방법은 구조체를 정의 할 때 같이 선언해주는 방법입니다.

/*
 example 013-02
 C language structure variable
*/

#include <stdio.h>

struct students {
          
          char name[20];
          int age;
          int height;
          double weight;
          
}person1,person2;

int main(){
                    
          return 0;
          
}

013-03 // KEYWORD TYPEDEF WHILE USING STRUCTURE

struct structure_name variable_name; 으로 이루어진 구조체 변수를 선언하는 문장을 typedef를 이용하여 짧게 바꾸어 쓸 수 있습니다. typedef는 다른 자료형의 별명을 만들어 사용하기 위한 예약어입니다.

/*
 example 013-03
 C language structure variable
*/

#include <stdio.h>

typedef struct students {
          
          char name[20];
          int age;
          int height;
          double weight;
          
} stu;

int main (void) {
          
          int a;
          stu b;
          
}

013-04 // ACCESSING MEMBERS OF A STRUCTURE

구조체 멤버로 접근하는 연산자는 2가지가 있습니다.

구조체 멤버에서 접근하는 연산자 (.)
구조체 포인터에서 접근하는 연산자 (->)

structure_variable_name.member_name

구조체 변수는 (.) 연산자를 사용하여 접근하고 초기화합니다. 혹은 선언과 동시에 중괄호를 이용하여 바로 초기화가 가능합니다.

struct structure_name structure_variable_name = { };
/*
 example 013-04
 C language structure variable
*/

#include <stdio.h>

void string_copy(char* str1, char* str2);

struct students {
          
          char name[20];
          int age;
          int height;
          double weight;
          
};

int main (void) {
          
          struct students b;
          string_copy(b.name,"c language");
          b.age = 15;
          b.height = 168;
          b.weight = 72.8;
          
          struct students c = {"c language2",18,178,75.0};
          
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",b.name,b.age,b.height,b.weight);
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",c.name,c.age,c.height,c.weight);
          
}

void string_copy(char* str1, char* str2){
          
          while(*str2!='\0'){
                    
                    *str1 = *str2;
                    
                    str1++;
                    str2++;
                    
          }
          
          *str1 = '\0';
          
}

013-05 // STRUCTURES WITHIN STRUCTURES

구조체 변수는 구조체 멤버로 포함할 수 있습니다.

/*
 example 013-05
 C language structure variable
*/

#include <stdio.h>

void line();

struct score {
          
          int mathematics;
          int language;
          int science;
          int total;
          double avg;
          
};

struct students {
          
          char name[20];
          int age;
          int height;
          double weight;
          struct score scor;
          
};


int main (void) {
          
          struct students a = {"c language1",18,178,75.0,{95,90,85}};
          struct students b;
          struct students c = {"c language3",18,178,75.0,{65,55,20}};
          
          a.scor.total = a.scor.mathematics+a.scor.language+a.scor.science;
          a.scor.avg = a.scor.total/3.0;
          
          c.scor.total = c.scor.mathematics+c.scor.language+c.scor.science;
          c.scor.avg = c.scor.total/3.0;
          
          line();
          
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",a.name,a.age,a.height,a.weight);
          printf("mathematics : %d, language : %d, science: %d, total : %d, avg : %.2f\n",a.scor.mathematics,a.scor.language,a.scor.science,a.scor.total,a.scor.avg);
          
          line();
          
          b = a;
          
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",b.name,b.age,b.height,b.weight);
          printf("mathematics : %d, language : %d, science : %d, total : %d, avg : %.2f\n",b.scor.mathematics,b.scor.language,b.scor.science,b.scor.total,b.scor.avg);
          
          line();
          
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",c.name,c.age,c.height,c.weight);
          printf("mathematics : %d, language : %d, science : %d, total : %d, avg : %.2f\n",c.scor.mathematics,c.scor.language,c.scor.science,c.scor.total,c.scor.avg);
          
          line(); 
          
}

void line(){
          
          int i = 0;
          
          printf("\n");
          
          while(i<40){
                    
                    printf("-");
                    i++;
                    
          }
          
          printf("\n\n");
          
}

013-06 // STRUCTURE AND POINTER

구조체 변수를 사용하기 위해 정의한 struct students는 int, double과 같은 자료형입니다. 사용자 정의 자료형이죠. 그렇기에 int, double과 같은 방법으로 포인터 사용이 가능합니다.

struct structure_name * structure_pointer_name

포인터가 선언되면 포인터에 구조체 변수의 주소를 대입합니다.

struct students *po;
po = &a;

포인터 po는 구조체 변수 a를 가리킵니다. 포인터를 사용하여 원소에 접근하기 위해서는 간접참조를 먼저 한 후, 멤버에 접근해야 합니다.

(*po).age = 19;
(*po).height = 180;

매번 괄호를 쳐주는 것은 불편한 일입니다. 그렇기에 구조체 포인터에서는 ->연산자를 사용하여 줄여 쓰기로 합니다.

po->age = 19;
po->height = 180;

/*
 example 013-05
 C language structure variable
*/

#include <stdio.h>

typedef struct {
          
          int mathematics;
          int language;
          int science;
          int total;
          double avg;
          
} sco;
typedef struct {
          
          char name[20];
          int age;
          int height;
          double weight;
          sco scor;
          
} stu;

void line();
stu calc_total(stu a);
void print_str(stu* p);

int main (void) {
          
          stu a = {"c language1",18,178,75.0,{95,90,85}};
          stu b;
          stu c = {"c language3",18,178,75.0,{65,55,20}};
          
          a = calc_total(a);
          b = a;
          c = calc_total(c);
          
          line();
          
          print_str(&a);
          print_str(&b);
          print_str(&c);

}

void print_str(stu* p){
          
          printf("name : %s, age : %d, height : %d, weight : %.2f\n",p->name,p->age,p->height,p->weight);
          printf("mathematics : %d, language : %d, science : %d, total : %d, avg : %.2f\n",p->scor.mathematics,p->scor.language,p->scor.science,p->scor.total,p->scor.avg);
                    
          line();

}

stu calc_total(stu a){
          
          a.scor.total = a.scor.mathematics+a.scor.language+a.scor.science;
          a.scor.avg = a.scor.total/3.0;
          
          return a;
          
}

void line(){
          
          int i = 0;
          
          printf("\n");
          
          while(i<40){
                    
                    printf("-");
                    i++;
                    
          }
          
          printf("\n\n");
          
}

013-07 // MEMORY ALLOCATION

구조체 변수를 선언하면 변수, 배열과 마찬가지로 메모리에 할당됩니다. 그렇기 때문에 구조체 포인터도 쓸 수 있습니다. 보다 효율적인 메모리 관리를 위해서는 구조체의 메모리 할당 구조를 알 필요가 있습니다.

struct students {

char name;
short age;
int height;
int height2;
double weight;
char name2;

};

struct students a = {‘a’,18,170,170,65.23,’b’};

이와같은 구조체가 선언되고 초기화되면 메모리 구조는 어떤 모습이 될까요. sizeof(a) 연산자로 크기를 보면 32bytes입니다. 케릭터형 2개와 정수형 2개, 더블형, 숏형이면 20bytes가 나와야하는데 말이죠.

구조체 변수가 초기화되면 가장 큰 자료형을 기준으로 할당이 시작됩니다. 가장큰 자료형이 double 형이므로 8bytes로 할당이 시작되고 memory alignment를 시작합니다. 4bytes를 기준으로 양분하는 것입니다. 이렇게 순서대로 할당하면 메모리에 빈공간이 생깁니다. 이런 메모리를 패딩 메모리라 부릅니다. 패딩 메모리가 많이 생기면 메모리 누수가 심합니다. 메모리를 관리해야 하는 상황이 생긴다면, 멤버의 순서를 바꾸어 누수를 줄일 수 있습니다.

struct students {

char name;
char name2;
short age;
int height;
int height2;
double weight;

};

struct students a = {‘a’,’b’,18,170,170,65.23};

구조체 멤버의 순서를 바꾸어 가독성은 떨어질 수 있으나 7bytes의 패딩 바이트를 줄였습니다.

REVIEW EXERCISES

1.x좌표와 y좌표를 가진 구조체를 정의하고 2개의 구조체 변수를 선언하여 두 구조체 변수의 거리를 측정하는 함수를 제작하여 출력하세요.

45.1231

Leave a Reply