구조체 포인터 전달
Coddy C 여정의 Logic & Flow 섹션에 포함된 레슨 — 63개 중 47번째.
구조체를 값으로 전달하는 방식은 데이터를 읽는 용도로는 적합하지만, 구조체 전체가 복사되기 때문에 크기가 큰 구조체의 경우에는 비효율적입니다. 더 중요한 점은, 함수 내부에서 원본 구조체를 수정할 수 없다는 것입니다. 바로 이런 상황에서 구조체 포인터(pointers to structs)를 전달하는 것이 필수적입니다.
구조체 자체 대신 구조체에 대한 포인터를 전달하면, 함수는 원본 구조체의 메모리 주소를 받습니다. 이 방식은 두 가지 주요 장점을 제공합니다: 더 효율적이며(복사 없음) 함수가 원본 데이터를 수정할 수 있게 해줍니다.
구조체 포인터를 인자로 받는 함수의 구문은 다음과 같습니다:
void functionName(struct StructureName *ptr) {
// ptr->member를 사용하는 함수 본문
}함수 내부에서 화살표 연산자를 사용하여 구조체 멤버에 접근하고 수정합니다. 포인터를 통해 이루어진 모든 변경 사항은 호출하는 함수에 있는 원래 구조체에 직접적인 영향을 미치므로, 이 방식은 구조체 데이터를 업데이트하거나 변환해야 하는 함수에 매우 적합합니다.
이 기술은 포인터의 강력함과 구조체(structs)의 조직화를 결합하므로, 복잡한 데이터 구조를 다루는 효율적인 C 프로그램을 작성하는 데 필수적입니다.
챌린지
쉬움효율적인 데이터 수정을 위해 구조체 포인터를 함수에 전달하는 방법을 보여주는 C 프로그램을 작성하세요. 프로그램의 요구 사항은 다음과 같습니다:
- 다음 멤버를 포함하는
BankAccount라는 이름의struct를 정의합니다:- 계좌 번호를 저장할 정수형
accountNumber - 계좌 소유주의 이름을 저장할 크기 30의 문자 배열
ownerName - 계좌 잔액을 저장할 실수형
balance - 거래 횟수를 저장할 정수형
transactionCount
- 계좌 번호를 저장할 정수형
- 다음 기능을 수행하는
depositMoney함수를 작성합니다:BankAccount구조체 포인터와 실수형 금액(amount)을 매개변수로 받습니다.- 화살표 연산자(arrow operator)를 사용하여 계좌 잔액에 금액을 더합니다.
- 거래 횟수를 1 증가시킵니다.
Deposit successful. New balance: [balance]를 출력합니다.
- 다음 기능을 수행하는
withdrawMoney함수를 작성합니다:BankAccount구조체 포인터와 실수형 금액(amount)을 매개변수로 받습니다.- 출금 금액이 현재 잔액보다 큰지 확인합니다.
- 잔액이 부족하면,
Insufficient funds. Current balance: [balance]를 출력합니다. - 잔액이 충분하면, 잔액에서 금액을 차감하고 거래 횟수를 증가시킨 후,
Withdrawal successful. New balance: [balance]를 출력합니다.
- 다음 기능을 수행하는
displayAccount함수를 작성합니다:BankAccount구조체 포인터를 매개변수로 받습니다.- 다음과 같은 정확한 형식으로 계좌 정보를 출력합니다:
Account Information:Account Number: [accountNumber]Owner: [ownerName]Balance: [balance]Transactions: [transactionCount]
- main 함수에서 다음을 수행합니다:
account라는 이름의BankAccount변수를 생성합니다.- 입력으로부터 계좌 번호, 소유주 이름, 초기 잔액을 읽어옵니다.
- 거래 횟수를 0으로 설정합니다.
displayAccount를 호출하여 초기 계좌 상태를 보여줍니다.- 입금액을 읽어와
depositMoney를 호출합니다. - 출금액을 읽어와
withdrawMoney를 호출합니다. displayAccount를 호출하여 최종 계좌 상태를 보여줍니다.
이 챌린지는 구조체 포인터를 함수에 전달하는 방식의 강력함을 보여줍니다. 값에 의한 전달(pass-by-value)과 달리, 함수는 원본 구조체의 메모리 주소를 전달받으므로 원본 데이터를 직접 수정할 수 있습니다. 이 방식은 복사가 발생하지 않아 더 효율적이며, 함수가 호출한 쪽의 구조체 값을 영구적으로 변경할 수 있게 해줍니다.
치트 시트
구조체를 값으로 전달할 때, 전체 구조체가 복사되므로 큰 구조체의 경우 비효율적이며 원본 데이터를 수정할 수 없습니다. 구조체 포인터를 전달하면 대신 메모리 주소를 전달함으로써 이 두 가지 문제를 모두 해결할 수 있습니다.
구조체 포인터를 받기 위한 함수 구문:
void functionName(struct StructureName *ptr) {
// ptr->member를 사용하는 함수 본문
}함수 내부에서는 화살표 연산자(->)를 사용하여 포인터를 통해 구조체 멤버에 접근하고 수정합니다. 변경된 사항은 호출한 함수의 원본 구조체에 직접적인 영향을 미칩니다.
이 방식은 두 가지 주요 장점을 제공합니다:
- 더 효율적임 (전체 구조체를 복사하지 않음)
- 함수가 원본 구조체 데이터를 수정할 수 있도록 허용함
직접 해보기
#include <stdio.h>
#include <string.h>
// TODO: 여기에 BankAccount 구조체를 정의하세요
// TODO: 여기에 depositMoney 함수를 작성하세요
// TODO: 여기에 withdrawMoney 함수를 작성하세요
// TODO: 여기에 displayAccount 함수를 작성하세요
int main() {
// 입력 읽기
int accountNum;
char ownerName[30];
float initialBalance;
float depositAmount;
float withdrawAmount;
scanf("%d", &accountNum);
scanf("%s", ownerName);
scanf("%f", &initialBalance);
scanf("%f", &depositAmount);
scanf("%f", &withdrawAmount);
// TODO: BankAccount 변수를 생성하고 초기화하세요
// TODO: 초기 상태를 표시하기 위해 displayAccount를 호출하세요
// TODO: 입금액과 함께 depositMoney를 호출하세요
// TODO: 출금액과 함께 withdrawMoney를 호출하세요
// TODO: 최종 상태를 표시하기 위해 displayAccount를 호출하세요
return 0;
}이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.