2009-03-10 14 views
3

C cinsinden genel (veya türlenmemiş) bir dizi oluşturmak için uğraşıyorum (C++ bunu gerçekleştirdiğinin farkındayım) Daha kolay). Özetle, belirli bir bilinen türden bir diziyi (çalışma zamanında) tutmak için bir dizi ayırmak istiyorum. Gerçek uygulamada kullanıcı girdisine bağlıdır.Basit veya kodlanmamış (via void *) dizisinin nasıl kullanılabileceğini gösteren basit bir C kodu örneği için istekte bulunun

Çeşitli Google isabetlerinde bulunan tavsiyeleri izleyerek bir enum/struct senaryosunu kullanmaya çalışıyorum, ancak korkarım ki, boşluk işaretçilerine ve somut bir örneğe sahip olmadığım deneyimsiz olmamın, bir parça çalışma parçamı almamı engellemesidir. kodu. (Normalde sadece kitap satın alırdım ama dil bilmediğim bir ülkedeyim ve İngilizce programlama kitapları yok.)

Sorun aşağıdaki basitleştirmeye kadar iniyor: Bir resmim var (sadece 1D) piksel değerleri int, float veya double olabilir. Bana türünü söyleyecek bir fonksiyonum var. Tek istediğim, pikselleri uygun türde bir dizide saklamak. (Pratikte bu görüntüler çok büyük ve benim motivasyon hafızayı korumak ve her tür için kod yazma blokları önlemek için.)

Aşağıdaki gibi bir şey deniyorum ama belki de en iyisi değil (kod parçacığı)) olası bir veri yapısı için:

enum type { 
    typeint, typefloat, typedouble 
}; 

struct genericarray { 
    enum type type; 
    void *storage; 
}; 

Nedense ben generciarray örneklerinde bu pikselleri depolamak istiyor. Şimdiye kadar yaptığım bütün girişimler, anlamadığımı itiraf ettiğim "uyarı: dereferencing‘ void * "işaretçisine dönüştü.

Herhangi bir yardım için ve özellikle basitleştirilmiş örnek için çalışan bir jenerik dizinin nasıl elde edileceğine minnettar olacağım. Örnek, init için sadece döngüler kullanabilir. Gerçek resimlerimi nasıl yükleyeceğimi anlayabilirim.

+0

** bir boşluk, uyarı önlemek kullanın. (Daha eksiksiz bir örnek için yanıtıma bakın) –

cevap

4

ben her şeyi kapsülleyen: yapı içinde bir boşluk * aksine

#include "stdlib.h" 
#include "stdio.h" 

// structure 
enum type { typeint, typefloat, typedouble }; 

struct genericarray 
{ 
    enum type type; 
    void ** storage; 
}; 

typedef struct genericarray genericarray; 

// allocate 
void allocate(long numItems, enum type varType, genericarray * array) 
{ 
    (*array).type = varType; 
    switch (varType) 
    { 
     case typeint: 
      (*array).storage = malloc(numItems*sizeof(int)); 
      break; 
     case typefloat: 
      (*array).storage = malloc(numItems*sizeof(float)); 
      break; 
     case typedouble: 
      (*array).storage = malloc(numItems*sizeof(double)); 
    } 
} 

// release 
void release(genericarray array) 
{ 
    free(array.storage); 
} 

// usage 
int main(int argCount, char ** argList) 
{ 
    genericarray image_1; 
    genericarray image_2; 

    int iv; 
    float fv; 

    allocate(10, typeint, &image_1); 
    allocate(10, typefloat, &image_2); 

    ((int *)(image_1.storage))[5] = 42; 
    iv = ((int *)(image_1.storage))[5]; 
    printf("image_1[5] = %d\n", iv); 

    ((float *)(image_2.storage))[5] = 3.14159; 
    fv = ((float *)(image_2.storage))[5]; 
    printf("image_2[5] = %f\n", fv); 

    release(image_2); 
    release(image_1); 

    return 0; 
} 
+0

Bu, tam olarak peşindeyim. Çok güzel kodlu ve öğretici (özellikle güzel çünkü benim için bu yeni bölge). Gerçek kodumu genellemeye çalışmadan önce bu gece yazdıklarını araştırmak istiyorum. Şimdiye kadar sizinki, bir dizi iyi cevap arasından en iyisidir. Teşekkür ederim. –

+0

Bir şey değil. İltifat için teşekkür ederim ve kodlamada iyi şanslar! –

+0

Orada bir enum kullanmak yerine, muhtemelen orada imzasız char elementsize özelliği eklerim. Bu, varType'taki hte anahtarının gerekliliğini ortadan kaldıracak ve yeni türler eklemeyi önemsiz hale getirecektir. – Arafangion

2
enum type { 
    typeint, typefloat, typedouble 
} 

struct genericarray { 
    enum type type; 
    union { int i; float f; double d; } storage; 
}; 

ne ihtiyaç vardır

DÜZENLEME: int/şamandıra/çift, bunu ayırmak gerekir için kapsayıcı olarak * hükümsüz kullanmak: (IMHO.) (Dizi eski Çeşidi genericarray olduğunu -

(*((int*)array.storage)) 

şamandıra değiştirin: void * depolama)

array.storage = malloc(sizeof(int)); 

ve KQUEUE olarak birlikte tip == typefloat vb

durumu için ve özgür olmalıdır da öyle

free(array.storage); 
+0

array.storage öğesine bir işaretçi atayamazsınız. Bu kod bir anlam ifade etmiyor. – jmucchiello

+0

üzgünüm .. yazmamıştım, bu dizi Dr. Person Person'in tanımlanmış tipinin 'genericarray'ıdır. – nothrow

2

olamaz çünkü ilk başka bir değere çevrim yapmadan boş işaretçi KQUEUE. Bunun nedeni, C uygulamasının, dereferged işaretçinin ne tür bir nesne olduğunu bilmesi gerektiğidir. birliğe ek olarak

Eğer KQUEUE depolama istiyorsanız size ima yöntemi kullanabilirsiniz, ancak koşullu (bir alçı ile örtük veya açık) dönüştürmek zorunda kalacak, zaten önerilen:

int *iptr; 
double *dptr; 

switch (x.type) 
{ 
    case typedouble: 
     dptr = x.storage; // implcit conversion example 
     // reference your "image" as dptr[i] now 
     break; 
    case typeint: 
     iptr = (int *)x.storage; // explicit conversion, actually unnecessary 
     // reference your "image" as iptr[i] now 
     break; 
} 
+0

Bu çözüme çok benzer bir şeyi başarı ile yaptım. Bence bu uygulamanın daha fazla kodu var ama boşluk * verisine nasıl eriştiğinizin çok açık ve sezgisel olduğunu düşünüyorum. –

0

Kullanmanız gereken üç türün birleşimi olan bir öğeye sahip bir yapı tanımlamak ve sonra bu türden bir arabellek dinamik olarak ayırmak istiyorsunuz.

2

Aslında hata veriyor satırları belirtmek yok ama ne yapabileceğini ben istiyorum bir döküm

fValue = ((float*)ga.storage)[idx]; 

eklemek onlar

struct genericarray ga; 
float fValue; 

fValue = ga.storage[idx]; 

gibi biraz görünebilir hayal ayar ve değerleri almak için bazı makroları veya işlevleri oluşturmanızı öneririz. g cevaplarındaki ifadeleri değiştirir ve bu iyi bir şey bu erişim fonksiyonlarıdır. aşağıdaki gibi