본문 바로가기
Programming/컴퓨터프로그래밍및실습

[컴프실] 제13장: 구조체

by Lizardee 2023. 8. 29.
자료형의 분류

C 자료형

 

구조체의 필요성
// 구조체
struct student {
	int number; //학번
	char name[10]; //이름
	double grade; //학점
};

 

 

배열과 구조체
  • 배열: 서로 같은 타입의 변수들을 묶는다.
  • 구조체: 서로 다른 타입의 변수들을 묶는다.

 

 

구조체 선언
// 구조체 선언: struct
struct student {      // 구조체 이름
	int number;       // 구조체 멤버
	char name[10]; 
	double grade; 
};

 

구조체 선언의 예
// x값과 y값으로 이루어지는 화면의 좌표
struct point {
	int x;
	int y;
};
// 날짜
struct date {
	int month;
	int day;
	int year;
};
// 사각형
struct ractangle {
	int x, y;
	int width;
	int height;
};

 

 

구조체 변수 선언
struct student {      // 구조체 정의
	int number;
	char name[10];
	double grade;
};

int main(void) {
	struct student s1; // 구조체 변수 선언
}

 

 

구조체 초기화
struct student {
	int number;
	char name[10];
	double grade;
};
struct student s1 = { 24, "Kim", 4.3 }; // 구조체 초기화

 

구조체 멤버 참조
s1.grade = 3.8; //구조체 변수, 구조체 멤버

 

struct student {             // 구조체 선언
	int number;
	char name[10];
	double grade;
};

int main(void) {
	struct student s;        // 구조체 변수 선언

	s.number = 20230001;     // 구조체 멤버 참조
	strcpy(s.name, "이지원"); // 문자열: strcpy(문자열 복사 함수)
	s.grade = 4.3;

	printf("학번: %d\n", s.number);
	printf("이름: %d\n", s.name);
	printf("학점: %.2f\n", s.grade);

	return 0;
}

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct student {
	int number;
	char name[10];
	double grade;
};

int main(void) {
	struct student s; //구조체 변수 선언

	printf("학번을 입력하시오: ");
	scanf("%d", &s.number);

	printf("이름을 입력하시오: ");
	scanf("%s", &s.name);

	printf("학점을 입력하시오: ");
	scanf("%lf", &s.grade);

	printf("\n학번: %d\n", s.number);
	printf("이름: %s\n", s.name);
	printf("학점: %.2f\n", s.grade);

	return 0;
}

 

Lab: 2차원 공간 상의 점을 구조체로 표현하기
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>

struct dot {
	int x;
	int y;
};

int main(void) {
	struct dot p1;
	struct dot p2;

	printf("점의 좌표를 입력하시오(x, y): ");
	scanf("%d%d", &p1.x, &p1.y);
	
	printf("점의 좌표를 입력하시오(x, y): ");
	scanf("%d%d", &p2.x, &p2.y);

	double answer = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
	printf("거리는 %lf입니다.\n", answer);

	return 0;
}

 

 

구조체를 멤버로 가지는 구조체

: 구조체 안에 구조체 포함

  • struct date dob;
struct date {
	int year;
	int month;
	int day;
};

struct student {
	int number;
	char name[10];
	struct date dob; //구조체 안에 구조체 포함
	double grade;
};

int main(void) {
	struct student s1; //구조체 변수 선언

	s1.dob.year = 2001;
	s1.dob.month = 3;
	s1.dob.day = 21;
}

 

Lab: 사각형을 point 구조체로 나타내기
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct point {              //point 구조체
	int x;
	int y;
};

struct rect {               //rect 구조체
	struct point p1;
	struct point p2;
};

int main(void) {
	struct rect r;                                        //rect 구조체 변수 선언
	int w, h, area, peri;

	printf("왼쪽 상단의 좌표를 입력하시오: ");
	scanf("%d%d", &r.p1.x, &r.p2.y);                      //r.p1.x

	printf("오른쪽 하단의 좌표를 입력하시오: ");
	scanf("%d%d", &r.p2.x, &r.p2.y);

	w = r.p2.x - r.p1.x;
	h = r.p1.y - r.p2.x;
	area = w * h;
	peri = 2 * (w + h);
	printf("면적은 %d이고, 둘레는 %d입니다.\n", area, peri);

	return 0;
}

 

 

구조체 변수의 대입과 비교
  • 같은 구조체 변수끼리 대입은 가능하지만, 비교는 불가능하다.
p2 = p1;        //대입: 가능

p2.x = p1.x;    //대입: 가능

if(p1==p2)      //비교: 불가능!

if(p1.x==p2.x)  //비교: 가능

 

#include <stdio.h>

struct point {
	int x;
	int y;
};

int main(void) {
	struct point p1 = { 10, 20 };
	struct point p2 = { 30, 40 };

	p2 = p1; //대입 가능

	if ((p1.x == p2.x) && (p1.y == p2.y))
		printf("p1과 p2가 같습니다.\n");

	return 0;
}

 


구조체 배열

: 구조체를 여러 개 모은 것

구조체 배열

struct student {
	int number;
	char name[20];
	double grade;
};

int main(void) {
	struct student list[100];      //구조체 배열 선언

	list[2].number = 24;
	strcpy(list[2].name, "홍길동");
	list[2].grade = 4.3;
}

 

 

구조체 배열의 초기화
struct student {
	int name;
	int stu_num;
};

int main(void) {
	struct student list[3] = {  // 구조체 배열의 초기화
		{"Jiwon", 210000},
		{"Leziwn", 220000}
	};
}

 

 

구조체 배열의 요소 개수 자동 계산
  • n = sizeof(list)/sizeof(list[0]);
  • n = sizeof(list)/sizeof(struct student);
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

#define SIZE 3

struct student {
	int number;
	char name;
	double grade;
};

int main(void) {
	struct student list[SIZE];
	int i;

	for (i = 0; i < SIZE; i++) {
		printf("학번을 입력하시오: ");
		scanf("%d", &list[i].number);

		printf("이름을 입력하시오: ");
		scanf("%s", &list[i].name);

		printf("학점을 입력하시오: ");
		scanf("%lf", &list[i].grade);
	}

	for (i = 0; i < SIZE; i++)
		printf("학번: %d, 이름: %s, 학점: %f\n", list[i].number, list[i].name, list[i].grade);

	return 0;
}

 


구조체와 포인터

구조체와 포인터

 

구조체를 가리키는 포인터
#include <stdio.h>

struct student {
	int number;
	char name[20];
	double grade;
};

int main(void) {
	struct student* p;                                        // 구조체를 가리키는 포인터
	struct student s = { 24, "Kim", 4.3 };

	p = &s;                                                  // p = &s

	printf("학번 = %d, 이름 = %s, 학점 = %f\n", s.number, s.name, s.grade);
	printf("학번 = %d, 이름 = %s, 학점 = %f\n", (*p).number, (*p).name, (*p).grade);

	return 0;
}

 

 

-> 연산자

: 구조체 포인터로 구조체 멤버를 참조할 때 사용

  • (*p).number
  • p->number
struct student* p;
struct student s = { 24, "Kim", 4.3 };

p = &s;

printf("학번 = %d, 이름 = %s, 학점 = %f\n", p->number, p->name, p->grade);

 

/* 포인터를 통한 구조체 참조 */
#include <stdio.h>

struct student {
	int number;
	char name[20];
	double grade;
};

int main(void) {
	struct student s = { 1, "홍길동", 4.3 };
	struct student* p;

	p = &s; //구조체를 가리키는 포인터

	printf("학번 = %d, 이름 = %s, 학점 = %f\n", s.number, s.name, s.grade);
	printf("학번 = %d, 이름 = %s, 학점 = %f\n", (*p).number, (*p).name, (*p).grade);
	printf("학번 = %d, 이름 = %s, 학점 = %f\n", p->number, p->name, p->grade);

	return 0;
}

 

 

포인터를 멤버로 가지는 구조체
struct date* dob;  // dob 포인터 선언
s.dob = &d         // dob 포인터가 가리키는 구조체 == d
s.dob->year        // dob 포인터 값 출력
#include <stdio.h>

struct date {
	int month;
	int day;
	int year;
};

struct student {
	int number;
	char name[20];
	double grade;
	struct date* dob;   // 포인터를 멤버로 가지는 구조체
};

int main(void) {
	struct date d = { 3, 20, 3000 };
	struct student s = { 1, "Kim", 4.3 };

	s.dob = &d;         // 포인터가 가리키는 구조체 == d

	printf("학번: %d, 이름: %s, 학점: %f\n", s.number, s.name, s.grade);
	printf("생년월일: %d년 %d월 %d일\n", s.dob->year, s.dob->month, s.dob->day);

	return 0;
}

 

 

구조체와 함수

▶ 구조체를 함수의 인수로 전달하는 경우

  • 구조체의 복사본이 함수로 전달되게 된다.
  • 만약 구조체의 크기가 크면, 그만큼 시간과 메모리가 소요된다.
// 구조체의 함수를 인수로 전달하는 경우
int equal(struct student s1, struct student s2) {
	if (s1.number == s2.number)
		return 1;
	else
		return 0;
}

int main(void) {
	struct student a = { 1, "Lee", 3.8 };
	struct student b = { 2, "Kim", 3.5 };

	if (equal(a, b) == 1)
		printf("같은 학생\n");
	else
		printf("다른 학생\n");

	return 0;
}

 

구조체의 포인터를 함수의 인수로 전달하는 경우

  • 시간과 공간을 절약할 수 있다.
  • 원본 훼손의 가능성이 있다.
// 구조체의 포인터를 함수의 인수로 전달하는 경우
int equal(struct student* p1, struct student* p2) {
	if (p1->number == p2->number)
		return 1;
	else
		return 0;
}

 

 

포인터를 통한 변경 금지

: 원본을 읽기만 하고 수정할 필요는 없는 경우, 매개변수를 정의할 때 const 키워드를 쓴다.

  • const struct student *p1
int equal(const struct student* p1, const struct student* p2) {  // const
	if (p1->number == p2->number)
		return 1;
	else
		return 0;
}

 

 

구조체를 반환하는 경우

: 복사본이 반환된다.

struct student create() {
	struct student s;

	s.number = 3;
	strcpy(s.name, "Park");
	s.grade = 4.0;

	return s;
}

int main(void) {
	struct student a;
	
	a = create();            // 구조체 s가 구조체 a로 복사된다.

	return 0;
}

 

 

Lab: 벡터 연산
#include <stdio.h>

struct vector {
	double x;
	double y;
};

struct vector get_vector_sum(struct vector a, struct vector b) {
	struct vector result;

	result.x = a.x + b.x;
	result.y = a.y + b.y;

	return result;
}

int main(void) {
	struct vector a = { 2.0, 3.0 };
	struct vector b = { 5.0, 6.0 };
	struct vector sum;

	sum = get_vector_sum(a, b);
	printf("벡터의 합은 (%f, %f)입니다.\n", sum.x, sum.y);

	return 0;
}

 


공용체(union)
  • 같은 메모리 영역을 여러 개의 변수가 공유한다.
  • 공용체를 선언하고 사용하는 방법은 구조체와 비슷하다.
union example {
	char c;    // 같은 공간 공유
	int i;     // 같은 공간 공유
};

 

#include <stdio.h>

union example { //공용체 선언
	int i;
	char c;
};

int main(void) {
	union example v; //공용체 변수 선언
	
	v.i = 1000;
	v.c = 'A';
	printf("v.c: %c, v.i: %i\n", v.c, v.i); //%i

	return 0;
}

 

 

구조체와 공용체의 차이점
// 구조체
struct student {
	int number;
	char gender;
	double grade;
} s1;

// 공용체
union student {
	int number;
	char gender;
	double grade;
} s2;

구조체: s1, 공용체: s2

 

공용체에 타입 필드 사용
#include <stdio.h>
#include <string.h>
#define STU_NUM 1
#define REG_NUM 2

struct student {
	int type;          //type 필드
	union {
		int stu_num;   //학번
		char reg_num;  //주민등록번호
	} id;
	char name[20];
};

void print(struct student s) {
	switch (s.type) {  //s.type
	case STU_NUM:
		printf("학번: %d\n", s.id.stu_num);
		printf("이름: %s\n", s.name);
		break;
	case REG_NUM:
		printf("주민등록번호: %d\n", s.id.reg_num);
		printf("이름: %s\n", s.name);
		break;
	default:
		printf("타입 오류\n");
		break;
	}
}

int main(void) {
	struct student s1, s2; //구조체 변수 선언

	s1.type = STU_NUM;
	s1.id.stu_num = 2176297;
	strcpy(s1.name, "이지원");

	s2.type = REG_NUM;
	s2.id.reg_num = 2727291;
	strcpy(s2.name, "이지나");

	print(s1);
	print(s2);

	return 0;
}

 


열거형(enumeration)

: 변수가 가질 수 있는 값들을 미리 열거해놓은 자료형

  • enum
// 열거형 정의
// enum 열거형이름(태그) 기호상수들

enum days { SUN, MON, TUE, WED, THU, FRI, SAT };

 

 

열거형 초기화
enum days { SUN, MON, TUE, WED, THU, FRI, SAT };     //SUN=0, MON=1, ...
enum days { SUN = 1, MON, TUE, WED,THU, FRI, SAT };  //SUN=1, MON=2, ...
enum days{SUN=7, MON=1, TUE, WED, THU, FRI, SAT};    //SUN=7, MON=1, TUE=2,...

 

 

열거형의 예
enum colors { white, red, blue, green, black };
enum boolean { false, true };
enum levels { low, medium, high };

 

#include <stdio.h>

enum days { SUN, MON, TUE, WED, THU, FRI, SAT };       // 열거형 정의

char* days_name[] = {                                  // 문자열 포인터 배열
	"sun", "mon", "tue", "wed", "thur", "fri", "sat"
};

int main(void) {
	enum days d;                                       // 열거형 변수 선언
	d = WED;

	printf("%d번째 요일은 %s입니다.\n", d, days_name[d]);

	return 0;
}

 

 

열거형과 다른 방법과의 비교
/* 정수 사용 */
// 컴퓨터는 알기 쉬우나, 사람은 기억하기 어렵다.
switch (code) {
case 1:
	printf("LCD TV\n");
	break;
case 2:
	printf("OLED TV\n");
	break;
}
/* 기호 상수 */
// 기호 상수를 작성할 때 오류가 생길 수 있다.
#define LCD 1 
#define OLED 2

switch (code) {
case LCD:
	printf("LCD TV\n");
	break;
case OLED:
	printf("OLED TV\n");
	break;
}
/* 열거형 */
enum tvtype { LCD, OLED }; //열거형 정의
enum tvtype code;          //열거형 변수 선언
 
switch (code) {
case LCD:
	printf("LCD TV\n");
	break;
case OLED:
	printf("OLED TV\n");
	break;
}

 


typedef

: 기본 자료형에 새로운 자료형을 추가하는 것

// typedef 정의
// typedef 기존자료형 new자료형

typedef unsigned char BYTE;

 

typedef unsigned char BYTE;
BYTE index;                     // unsiged int index;

typedef int INT32;
typedef unsigned int UINT32;

INT32 i;                       // int i;
UINT32 k;                      // unsigned int k;

 

 

구조체로 새로운 타입 정의
struct point {                // 구조체 정의
	int x;
	int y;
};
typedef struct point POINT;  // struct point --> POINT
POINT a, b;
typedef struct complex { // struct --> complex
	double real;
	double image;
} COMPLEX;               // complex의 변수 COMPLEX
COMPLEX x, y;

 

Lab: 2차원 공간 상의 점을 POINT 타입으로 정의
#include <stdio.h>

// 구조체 정의: POINT라는 이름으로 x와 y 좌표를 가지는 구조체 정의
typedef struct point { 
    int x;
    int y;
} POINT; 

// 좌표 이동 함수: 현재 좌표 p와 이동량 delta를 받아서 새로운 좌표를 계산하여 반환
POINT translate(POINT p, POINT delta) {
    POINT new_p;

    // 새로운 x 좌표는 현재 x 좌표에 이동량의 x를 더한 값
    new_p.x = p.x + delta.x;
    // 새로운 y 좌표는 현재 y 좌표에 이동량의 y를 더한 값
    new_p.y = p.y + delta.y;

    return new_p; // 새로운 좌표를 반환
}

int main(void) {
    // 초기 좌표와 이동량을 설정
    POINT p = { 2, 3 };      // 초기 좌표 (2, 3)
    POINT delta = { 10, 10 }; // 이동량 (10, 10)
    POINT result;            // 결과 좌표를 저장할 변수

    // translate 함수를 호출하여 좌표를 이동시키고 결과를 result에 저장
    result = translate(p, delta);

    // 결과를 출력
    printf("(%d, %d) + (%d, %d) -> (%d, %d)\n", p.x, p.y, delta.x, delta.y, result.x, result.y);

    return 0;
}