2011-01-14 6 views

答えて

30

典型的なCのコードは次のようになりますのreallocが失敗した場合、それはゼロを返しますが、古い記憶がまだ有効であることを

void* newMem = realloc(oldMem, newSize); 
if(!newMem) 
{ 
    // handle error 
} 

oldMem = newMem; 

注、この典型的な使い方は、メモリリークが発生します。残念ながら

oldMem = realloc(oldMem, newSize); 
if(!oldMem) 
{ 
    // handle error 
} 

それは非常に一般的です。

また、C++のvector/listには特別なことはありません。同様の構造体をC言語で実装することができます。構文(およびエラー処理)は異なって見えます。たとえば、Cのstd :: vectorのLodePNG'sアナログを参照してください。

+0

クールすごい、C++と同等いただきましたので?例えばmalloc = new、free = delete、realloc =? – Kaije

+0

@user:あなたと同等のものが間違っています。それらは次のとおりです:malloc = vector :: vector、free = vector :: clear、realloc = vector :: resize。 – ybungalobill

+2

@ybungalobill、um ... 'vector :: clear()'は実際には 'free'に類似していません。 –

23

多くのCプロジェクトでは、ベクターのようなAPIが実装されています。ダイナミックアレイはそのような共通のニーズであり、可能な限りメモリ管理を抽象化するのが良いことです。その後、彼らはvectorで動作するさまざまなAPI関数呼び出しを持っているでしょう

typedef struct dynamic_array_struct 
{ 
    int* data; 
    size_t capacity; /* total capacity */ 
    size_t size; /* number of elements in vector */ 
} vector; 

:典型的なCの実装は次のようになります

int vector_init(vector* v, size_t init_capacity) 
{ 
    v->data = malloc(init_capacity * sizeof(int)); 
    if (!v->data) return -1; 

    v->size = 0; 
    v->capacity = init_capacity; 

    return 0; /* success */ 
} 

その後、もちろん、あなたがpush_backinsertresizeのための機能を必要とします、sizecapacityを超えた場合はreallocとなります。再割り当てが必要な場合

vector_resize(vector* v, size_t new_size); 

vector_push_back(vector* v, int element); 

通常、capacityはすべての時間を再割り当てを避けるために倍増しています。これは通常std::vectorで内部的に採用されているものと同じですが、通常std::vectorはC++オブジェクトの構築/破壊のためにreallocを呼び出さない点が異なります。むしろ、std::vectorは、新しいバッファを割り当て、次にコンストラクト/ムーブを(バッファnewを使用して)新しいバッファにコピーします。

Cの実際のベクトル実装では、intではなくvoid*ポインターを要素として使用することがあるため、コードはより一般的です。とにかく、このようなことは多くのCプロジェクトで実装されています。 Cのベクトル実装の例については、http://codingrecipes.com/implementation-of-a-vector-data-structure-in-cを参照してください。

+0

ここでは、構造体のデータ変数のポインタを作成するようですが、他の多くの場合は私は、構造のデータ変数がダブルポインタによって保持されていることを見た。これら2つの方法の違いは何ですか? – Kai

+0

リンクが壊れています(https://gist.github.com/EmilHernvall/953968/0fef1b1f826a8c3d8cfb74b2915f17d2944ec1d0を参照してください)普及している実装のようです。 –

8

実装に必要なメンバーを保持する構造体を隠すことから始めます。次に、構造の内容を操作する関数のグループを提供します。このような

何か:これにさらに

typedef struct vec 
{ 
    unsigned char* _mem; 
    unsigned long _elems; 
    unsigned long _elemsize; 
    unsigned long _capelems; 
    unsigned long _reserve; 
}; 

vec* vec_new(unsigned long elemsize) 
{ 
    vec* pvec = (vec*)malloc(sizeof(vec)); 
    pvec->_reserve = 10; 
    pvec->_capelems = pvec->_reserve; 
    pvec->_elemsize = elemsize; 
    pvec->_elems = 0; 
    pvec->_mem = (unsigned char*)malloc(pvec->_capelems * pvec->_elemsize); 
    return pvec; 
} 

void vec_delete(vec* pvec) 
{ 
    free(pvec->_mem); 
    free(pvec); 
} 

void vec_grow(vec* pvec) 
{ 
    unsigned char* mem = (unsigned char*)malloc((pvec->_capelems + pvec->_reserve) * pvec->_elemsize); 
    memcpy(mem, pvec->_mem, pvec->_elems * pvec->_elemsize); 
    free(pvec->_mem); 
    pvec->_mem = mem; 
    pvec->_capelems += pvec->_reserve; 
} 

void vec_push_back(vec* pvec, void* data, unsigned long elemsize) 
{ 
    assert(elemsize == pvec->_elemsize); 
    if (pvec->_elems == pvec->_capelems) { 
     vec_grow(pvec); 
    } 
    memcpy(pvec->_mem + (pvec->_elems * pvec->_elemsize), (unsigned char*)data, pvec->_elemsize); 
    pvec->_elems++;  
} 

unsigned long vec_length(vec* pvec) 
{ 
    return pvec->_elems; 
} 

void* vec_get(vec* pvec, unsigned long index) 
{ 
    assert(index < pvec->_elems); 
    return (void*)(pvec->_mem + (index * pvec->_elemsize)); 
} 

void vec_copy_item(vec* pvec, void* dest, unsigned long index) 
{ 
    memcpy(dest, vec_get(pvec, index), pvec->_elemsize); 
} 

void playwithvec() 
{ 
    vec* pvec = vec_new(sizeof(int)); 

    for (int val = 0; val < 1000; val += 10) { 
     vec_push_back(pvec, &val, sizeof(val)); 
    } 

    for (unsigned long index = (int)vec_length(pvec) - 1; (int)index >= 0; index--) { 
     int val; 
     vec_copy_item(pvec, &val, index); 
     printf("vec(%d) = %d\n", index, val); 
    } 

    vec_delete(pvec); 
} 

彼らは機能グループのVEC *の代わりに、ボイド*を使用してカプセル化を達成し、実際に中にそれを定義することによって、ユーザからの構造定義を非表示にしますCモジュールにはヘッダーではなく機能のグループが含まれています。また、ヘッダーから外してCモジュールでのみプロトタイプを作成することで、非公開であると考える機能を隠すことになります。

struct vc_vector { 
    size_t count; 
    size_t element_size; 
    size_t reserved_size; 
    char* data; 
    vc_vector_deleter* deleter; 
}; 

... 

vc_vector* vc_vector_create_copy(const vc_vector* vector) { 
    vc_vector* new_vector = vc_vector_create(vector->reserved_size/vector->count, 
              vector->element_size, 
              vector->deleter); 
    if (unlikely(!new_vector)) { 
    return new_vector; 
    } 

    if (memcpy(vector->data, 
      new_vector->data, 
      new_vector->element_size * vector->count) == NULL) { 
    vc_vector_release(new_vector); 
    new_vector = NULL; 
    return new_vector; 
    } 

    new_vector->count = vector->count; 
    return new_vector; 
} 

それを使用するには::

+0

これは30分で書かれていますが、保証はありません。 –

1

あなたは、実装vc_vectorが見ることができる

vc_vector* v1 = vc_vector_create(0, sizeof(int), NULL); 
for (int i = 0; i < 10; ++i) { 
    vc_vector_push_back(v1, &i); 
} 

// v1 = 0 1 2 3 4 5 6 7 8 9 

vc_vector* v2 = vc_vector_create_copy(v1); 

// v2 = 0 1 2 3 4 5 6 7 8 9 (copy of v1) 

// to get pointer to int: 

const int* v2_data = vc_vector_data(v1); 
関連する問題