부모 멤버 접근하기
Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 30번째.
이제 구조체 임베딩(struct embedding)과 첫 번째 멤버 규칙(first member rule)을 이해했으므로, 함수 내에서 임베딩된 부모의 데이터를 읽고 수정하는 방법이라는 실무적인 측면에 집중해 보겠습니다.
함수가 Child 구조체(또는 그에 대한 포인터)를 전달받을 때, 부모의 멤버에 접근하려면 임베디드된 구조체를 거쳐야 합니다. 구문은 값으로 작업하는지 아니면 포인터로 작업하는지에 따라 달라집니다.
typedef struct {
int id;
int score;
} Parent;
typedef struct {
Parent parent;
char grade;
} Child;Child에 대한 포인터를 사용하여 화살표 연산자로 부모(parent)에 접근한 다음, 점(dot) 연산자로 해당 멤버에 접근합니다:
void update_score(Child* c, int new_score) {
c->parent.score = new_score; // 화살표 연산자 사용 후 점 연산자 사용
}
void print_info(Child* c) {
printf("ID: %d, Score: %d\n", c->parent.id, c->parent.score);
}값(복사로 전달됨)을 사용할 때는, 전체적으로 점(dot)을 사용합니다:
void show_id(Child c) {
printf("ID: %d\n", c.parent.id); // 점 다음에 점
}이 체인형 접근 패턴 — child->parent.member 또는 child.parent.member — 은 C의 컴포지션 모델에서 상속된 데이터와 상호작용하는 방식입니다. 실제 상속보다는 약간 더 장황하지만, 타입 간의 관계를 명시적이고 명확하게 보여줍니다.
챌린지
쉬움중첩된 구조체 내부의 데이터를 액세스하고 수정하는 방법을 보여주는 학생 성적 관리 시스템을 만들어 보겠습니다. Student가 중첩된 Person을 포함하는 계층 구조를 만들고, 자식 구조체를 통해 부모의 데이터와 상호작용하는 함수를 작성하게 됩니다.
코드는 다음 세 개의 파일로 구성됩니다:
student.h: 인클루드 가드(include guards)를 사용하여 구조체 계층을 정의합니다.name(50자의 문자 배열)과age(정수)를 가진Person구조체를 생성합니다. 그런 다음Person을 첫 번째 멤버로 포함하고grade필드(점수를 나타내는 정수)를 추가한Student구조체를 정의합니다. 두 개의 함수를 선언합니다:Student*와 새로운 나이 값을 받는set_person_age, 그리고Student*를 받아 모든 정보를 표시하는print_student입니다.student.c: 두 함수를 구현합니다.set_person_age함수는 중첩된Person구조체 내부의 나이를 수정해야 합니다. 여기서 화살표 연산자 다음에 점 연산자를 사용하는 구문(s->person.age)을 연습하게 됩니다.print_student함수는 중첩된 person과 student 자체의 모든 필드에 액세스하여 표시해야 합니다.main.c:Student변수를 생성하고 모든 필드를 초기화합니다. 그런 다음set_person_age를 사용하여 중첩된 person의 나이를 업데이트하고,print_student를 호출하여 결과를 표시합니다.
네 가지 입력을 받게 됩니다: 학생의 이름(문자열), 초기 나이(정수), 성적(정수), 그리고 함수를 통해 업데이트할 새로운 나이(정수)입니다.
메인 파일에서 초기 값으로 학생을 생성한 다음, set_person_age를 호출하여 나이를 새 값으로 변경하고, 마지막으로 print_student를 호출하여 업데이트된 정보를 표시합니다.
출력은 다음과 같아야 합니다:
Name: Emma
Age: 21
Grade: 85여기서 Emma는 이름이고, 21은 (초기 나이가 아닌) 업데이트된 나이이며, 85는 성적입니다. 여기서 핵심 학습 내용은 중첩된 구조체를 탐색하여 부모 멤버를 읽고 쓰는 것입니다.
치트 시트
함수에서 포함된 부모 구조체 멤버에 접근하려면, 포인터를 사용하는지 또는 값을 사용하는지에 따라 달라지는 체인 접근 구문을 사용하세요.
자식 구조체에 대한 포인터를 사용하는 경우, 화살표 연산자를 사용하여 포함된 부모에 접근한 다음, 점 표기법을 사용하여 해당 멤버에 접근합니다:
void update_score(Child* c, int new_score) {
c->parent.score = new_score; // 화살표 다음 점
}
void print_info(Child* c) {
printf("ID: %d, Score: %d\n", c->parent.id, c->parent.score);
}값(복사로 전달됨)을 사용하는 경우, 전체적으로 점 표기법을 사용합니다:
void show_id(Child c) {
printf("ID: %d\n", c.parent.id); // 점 다음 점
}이 패턴 — child->parent.member 또는 child.parent.member — 은 C의 구성 모델에서 상속된 데이터에 대한 명시적인 접근을 제공합니다.
직접 해보기
#include <stdio.h>
#include <string.h>
#include "student.h"
int main() {
char name[50];
int initial_age, grade, new_age;
// 입력 읽기
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = '\0'; // 줄바꿈 제거
scanf("%d", &initial_age);
scanf("%d", &grade);
scanf("%d", &new_age);
// TODO: Student 변수 생성
// TODO: 학생의 모든 필드 초기화
// - strcpy를 사용하여 name을 포함된 person의 name으로 복사
// - 포함된 person의 age를 initial_age로 설정
// - 학생의 grade 설정
// TODO: set_person_age를 호출하여 나이를 new_age로 업데이트
// TODO: print_student를 호출하여 결과 표시
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.