
B. 구조체 배열과 구조체 포인터
1. 구조체와 배열
a. 구조체 배열 선언 및 초기화
배열의 요소에는 제한이 없어서 구조체도 가능함
구조체 배열을 선언하는 방법은 일반 배열 선언방법과 같고, 접근 방법도 동일함
🤓 예제 : 구조체 배열의 선언 및 초기화
struct book text_book[3] = //2차원 배열의 초기화 방법과 똑같은 방법으로 초기화
{
{"국어", "홍길동", 15000},
{"영어", "이순신", 18000},
{"수학1", "강감찬", 10000}
};
puts("각 교과서의 이름은 다음과 같습니다.");
printf("%s, %s, %s\n", text_book[0].title, text_book[1].title, text_book[2].title);
//멤버 연산자(.)를 사용하여 각 배열 요소의 멤버에 접근
✨ 실행결과
각 교과서의 이름은 다음과 같습니다.
국어, 영어, 수학1
🎨 도식화
2. 구조체와 포인터
b. 구조체 포인터 선언
구조체의 이름은 구조체를 가리키는 주소 ❌
👉 따라서 포인터에 할당할 때에는 반드시 주소 연산자(&)를 사용
📘 문법
struct 구조체이름* 구조체포인터이름;
🤓 예제
struct book* ptr_my_book;
b. 구조체의 멤버에 접근하기
구조체 포인터를 이용하는 방법에는 두가지가 있음 (동일하게 작동)
1) 참조 연산자(*)를 이용하는 방법
📘 문법
(*구조체포인터).멤버변수이름
//참조 연산자(*)는 멤버 연산자(.)보다 연산자 우선순위가 낮으므로 반드시 괄호(())를 사용
🤓 예제
(*ptr_my_book).author
//참조 연산자(*)는 멤버 연산자(.)보다 연산자 우선순위가 낮으므로 반드시 괄호(())를 사용
2) 화살표 연산자(->)를 이용하는 방법 (더 많이 사용)
📘 문법
구조체포인터 -> 멤버변수이름
🤓 예제
ptr_my_book -> author
🤓 예제 : 참조 연산자와 화살표 연산자를 동시에 사용
#include <stdio.h>
#include <string.h>
struct book
{
char title[30];
char author[30];
int price;
};
int main(void)
{
struct book my_book = {"C언어 완전 해부", "홍길동", 35000};
struct book* ptr_my_book; // 구조체 포인트 선언
ptr_my_book = &my_book;
strcpy((*ptr_my_book).title, "C언어 마스터"); // 참조 연산자(*)를 이용하는 방법
strcpy(ptr_my_book->author, "이순신"); // 화살표 연산자(->)를 이용하는 방법
my_book.price = 32000; // 구조체 변수을 이용한 직접 수정
printf("책의 제목은 %s이고, 저자는 %s이며, 가격은 %d원입니다.\n", my_book.title, my_book.author, my_book.price);
return 0;
}
✨ 실행결과
책의 제목은 C언어 마스터이고, 저자는 이순신이며, 가격은 32000원입니다.
C. 구조체의 활용
1. 구조체 활용
a. 함수와 구조체
함수 전달 인수나 반환값으로 구조체를 사용할 수 있음
방식은 기본 타입과 같고, 구조체 포인터나 구조체의 멤버 변수만을 사용할 수도 있음
1) 구조체를 인수로 전달하는 방식
함수가 원본 구조체의 복사본을 가지고 작업해 안전함
🤓 예제 : 구조체의 멤버 변수를 함수의 인수로 전달
#include <stdio.h>
typedef struct
{
int savings;
int loan;
} PROP;
int calcProperty(int, int);
int main(void)
{
int hong_prop;
PROP hong = {10000000, 4000000};
hong_prop = calcProperty(hong.savings, hong.loan); // 구조체의 멤버 변수를 함수의 인수로 전달함
printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", hong.savings, hong.loan, hong_prop);
return 0;
}
int calcProperty(int s, int l)
{
return (s - l);
}
✨ 실행결과
홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.
2) 인수로 구조체의 주소를 직접 전달하는 방식
주소 하나만을 전달하므로 처리가 빠름
💥 원본 구조체에 직접 접근하므로 원본 데이터의 보호 측면에서는 매우 위험
🤓 예제 : 함수의 인수로 구조체의 주소를 직접 전달
#include <stdio.h>
typedef struct
{
int savings;
int loan;
} PROP;
int calcProperty(PROP*);
int main(void)
{
int hong_prop;
PROP hong = {10000000, 4000000};
hong_prop = calcProperty(&hong); // 구조체의 주소를 함수의 인수로 전달함.
printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", hong.savings, hong.loan, hong_prop);
return 0;
}
int calcProperty(PROP* money)
{
money->savings = 100; // 호출된 함수에서 원본 구조체의 데이터를 변경
return (money->savings - money->loan);
}
✨ 실행결과
홍길동의 재산은 적금 100원에 대출 4000000원을 제외한 총 -3999900원입니다.
3) ✔ 인수로 구조체를 전달하면서 원본을 보호하는 방식
🤓 예제 : const 키워드를 사용
#include <stdio.h>
typedef struct
{
int savings;
int loan;
} PROP;
PROP initProperty(void);
int calcProperty(const PROP*);
int main(void)
{
PROP prop;
int hong_prop;
prop = initProperty();
hong_prop = calcProperty(&prop);
printf("홍길동의 재산은 적금 %d원에 대출 %d원을 제외한 총 %d원입니다.\n", prop.savings, prop.loan, hong_prop);
return 0;
}
PROP initProperty(void)
{
PROP hong = {10000000, 4000000};
return hong; // 구조체를 함수의 반환값으로 반환함.
}
int calcProperty(const PROP* money) // const 키워드를 사용하여 구조체의 데이터를 직접 수정하는 것을 방지함.
{
return (money->savings - money->loan);
}
✨ 실행결과
홍길동의 재산은 적금 10000000원에 대출 4000000원을 제외한 총 6000000원입니다.
b. 중첩된 구조체
구조체를 정의할 때 멤버 변수로 또 다른 구조체를 포함 가능 ⭕
🤓 예제 : 또 다른 구조체를 포함하기
#include <stdio.h>
struct name
{
char first[30];
char last[30];
};
struct friends
{
struct name friend_name; //friends 구조체는 또 다른 구조체인 name 구조체를 멤버 변수로 포함
char address[30];
char job[30];
};
int main(void)
{
struct friends hong =
{
{ "길동", "홍" },
"서울시 강남구 역삼동",
"학생"
};
printf("%s\n\n", hong.address);
printf("%s%s에게,\n", hong.friend_name.last, hong.friend_name.first);
printf("그동안 잘 지냈니? 아직 %s이지?\n", hong.job);
puts("공부 잘 하고, 다음에 꼭 한번 보자.\n잘 지내^^");
return 0;
}
✨ 실행결과
서울시 강남구 역삼동
홍길동에게,
그동안 잘 지냈니? 아직 학생이지?
공부 잘 하고, 다음에 꼭 한번 보자.
잘 지내^^
c. 구조체의 크기
구조체의 크기는 멤버 변수들의 크기에 따라 결정
하지만 구조체의 크기가 언제나 멤버 변수들 총합과 일치하는 것은 ❌
🤓 예제
#include <stdio.h>
typedef struct
{
char a;
int b;
double c;
} TYPESIZE;
int main(void)
{
puts("구조체 TYPESIZE의 각 멤버의 크기는 다음과 같습니다.");
printf("%d %d %d\n", sizeof(char), sizeof(int), sizeof(double));
puts("구조체 TYPESIZE의 크기는 다음과 같습니다.");
printf("%d\n", sizeof(TYPESIZE));
return 0;
}
✨ 실행결과
구조체 TYPESIZE의 각 멤버의 크기는 다음과 같습니다.
1 4 8
구조체 TYPESIZE의 크기는 다음과 같습니다.
16 //13바이트가 아님
d. 바이트 패딩(byte padding)
컴파일러가 메모리의 접근을 쉽게 하기 위해(프로그램 속도 향상) 크기가 가장 큰 멤버 변수를 기준으로 모든 멤버 변수의 메모리 크기를 맞추는것(할당)
- 패딩 바이트(padding byte) : 이때 추가되는 바이트
🎨 도식화
📝 이미지 설명
- char형 멤버 변수를 위해 8바이트가 할당되며, 할당되는 1바이트를 제외한 7바이트가 남음
- int형 멤버 변수는 남은 7바이트보다 작으므로, 그대로 7바이트 중 4바이트를 할당
- double형 멤버 변수는 8바이트인데 남은 공간은 3바이트뿐이므로 다시 8바이트를 할당
- 총 이 구조체의 크기는 총 16바이트가 되며, 그중에서 패딩 바이트(padding byte)는 3바이트가 됨
출처 : http://www.tcpschool.com/c/c_struct_pointer
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
'프로그래밍 언어 > C' 카테고리의 다른 글
[메모리의 관리] 메모리의 기초 총정리 (0) | 2023.08.17 |
---|---|
[자료형(data type)] C 파생형 공용체와 열거체 (0) | 2023.08.17 |
[자료형(data type)] C 파생형 구조체 기본 (0) | 2023.08.17 |
[자료형(data type)] C 파생형 포인터와 배열 (0) | 2023.08.17 |
[자료형(data type)] C 파생형 포인터의 기본 (0) | 2023.08.17 |