あなたがやろうとしていることに関するCの問題は、構造を移動する方法を知る必要があることです(つまり、型を知る必要があります)。std::vector<T>
テンプレート(C++
概念)を使用しているため、そのように機能する理由があります。そうは言っても、あなたが提案したものとは少し違うことを試すことができます。配列を使用したくない場合は、ジェネリック型を格納できます。ただし、データを取得して使用する場合、ユーザーは自分が期待しているデータの種類を知っている必要があります。以下では、配列を回避し(ただし、配列を使用することでよりクリーンなソリューションが存在する可能性があります)、ほぼ同じ柔軟性を提供するリンクリストの実装がありますstd::vector<T>
(これはリンクリストであるため、パフォーマンス上の利点は別として)O(n)
すべての操作(リストを巧妙に逆にして、O(1)
挿入することもできますが、これは単なる例です)
#include <stdio.h>
#include <stdlib.h>
typedef struct _item3_t
{
void *x, *y, *z;
struct _item3_t* next;
} item3_t;
typedef struct
{
item3_t* head;
} vec3_t;
void insert_vec3(vec3_t* vec, void* x, void* y, void* z)
{
item3_t* item = NULL;
item3_t* tmp = NULL;
int i = 0;
if(vec == NULL)
return;
item = malloc(sizeof(item3_t));
item->x = x;
item->y = y;
item->z = z;
item->next = NULL;
tmp = vec->head;
if(tmp == NULL) { // First element
vec->head = item;
} else {
while(tmp->next != NULL)
tmp = item->next;
tmp->next = item;
}
}
// This is one method which simply relies on the generic method above
void insert_vec3_float(vec3_t* vec, float x, float y, float z)
{
float* xv, *yv, *zv;
if(vec == NULL)
return;
xv = malloc(sizeof(float));
yv = malloc(sizeof(float));
zv = malloc(sizeof(float));
*xv = x;
*yv = y;
*zv = z;
insert_vec3(vec, xv, yv, zv);
}
void init_vec3(vec3_t* vec)
{
if(vec == NULL)
return;
vec->head = NULL;
}
void destroy_vec3(vec3_t* vec)
{
item3_t* item = NULL, *next = NULL;
if(vec == NULL)
return;
item = vec->head;
while(item != NULL) {
next = item->next;
free(item->x);
free(item->y);
free(item->z);
free(item);
item = next;
}
}
item3_t* vec3_get(vec3_t* vec, int idx)
{
int i = 0;
item3_t* item = NULL;
if(vec == NULL)
return NULL;
item = vec->head;
for(i = 0 ; i < idx && item != NULL ; ++i)
item = item->next;
return item;
}
void do_something(item3_t* item)
{
if(item == NULL)
return;
float x = *((float*)item->x);
float y = *((float*)item->y);
float z = *((float*)item->z);
// To do - something? Note, to manipulate the actual
// values in the vector, you need to modify their values
// at their mem addresses
}
int main()
{
vec3_t vector;
init_vec3(&vector);
insert_vec3_float(&vector, 1.2, 2.3, 3.4);
printf("%f %f %f\n", *((float*)vec3_get(&vector, 0)->x), *((float*)vec3_get(&vector, 0)->y), *((float*)vec3_get(&vector, 0)->z));
do_something(vec3_get(&vector, 0));
destroy_vec3(&vector);
return 0;
}
このコードは、箱から出してすぐにコンパイルする必要があります。ここにあるのは、「ベクトル」(特にvec3構造)であるリンクリストです。リスト内の各ノード(つまり、あるstd::vector<T>
意味ではすべての要素)には、すべてvoid
ポインターである3つの要素があります。したがって、ここに任意のデータ型を格納できます。唯一の落とし穴は、それらのポインタが指すようにメモリを割り当てる必要があることです。要素を削除するときは、そのメモリを解放する必要があります(vec3_destroy
例についてはメソッドを参照してください)。これが、これらのvoidポインタがあなたのケースでどのように機能するかを理解するのにもう少し役立つことを願っています。
データを取得するために[]
表記を使用することはできませんがvec3_get
、同じ方法でメソッドを使用できます。このdo_something
メソッドは、OPで述べたものと同様のことを達成できる可能性のある何らかの方法のスタブの例です。