Dies ist eine Implementierung eines std::vector
ähnlichen erweiterbaren Arrays, jedoch in einfachem C89-Code. Das Ergebnis ist ein typsicheres, einfach zu verwendendes dynamisches Array mit einem vertrauten Satz von Operationen.
Es funktioniert, indem es den gleichen Trick wie viele Allokatoren verwendet, nämlich etwas mehr Daten als angefordert zuzuweisen und die zusätzliche Auffüllung an der Vorderseite als Speicher für Metadaten zu verwenden. Somit sieht jeder Nicht-Null-Vektor im Speicher so aus:
+-----------------+------+----------+---------+
| elem_destructor | size | capacity | data... |
+-----------------+------+----------+---------+
^
| user's pointer
Dabei erhält der Benutzer einen Zeiger auf das erste data
. Auf diese Weise hat der Code einfachen Zugriff auf die erforderlichen Metadaten, der Benutzer muss sich jedoch nicht um diese Details kümmern. Der Gesamtaufwand beträgt 2 * sizeof(size_t) + sizeof(void (*)(void *))
pro Vektor.
Damit der Code möglichst generisch ist, wird er als reines Makro implementiert und besteht daher nur aus dem Header. Die Verwendung ist einfach:
/* if this is defined, then the vector will double in capacity each
* time it runs out of space. if it is not defined, then the vector will
* be conservative, and will have a capcity no larger than necessary.
* having this defined will minimize how often realloc gets called.
*/
#define CVECTOR_LOGARITHMIC_GROWTH
#include "cvector.h"
#include <stdio.h>
int main ( int argc , char * argv []) {
/* this is the variable that will store the array, you can have
* a vector of any type! For example, you may write float *v = NULL,
* and you'd have a vector of floats :-). NULL will have a size
* and capacity of 0. Additionally, vector_begin and vector_end will
* return NULL on a NULL vector. Alternatively, for clarity of writing
* you can use the cvector_vector_type macro to define a vector of a
* given type.
*/
cvector_vector_type ( int ) v = NULL ;
( void ) argc ;
( void ) argv ;
/* add some elements to the back */
cvector_push_back ( v , 10 );
cvector_push_back ( v , 20 );
cvector_push_back ( v , 30 );
cvector_push_back ( v , 40 );
/* remove an element by specifying an array subscript */
cvector_erase ( v , 2 );
/* remove an element from the back */
cvector_pop_back ( v );
/* print out some stats about the vector */
printf ( "pointer : %pn" , ( void * ) v );
printf ( "capacity: %lun" , cvector_capacity ( v ));
printf ( "size : %lun" , cvector_size ( v ));
/* iterator over the vector using "iterator" style */
if ( v ) {
int * it ;
int i = 0 ;
for ( it = cvector_begin ( v ); it != cvector_end ( v ); ++ it ) {
printf ( "v[%d] = %dn" , i , * it );
++ i ;
}
}
/* iterator over the vector standard indexing too! */
if ( v ) {
size_t i ;
for ( i = 0 ; i < cvector_size ( v ); ++ i ) {
printf ( "v[%lu] = %dn" , i , v [ i ]);
}
}
/* well, we don't have destructors, so let's clean things up */
cvector_free ( v );
return 0 ;
}
std::vector | cvector |
---|---|
std::vector<int> v | cvector(int) v |
Zerstörer | cvector_free(v) |
v.at(3) | cvector_at(v, 3) |
v[3] | v[3] |
v.front() | cvector_front(v) |
v.back() | cvector_back(v) |
v.begin() | cvector_begin(v) |
v.end() | cvector_end(v) |
v.empty() | cvector_empty(v) |
v.size() | cvector_size(v) |
v.capacity() | cvector_capacity(v) |
v.shrink_to_fit() | cvector_shrink_to_fit(v) |
v.clear() | cvector_clear(v) |
v.insert(pos, value) | cvector_insert(v, pos, value) |
v.erase(v.begin() + 2) | cvector_erase(v, 2) |
v.push_back(value) | cvector_push_back(v, value) |
v.pop_back() | cvector_pop_back(v) |
v.reserve(new_cap) | cvector_reserve(v, new_cap) |
v.resize(count) | cvector_resize(v, count) |
v.swap(other) | cvector_swap(v, other) |
std::vector<int> other = v; | cvector(int) other; cvector_copy(v, other); |