728x90

앞서 구현한 벡터는 vector_get()을 통해 직접 인덱싱할 수 있었지만, C++의 for (auto x : vec) 같은 문법은 지원하지 않기 때문에 반복문에서 사용하기가 조금 불편합니다.

그래서 이번에는 C 스타일로 이터레이터(iterator)를 만들어서 while, for 루프에서 자연스럽게 벡터를 순회할 수 있도록 기능을 확장해 보겠습니다.


🔧 이터레이터 구조 정의

typedef struct {
    StaticVector* vector;
    size_t index;
} VectorIterator;
  • vector: 순회 대상이 되는 벡터
  • index: 현재 이터레이터가 가리키고 있는 인덱스

📜 이터레이터 함수들

// 시작 위치의 이터레이터 반환
VectorIterator vector_begin(StaticVector* vec) {
    VectorIterator it = {vec, 0};
    return it;
}

// 다음 요소가 존재하는지 확인
int vector_iterator_has_next(VectorIterator* it) {
    return it->index < it->vector->size;
}

// 다음 요소를 반환하고, 내부 인덱스를 증가
void* vector_iterator_next(VectorIterator* it) {
    if (!vector_iterator_has_next(it)) return NULL;
    return it->vector->buffer + (it->element_size * it->index++);
}

🧪 사용 예시

int main() {
    int buffer[MAX_VECTOR_CAPACITY];
    StaticVector vec;
    vector_init_static(&vec, buffer, sizeof(int), MAX_VECTOR_CAPACITY);

    for (int i = 1; i <= 5; ++i) {
        vector_push_back(&vec, &i);  // 1 ~ 5 저장
    }

    printf("== 벡터 요소 출력 ==\n");
    VectorIterator it = vector_begin(&vec);
    while (vector_iterator_has_next(&it)) {
        int* val = (int*)vector_iterator_next(&it);
        printf("%d ", *val);
    }
    printf("\n");

    return 0;
}

출력:

 
== 벡터 요소 출력 ==
1 2 3 4 5

✅ 이터레이터 도입의 장점

 

이점 설명
코드 가독성 향상 반복문에서 인덱싱 없이 순회 가능
범용성 모든 타입의 벡터에 공통으로 사용 가능
재사용성 이터레이터 구조를 통해 다른 컨테이너에도 확장 가능

🔚 마무리하며

이번 글에서는 정적 제네릭 벡터에 이터레이터 기능을 추가해 반복문에서 쉽게 사용할 수 있도록 확장해 보았습니다. 이를 통해 C에서도 마치 고급 언어처럼 벡터를 유연하게 사용할 수 있게 되었죠!

728x90
728x90

C++의 std::vector처럼 다양한 타입의 데이터를 담을 수 있는 벡터 자료구조는 매우 편리합니다. 하지만 임베디드 환경에서 동작하는 C 언어에서는 다음과 같은 제약이 존재하죠:

  • malloc, realloc, free와 같은 동적 메모리 할당이 금지
  • 표준 라이브러리 의존 최소화 필요
  • 컴파일 타임에 크기가 고정된 구조 선호

이 글에서는 이런 조건을 만족하는 정적(static) 제네릭 벡터를 직접 구현해 보겠습니다.
 


목표

  • 어떤 타입이든 담을 수 있는 제네릭 벡터
  • malloc 없이 작동 (정적 메모리)
  • 삽입, 삭제, 조회 기능 지원
  • C 언어로 작성

📦 구조 설계

먼저 벡터 구조체는 다음과 같은 정보를 담습니다:

typedef struct {
    uint8_t* buffer;       // 데이터를 저장하는 버퍼
    size_t element_size;   // 요소 하나의 크기
    size_t size;           // 현재 저장된 요소 개수
    size_t capacity;       // 최대 저장 가능한 요소 개수
} StaticVector;

🛠️ 구현 코드

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

#define MAX_VECTOR_CAPACITY 128  // 벡터 최대 용량 (임베디드 환경에서 제한)

// 제네릭 벡터 구조체
typedef struct {
    uint8_t* buffer;       // 외부에서 주입받은 버퍼
    size_t element_size;   // 요소 하나의 크기
    size_t size;           // 현재 저장된 요소 수
    size_t capacity;       // 전체 저장 가능한 요소 수
} StaticVector;

// 초기화 (버퍼는 외부에서 미리 선언하여 전달)
void vector_init_static(StaticVector* vec, void* buffer, size_t element_size, size_t capacity) {
    vec->buffer = (uint8_t*)buffer;
    vec->element_size = element_size;
    vec->size = 0;
    vec->capacity = capacity;
}

int vector_push_back(StaticVector* vec, void* element) {
    if (vec->size >= vec->capacity) return -1;  // overflow
    memcpy(vec->buffer + vec->size * vec->element_size, element, vec->element_size);
    vec->size++;
    return 0;
}

int vector_insert(StaticVector* vec, size_t index, void* element) {
    if (vec->size >= vec->capacity || index > vec->size) return -1;

    uint8_t* insert_pos = vec->buffer + index * vec->element_size;
    memmove(insert_pos + vec->element_size, insert_pos, (vec->size - index) * vec->element_size);
    memcpy(insert_pos, element, vec->element_size);
    vec->size++;
    return 0;
}

int vector_erase(StaticVector* vec, size_t index) {
    if (index >= vec->size) return -1;
    uint8_t* erase_pos = vec->buffer + index * vec->element_size;
    memmove(erase_pos, erase_pos + vec->element_size, (vec->size - index - 1) * vec->element_size);
    vec->size--;
    return 0;
}

void* vector_get(StaticVector* vec, size_t index) {
    if (index >= vec->size) return NULL;
    return vec->buffer + index * vec->element_size;
}

void vector_clear(StaticVector* vec) {
    vec->size = 0;
}

✨ 사용 예시

int main() {
    int buffer[MAX_VECTOR_CAPACITY];  // 정적으로 할당된 버퍼
    StaticVector vec;

    vector_init_static(&vec, buffer, sizeof(int), MAX_VECTOR_CAPACITY);

    for (int i = 0; i < 5; ++i) {
        vector_push_back(&vec, &i);
    }

    int value = 999;
    vector_insert(&vec, 2, &value);
    vector_erase(&vec, 0);

    for (size_t i = 0; i < vec.size; ++i) {
        int* p = (int*)vector_get(&vec, i);
        printf("%d ", *p);
    }

    return 0;
}

출력 예:

 
1 999 2 3 4

 


✅ 정리

 

항목 설명
제네릭 지원 void*와 element_size를 통해 어떤 타입도 저장 가능
정적 메모리 외부에서 버퍼를 받아와 동적 할당 없이 작동
기본 연산 지원 push_back, insert, erase, get, clear 등
임베디드 최적화 malloc 없이도 안전하게 작동

 
 
 
 

// static_vector.h
#ifndef STATIC_VECTOR_H
#define STATIC_VECTOR_H

#include <stddef.h>
#include <stdint.h>

// 정적 제네릭 벡터 구조체
typedef struct {
    uint8_t* buffer;
    size_t element_size;
    size_t size;
    size_t capacity;
} StaticVector;

// 벡터 초기화 (외부 버퍼 필요)
void vector_init_static(StaticVector* vec, void* buffer, size_t element_size, size_t capacity);

// 요소 추가
int vector_push_back(StaticVector* vec, void* element);

// 요소 삽입
int vector_insert(StaticVector* vec, size_t index, void* element);

// 요소 삭제
int vector_erase(StaticVector* vec, size_t index);

// 요소 접근
void* vector_get(StaticVector* vec, size_t index);

// 벡터 비우기
void vector_clear(StaticVector* vec);

// ===== 이터레이터 =====
typedef struct {
    StaticVector* vector;
    size_t index;
} VectorIterator;

VectorIterator vector_begin(StaticVector* vec);
int vector_iterator_has_next(VectorIterator* it);
void* vector_iterator_next(VectorIterator* it);

#endif // STATIC_VECTOR_H
// static_vector.c
#include "static_vector.h"
#include <string.h>

void vector_init_static(StaticVector* vec, void* buffer, size_t element_size, size_t capacity) {
    vec->buffer = (uint8_t*)buffer;
    vec->element_size = element_size;
    vec->size = 0;
    vec->capacity = capacity;
}

int vector_push_back(StaticVector* vec, void* element) {
    if (vec->size >= vec->capacity) return -1;
    memcpy(vec->buffer + vec->size * vec->element_size, element, vec->element_size);
    vec->size++;
    return 0;
}

int vector_insert(StaticVector* vec, size_t index, void* element) {
    if (vec->size >= vec->capacity || index > vec->size) return -1;
    uint8_t* insert_pos = vec->buffer + index * vec->element_size;
    memmove(insert_pos + vec->element_size, insert_pos, (vec->size - index) * vec->element_size);
    memcpy(insert_pos, element, vec->element_size);
    vec->size++;
    return 0;
}

int vector_erase(StaticVector* vec, size_t index) {
    if (index >= vec->size) return -1;
    uint8_t* erase_pos = vec->buffer + index * vec->element_size;
    memmove(erase_pos, erase_pos + vec->element_size, (vec->size - index - 1) * vec->element_size);
    vec->size--;
    return 0;
}

void* vector_get(StaticVector* vec, size_t index) {
    if (index >= vec->size) return NULL;
    return vec->buffer + index * vec->element_size;
}

void vector_clear(StaticVector* vec) {
    vec->size = 0;
}

// ===== 이터레이터 구현 =====

VectorIterator vector_begin(StaticVector* vec) {
    VectorIterator it = {vec, 0};
    return it;
}

int vector_iterator_has_next(VectorIterator* it) {
    return it->index < it->vector->size;
}

void* vector_iterator_next(VectorIterator* it) {
    if (!vector_iterator_has_next(it)) return NULL;
    return it->vector->buffer + (it->vector->element_size * it->index++);
}
728x90

+ Recent posts