C
구조체의 필드에 접근 방법 (->, .)
by yororing
2024. 8. 30.
00 개요
- c 파일 코드분석 중 struct의 필드에 접근하는 방법이 여러가지인 것을 발견하여 이에 대한 정리
01 구조체의 필드에 접근 방법
- C에서 구조체의 필드에 접근하는 방법은 구조체 변수의 유형에 따라 다름
- 크게 두 가지 방법 존재: 구조체 변수가 직접적인 값일 때와 포인터일 때
1. 구조체 변수로 접근 (직접 변수 접근)
- 만약 구조체가 포인터가 아니라 직접 변수로 선언되었다면, . 연산자 사용하여 필드에 접근 가능
- 예시
struct lsInfo {
int nRes;
// 다른 필드들...
};
struct lsInfo info; // 구조체 변수를 직접 선언
info.nRes = 5; // `.` 연산자를 사용하여 필드에 접근
- 위 예제에서는 info는 lsInfo 구조체 타입의 변수
- info.nRes를 통해 nRes 필드에 접근한 것
2. 구조체 포인터로 접근 (포인터 접근)
- 구조체가 포인터로 선언되었다면, -> 연산자 사용하여 필드에 접근 가능
- 포인터는 구조체의 메모리 주소를 가리키고 있으며, -> 연산자는 포인터가 가리키는 구조체의 필드에 접근하는 데 사용됨
- 예시
struct lsInfo {
int nRes;
// 다른 필드들...
};
struct lsInfo *infoPtr; // 구조체 포인터 선언
infoPtr = &info; // 구조체 변수의 주소를 포인터에 할당
infoPtr->nRes = 5; // `->` 연산자를 사용하여 필드에 접근
- 위 예제에서 infoPtr는 lsInfo 구조체를 가리키는 포인터
- infoPtr->nRes를 통해 포인터가 가리키는 구조체의 nRes 필드에 접근한 것
3. 간접 접근 (포인터 접근 + 역참조)
- 구조체 포인터가 있을 때, * 연산자를 사용하여 포인터를 역참조(dereference)한 후 . 연산자를 사용해 필드에 접근 가능
- 예시
struct lsInfo {
int nRes;
// 다른 필드들...
};
struct lsInfo *infoPtr; // 구조체 포인터 선언
infoPtr = &info; // 구조체 변수의 주소를 포인터에 할당
(*infoPtr).nRes = 5; // `*` 연산자로 포인터를 역참조하고, `.` 연산자로 필드에 접근
- 위 방법은 -> 연산자를 사용하는 것과 동일한 효과를 가짐
- 그러나, 위의 코드는 좀 복잡함
- -> 연산자를 사용하는 것이 일반적으로 더 간결하고 가독성 좋음
4. 포인터 연산을 통한 접근 (주소 연산)
- 구조체 배열이 있을 때 포인터 연산을 사용하여 각 구조체의 필드에 직접 접근 가능
- 이 방법은 특히 배열에서 유용
- 포인터를 통해 구조체의 특정 필드의 메모리 주소를 계산하여 접근하는 것
- 예시
#include <stdio.h>
struct resItem {
char name[50];
char des[100];
};
struct lsInfo {
int nRes;
struct resItem resTable[10]; // 구조체 배열
};
int main() {
struct lsInfo info;
info.nRes = 2;
// 배열 초기화
snprintf(info.resTable[0].name, sizeof(info.resTable[0].name), "Resource1");
snprintf(info.resTable[0].des, sizeof(info.resTable[0].des), "Description1");
snprintf(info.resTable[1].name, sizeof(info.resTable[1].name), "Resource2");
snprintf(info.resTable[1].des, sizeof(info.resTable[1].des), "Description2");
// 포인터 연산을 통한 접근
struct resItem *resPtr = info.resTable; // 배열의 첫 번째 요소를 가리키는 포인터
for (int i = 0; i < info.nRes; i++) {
printf("Resource %d: Name=%s, Description=%s\n",
i,
(char *) &resPtr[i].name, // 필드의 주소를 이용해 접근
(char *) &resPtr[i].des);
}
return 0;
}
- 설명
- 구조체 배열과 포인터 설정:
- struct resItem *resPtr = info.resTable;는 resTable 배열의 첫 번째 요소를 가리키는 포인터를 설정
- 구조체 배열의 첫 번째 요소를 가리키는 포인터를 사용하여 배열의 모든 요소에 접근 가능
- 포인터 연산을 통한 필드 접근:
- 포인터 resPtr를 사용하여 resTable 배열의 각 resItem 구조체에 접근
- &resPtr[i].name과 &resPtr[i].des를 통해 각 resItem 구조체의 name과 des 필드의 주소를 얻어 값에 접근
- 출력:
- printf를 사용하여 각 resItem 구조체의 name과 des 필드를 출력
- 포인터 연산을 통해 접근한 필드의 값이 출력됨
- 요약
- 포인터 연산을 통한 필드 접근은 구조체 배열에서 포인터를 사용하여 필드에 직접 접근하는 방법
- &resPtr[i].name과 같은 방식으로 구조체의 필드에 접근할 수 있으며, 이는 배열의 요소와 관련된 특정 필드의 메모리 주소를 직접 활용하는 방법
5. 정리
- info.nRes: 구조체 변수가 직접 선언된 경우, . 연산자를 사용하여 필드에 접근
- infoPtr->nRes: 구조체 포인터가 있는 경우, -> 연산자를 사용하여 필드에 접근
- (*infoPtr).nRes: 구조체 포인터를 역참조한 후 . 연산자를 사용하여 필드에 접근
- &resPtr[i].name (포인터 연산을 통한 필드 접근): 구조체 배열에서 포인터를 사용하여 필드에 접근
- 보통 구조체 포인터의 필드에 접근할 때는 -> 연산자를 사용하는 것이 가장 일반적이고 간결한 방법!