C - 구조체 심화

2022. 3. 14. 17:44C

구조체를 멤버로 가지는 구조체 예제이다.

#include <stdio.h>

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 = 1983;
	s1.dob.month = 5;
	s1.dob.day = 29;
	printf("%d %d %d", s1.dob.year, s1.dob.month, s1.dob.day);
}

출력 결과

1983 5 29

위의 예제를 통해 구조체의 멤버로 다른 구조체가 사용이 가능하다는 사실을 확인할 수 있다.

 

*구조체의 배열

#include <stdio.h>
#define SIZE 3

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

struct student list[SIZE];

int main(void) {
	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("이름: %s, 학점: %.1lf\n", list[i].name, list[i].grade);
	}
}

출력 결과

학번을 입력하세요 : 1111
이름을 입력하세요 : aa
학점을 입력하세요 : 4.5
학번을 입력하세요 : 2222
이름을 입력하세요 : bb
학점을 입력하세요 : 3.3
학번을 입력하세요 : 3333
이름을 입력하세요 : cc
학점을 입력하세요 : 2.2
이름: aa, 학점: 4.5
이름: bb, 학점: 3.3
이름: cc, 학점: 2.2

*구조체를 가리키는 포인터 

#include <stdio.h>

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

};
int main(void) {
	struct student s = { 24, "KIM", 4.3 };
	struct student* p;
	p = &s;
	printf("학번=%d, 이름=%s. 학점=%lf", (*p).number, (*p).name, (*p).grade);
}

출력 결과

학번=24, 이름=KIM. 학점=4.300000

 

(*p).number를 보면 *p.number로 쓰지 않고 (*p)로 표기한 이유에 대해 알아보자

연산자의 우선 순위가 *연산자에 비해 더 높기 때문에 p.number가 먼저 계산되고 다음에 *(p.number)가 계산된다. 하지만 우리가 원하는 것은 *p를 먼저 계산하는 것이므로 반드시 괄호를 이용해야 한다.

 

다른 표기방법으로는

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

(*p).멤버가 아닌 p->멤버를 통해 좀 더 쉽게 표기할 수 있다.

 

헷갈릴 수 있는 구조체 변수와 구조체 포인터의 조합을 정리해보자

1.(*p).number : 포인터 p가 가리키는 구조체의 멤버 number을 의미

2.p->number : 1번과 동일

3.*p.number : 연산자 우선순위에 의하여*(p.number)와 같다. 구조체 p의 멤버 number가 가리키는 것이란 의미.

단 이때 number은 반드시 포인터여야 하고 아닐시 오류이다.

4.*p->number :연산자 우선순위에 의하여*(p->number)와 같다. p가 가리키는 구조체의 멤버 p가 가리키는 내용을 의미한다. 만약 number가 포인터가 아니면 오류이다.

 

정리하고 다시보니 더 헷갈리는거 같다

예제를 통해 다시 한번 정리해보자

#include <stdio.h>

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

};
int main(void) {
	struct student s = { 24, "KIM", 4.3 }; 
	struct student* p; 
	//구조체 변수s를 선언하고 초기화 하였다. student 구조체를 가리킬 수 있는 포인터p를 선언
	
	p = &s;
	//구조체 변수 s의 주소값을 p에 대입하여 p가 s를 가리키도록 하였다

	printf("학번=%d, 이름=%s, 학점=%lf\n", s.number, s.name, s.grade);
	printf("학번=%d, 이름=%s, 학점=%lf\n", (*p).number, (*p).name, (*p).grade);
	//구조체 포인터p를 이용해 구조체 변수 s의 멤버를 참조한다. (*p)=s 이기에 s.멤버와 동일하다고 볼 수 있다.
	printf("학번=%d, 이름=%s, 학점=%lf\n", p->number, p->name, p->grade);
	//위와 같은 내용이지만 다른 방법이다. 연산자는 간접 멤버 연산자로서 구조체 포인터에서 바로 구조체의 멤버로 접근 가능하다.
}

출력 결과

학번=24, 이름=KIM, 학점=4.300000
학번=24, 이름=KIM, 학점=4.300000
학번=24, 이름=KIM, 학점=4.300000

구조체와 구조체 포인터 반환하기

하 진짜 개어렵다 너무 어려워서 미칠거 같ㅇ

#define _CRT_SECURE_NO_WARINGS
#include <stdio.h>
#include <string.h>

struct Person {
	char name[20];
	int age; 
	char address[100];
};
struct Person getPerson() {
	struct Person p;
	strcpy(p.name, "홍길동");
	p.age = 30;
	strcpy(p.address, "서울시 용산구 한남동");
	return p;
}
int main() {
	struct Person p1;
	p1 = getPerson();
	printf("이름 : %s \n", p1.name);
	printf("나이 : %d \n", p1.age);
	printf("주소 : %s \n", p1.address);

	return 0;
}

출력 결과

이름 : 홍길동
나이 : 30
주소 : 서울시 용산구 한남동

위 구문을 포인터를 활용한 동적 할당 구문으로 바꿔보자

#define _CRT_SECURE_NO_WARINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Person {
	char name[20];
	int age; 
	char address[100];
};
struct Person* allocPerson() {
	struct Person *p = malloc(sizeof(struct Person));
	strcpy(p->name, "홍길동");
	p->age = 30;
	strcpy(p->address, "서울시 용산구 한남동");
	return p;
}
int main() {
	struct Person *p1;
	p1 = allocPerson();
	printf("이름 : %s \n", p1->name);
	printf("나이 : %d \n", p1->age);
	printf("주소 : %s \n", p1->address);
	
	free(p1);

}

하 진짜 제발 하나님 진짜 너무 어려워요 모르겠다구요 진짜

출력 결과는 똑같이 나온다.

위 구문을 자세히 분석해보자.

#define _CRT_SECURE_NO_WARINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Person {
	char name[20];
	int age; 
	char address[100];
};
struct Person* allocPerson() { //allocPerson과 같은 반환값 자료형을 구조체 포인터로 지정해준다 밑의 함수 안에서
	//구조체 포인터의 메모리를 할당하고 값을 저장한 뒤 구조체 포인터를 반환한다.
	struct Person *p = malloc(sizeof(struct Person)); //malloc함수로 struct Person크기의 메모리를 할당 받는 구문
	strcpy(p->name, "홍길동"); //포인터 p가 가리키는 구조체의 멤버 name에 홍길동이란 값을 넣는다
	p->age = 30; //포인터 p가 가리키는 구조체의 멤버 age에 30이란 값을 넣는다
	strcpy(p->address, "서울시 용산구 한남동");//포인터 p가 가리키는 구조체의 멤버 address에 서울시 용산구 한남동이란 값을 넣는다
	return p; //구조체 p에 저장된 값을 반환한다
}
int main() {
	struct Person *p1;
	p1 = allocPerson(); //이 함수를 통해 반환값을 저장한다. (allocPerson함수를 호출한 뒤에 반환된 포인터를 p1에 저장한다)
	//위 구문을 통해 화살표 연산자로 멤버에 접근이 가능해진다.
	printf("이름 : %s \n", p1->name); 
	printf("나이 : %d \n", p1->age);
	printf("주소 : %s \n", p1->address);
	
	free(p1); //할당 받은 메모리를 해제하는 구문

}

 

'C' 카테고리의 다른 글

C - 자료구조 기초  (0) 2022.03.21
C - 구조체 크기 알아보기  (0) 2022.03.15
C - 동적 메모리 할당  (0) 2022.03.11
C - 함수 포인터  (0) 2022.03.11
C - 문자 입출력 라이브러리  (0) 2022.03.10