티스토리 뷰

코딩/C

포인터 이용 구조체 매핑

seasameoil 2025. 5. 13. 18:35

C 언어에서 값 전달, 포인터, 구조체 설계 방식 정리

코드를 짤 때, 데이터를 어떻게 전달하고 관리할지는 꽤 중요한 선택입니다.  
값을 직접 넘길지, 주소를 넘길지, 혹은 구조체로 묶을지에 따라 코드의 구조와 효율이 달라지니까요.  
이 글에서는 다음 네 가지 방식에 대해 정리해 보았습니다.

  • 값 그대로 전달
  • 포인터 이용해서 전달
  • 구조체 안의 구조체
  • 주소 넘기기 + memcpy()

1. 값 그대로 전달

가장 단순한 방식입니다. 함수에 값을 넘기면, 그 값은 복사되어 함수 내부에서 사용됩니다.  
즉, 원본에는 영향을 주지 않습니다.

#include <stdio.h>

void doubleValue(int x) {
    x = x * 2;
    printf("Inside function: %d\n", x);  // 20
}

int main() {
    int num = 10;
    doubleValue(num);
    printf("After function: %d\n", num); // 10
    return 0;
}

2. 포인터 이용해서 전달

값이 아닌 주소를 넘기는 방식입니다. 함수 내부에서 원본 값을 직접 수정할 수 있습니다.

#include <stdio.h> 

void doubleValue(int* x) 
{ 
  *x = *x * 2;
} 

int main()
{
  int num = 10; 
  doubleValue(&num);
  printf("After function: %d\n", num); // 20 
  return 0;
}

 

포인터를 활용하면 메모리도 아끼고, 값 수정도 가능합니다.
단, 포인터 실수에 의한 오류에는 주의해야 합니다.


3. 구조체 안의 구조체

연관된 데이터를 하나로 묶고 싶을 때 구조체는 좋은 도구입니다.
그리고 여러 곳에서 반복되는 구조가 있다면, 구조체 안에 구조체를 넣어 재사용할 수 있습니다.

#include <stdio.h>

typedef struct {
    int year;
    int month;
    int day;
} Date;

typedef struct {
    char name[20];
    Date birthday;
} Person;

typedef struct {
    char productName[20];
    Date manufacturedDate;
} Product;

void printPerson(Person* p) {
    printf("Name: %s\n", p->name);
    printf("Birthdate: %d-%02d-%02d\n", 
           p->birthday.year, p->birthday.month, p->birthday.day);
}

void printProduct(Product* p) {
    printf("Product: %s\n", p->productName);
    printf("Manufactured: %d-%02d-%02d\n", 
           p->manufacturedDate.year, p->manufacturedDate.month, p->manufacturedDate.day);
}

int main() {
    Person alice = { "Alice", {1990, 12, 25} };
    Product phone = { "PhoneX", {2024, 3, 10} };

    printPerson(&alice);
    printProduct(&phone);
    return 0;
}

 

Date라는 구조를 반복 선언하지 않고 한 번만 정의해서 여러 구조체에 넣을 수 있기 때문에 중복 제거유지보수 측면에서 훨씬 유리합니다.


4. 주소 넘기기 + memcpy()로 매핑

하나의 패킷 안에 다양한 형태의 데이터를 담아야 할 때는
유연하게 처리할 수 있는 구조가 필요합니다. union을 쓰지 못하는 상황이라면, void* 포인터와 memcpy()를 이용해 원하는 구조체로 직접 매핑할 수 있습니다.

#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef struct {
    int id;
    float value;
} SensorData;

typedef struct {
    char msg[32];
} TextData;

typedef struct {
    uint8_t type;   // 0: SensorData, 1: TextData
    void* data;
} Packet;

void handlePacket(Packet* pkt) {
    if (pkt->type == 0) {
        SensorData s;
        memcpy(&s, pkt->data, sizeof(SensorData));
        printf("Sensor id: %d, value: %.2f\n", s.id, s.value);
    } else if (pkt->type == 1) {
        TextData t;
        memcpy(&t, pkt->data, sizeof(TextData));
        printf("Message: %s\n", t.msg);
    }
}

int main() {
    SensorData s = { 101, 25.6f };
    TextData t = { "Hello, World!" };

    Packet p1 = { 0, &s };
    Packet p2 = { 1, &t };

    handlePacket(&p1);
    handlePacket(&p2);
    return 0;
}

이 방식의 장점은 구조체를 통째로 넘기는 것보다 더 유연하고 확장성 있는 방식으로 데이터를 처리할 수 있다는 점입니다.


 

정리 – 어떤 방식이 언제 유리할까?

방식 주요 특징 장점 단점 대표 상황
값 그대로 전달 값 복사 간단하고 안전 원본 수정 불가 정수, 부동소수 등 기본형 인자
포인터로 전달 주소 전달 수정 가능, 메모리 절약 포인터 실수에 주의 필요 배열, 구조체 수정 함수 등
구조체 안의 구조체 구조 계층화, 중복 구조 재사용 가독성↑, 유지 보수 편리 구조가 복잡해질 수 있음 날짜, 좌표 등 공통 데이터 활용 시
주소 넘기기 + memcpy() 다양한 구조를 하나의 틀로 유연하게 처리 확장성과 유연성 확보 타입 안정성 직접 관리 필요 패킷 처리, 메시지 인터페이스 등

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함