본문 바로가기
Programming/C

13. 구조체

by 기딩 2023. 10. 19.
728x90

자료형

  • 기초자료형; int, char, double, void …
  • 파생자료형; 배열, 포인터, 구조체, 공용체
  • 사용자정의 자료형; typedef, enum

배열과 달리 사이즈나 자료형 달라도 됨

 

구조체의 이름(:태그) ; 변수명이 아님 ← 틀만 만들 땐 메모리 할당 안 됨

안에 변수를 적어야 할당됨

struct 구조체명 { //구조체 선언
// 멤버들
	int number; // 1000
	char name[10]; // 1004
	double grade; // 1014
}; // 마지막에 세미콜론 o

 

구조체의 초기화

struct student s1 = {24, "Kim", 4.3};

 

구조체 멤버 참조

s1.grade = 3.8;

 

예제1

#include <stdio.h>

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

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

	s.number = 20190001; //구조체 멤버 참조
	strcpy(s.name, "홍길동");
	s.grade = 4.3;

	printf("학번: %d\\n", s.number);
	printf("이름: %s\\n", s.name);
	printf("학점: %.2f\\n", s.grade);
	printf("%p\\n", & s.number); //00000058354FFC58
	printf("%p\\n", &s.name); //00000058354FFC5C. 58+4 = 5C
	printf("%p", &s.grade); //00000058354FFC68 5C+10(A) = 66, but 4byte씩 패킹돼서 5C+12(C)= 68

	return 0;
}

💡 #pragma pack(1) ; 4byte씩이 아니라 꽉 눌러담고 싶을 때
    레지스터 access할 때도 써야 할 때 있음

 

 

두 점 사이 거리 구하기

#include <math.h>
#include <stdio.h>
struct point {
	int x;
	int y;
};

int main(void)
{
	struct point p1, p2;
	int xdiff, ydiff;
	double dist;
	printf("점의 좌표를 입력하시오(x y): ");
	scanf_s("%d %d", &p1.x, &p1.y);
	
	printf("점의 좌표를 입력하시오(x y): ");
	scanf_s("%d %d", &p2.x, &p2.y);
	
	xdiff = p1.x - p2.x;
	ydiff = p1.y - p2.y;
	
	dist = sqrt((double)(xdiff * xdiff + ydiff * ydiff));
	
	printf("두 점 사이의 거리는 %f입니다.\\\\n", dist);
	
	return 0;
}

 

구조체를 멤버로 갖는 구조체 있을 수 ㅇ

#include <stdio.h>

struct point{
	int x;
	int y;
};

struct rect{
	struct point p1;
	struct point p2;
};

int main(void)
{
	struct rect r;
	int w, h, area, peri;
	printf(”왼쪽 상단의 좌표를 입력하시오: “);
	scanf(”%d %d”, &r.p1.x, &r.01.y);
	printf(”오른쪽 상단의 좌표를 입력하시오: “);
	scanf(”%d %d”, &r.p2.x, %r.p2.y);
	w = r.p2.x - r.p1.x;
	h = r.p2.x - r.p1.x;
	area = w * h;
	peri = 2 * w + 2 * h;
	printf(”면적은 %d이고 둘레는 %d입니다.\\n”, area, peri);
	
	return 0;
}

같은 구조체 변수끼리 대입 가능, 비교는 불가능(멤버들끼리 비교해야)

struct point {
	int x;
	int y;
};

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

	p2 = p1;			// 대입 가능, 주소는 다르고 값만 대입됨

	if (p1 == p2)			//비교 -> 컴파일 오류!!
		printf("p1와 p2이 같습니다.");

	if ((p1.x == p2.x) && (p1.y == p2.y))	//올바른 비교
		printf("p1와 p2이 같습니다.");
}

 

 

구조체와 포인터

  1. 구조체를 가르키는 포인터
  2. 포인터를 멤버로 가지는 구조체
struct student s = {24, "Kim", 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);
#include <stdio.h>
#define SIZE 3

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

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

	for (int i = 0; i < SIZE; i++)
	{
		printf("학번을 입력하시오: ");
		scanf_s("%d", &list[i].number);
		printf("이름을 입력하시오: ");
		scanf_s("%s", list[i].name, 20); //scanf_s 문자열은 사이즈 지정 필요
		printf("학점을 입력하시오(실수): ");
		scanf_s("%lf", &list[i].grade);
	}

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

	struct student s = { 24,"Kim", 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;
}

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

  • 시간, 공간 절약 o
  • 원본 훼손의 가능성 o

 

값으로 함수의 인수 전달

#include <stdio.h>

struct vector {
	float x;
	float y;
};
struct vector get_vector_sum(struct vector a, struct vector b);

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;
}

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;
}

 

 

공용체

같은 메모리 영역을 여러 변수가 공유 (덮어둠)

선언, 사용법은 구조체와 비슷

union example{

       char c; //주소 0x100이면

       int i; //얘도 주소 0x100

}; //구조체면 다음 주소에 되지만, 공용체는 같은 주소

#include <stdio.h>

union example {
	int i;
	char c;
};

int main(void)
{
	union example v;

	v.c = 0x01;
	printf("v.c:%c   v.i:%x\\n", v.c, v.i);

	v.i = 0xABCDEF7A;
	printf("v.c:%c   v.i:%i\\n", v.c, v.i);

	return 0;
}

 

 

열거형 enum

  • 변수가 가질 값들을 미리 열거
  • 0부터 1, 2, 3, …

int today;

today = 0; //일요일

today = 1; //월요일

  • 오류 줄이고 가독성 높이기
  • 0보단 SUN 기호상수가 더 적절
  • today에 9 같은 의미없는 값 대입 안 되도록 미리 차단해주기

 

예제

#include <stdio.h>
enum days { SUN, MON, TUE, WED, THU, FRI, SAT};
char* days_name[] = { //문자열의 배열
	"sunday", "monday", "tudesday", "wednesday", "thursday",
	"friday", "saturday" };

int main(void)
{
	enum days d;
	d = WED; //d에 3들어감 -> 3번째 배열
	printf("%d번째 요일은 %s입니다.\\n", d, days_name[d]);
	
	return 0;
}

 

 

typedef

  • 기존의 자료형에 새로운 자료형 BYTE로 정의
  • typedef (기존)unsigned char (새로운)BYTE;

  

정수 사용 기호 상수 열거형
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 OLCD:
         printf(”OLED TV\n”);
         break;
}
enum tvtype {
    LCD, OLED};
enum tvtype code;

switch(code) {
   case LCD:
      printf(”LCD TV\n”);
      break;
   case PDP:
       printf(”OLED TV\n”);
       break;
}
컴퓨터는 쉬우나, 사람은 기억 하기 어렵 기호 상수 작성 시 오류 저지를 수도 컴파일러가 중복 안 일어나게 체크

 

#include <stdio.h>

typedef struct point { //태그 안 써도 되나봄
	int x;
	int y;
} POINT;

/* //위와 동일, but 위가 더 자주 씀
struct point{
	int x;
	int y;
};
typedef struct point POINT;
*/

POINT translate(POINT p, POINT delta);

int main(void)
{
	POINT p = { 2, 3 };
	POINT delta = { 10, 10 };
	POINT result;

	result = translate(p, delta);
	printf("새로운 점의 좌표는(%d, %d)입니다.\\n", result.x, result.y);

	return 0;
}

POINT translate(POINT p, POINT delta)
{
	POINT new_p;

	new_p.x = p.x + delta.x;
	new_p.y = p.y + delta.y;

	return new_p;
}

 

공용체에 타입필드 사용

#include <string.h>
#define STU_NUMBER 1
#define REG_NUMBER 2

struct student {
	int type;
	union {
		int stu_number;
		char reg_number[15];
	} id;
	char name[20];
};

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

int main(void)
{
	struct student s1, s2;

	s1.type = STU_NUMBER;
	s1.id.stu_number = 20190001;
	strcpy(s1.name, "홍길동");

	s2.type = REG_NUMBER;
	strcpy(s2.id.reg_number, "860101-1056076");
	strcpy(s2.name, "김철수");

	print(s1);
	print(s2);
	
	return 0;
}
728x90

'Programming > C' 카테고리의 다른 글

16. 전처리 및 다중 소스 파일  (1) 2023.10.19
15. 스트림과 파일 입출력  (1) 2023.10.19
12. 문자열  (0) 2023.10.19
11. 포인터  (1) 2023.10.19
10. 배열  (0) 2023.10.19