본문 바로가기
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;       // `->` 연산자를 사용하여 필드에 접근
  • 위 예제에서 infoPtrlsInfo 구조체를 가리키는 포인터
  • 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 (포인터 연산을 통한 필드 접근): 구조체 배열에서 포인터를 사용하여 필드에 접근
  • 보통 구조체 포인터의 필드에 접근할 때는 -> 연산자를 사용하는 것이 가장 일반적이고 간결한 방법!