2010-08-11 21 views
14

मैंने देखा है कि हमारे कोड बेस में कई स्थानों पर हम गतिशील रूप से विस्तारित सरणी का उपयोग करते हैं, यानी एक तत्व सरणी और "अधिकतम तत्व" मान के साथ एक आधार सरणी।एसटीएल वेक्टर के एक अच्छा सी समकक्ष?

सामान्य ऑब्जेक्ट उन्मुख कारणों के लिए, मैं इन्हें एक सामान्य डेटा संरचना और उपयोगिता कार्यों के साथ प्रतिस्थापित करना चाहता हूं। सरणी तत्व या तो मूल डेटा प्रकार या structs हो सकते हैं, मुझे तत्वों के लिए तेज़ी से यादृच्छिक पहुंच की आवश्यकता है, और अधिमानतः एक प्रकार-सुरक्षित कार्यान्वयन।

तो, मूल रूप से, एक एसटीएल वेक्टर है कि मैं क्या उपयोग करना चाहते हैं है, लेकिन कोड बेस तो मैं कुछ और :-) साथ आने के लिए

मैं इसे कुछ सोचा दे दी है C89 के लिए प्रतिबंधित और मार पड़ी है है इस प्रारंभिक मसौदा अप, बस पता चलता है कि मैं क्या कर रहा हूँ पर निशाना:

/* Type-safe dynamic list in C89 */ 

#define list_declare(type) typedef struct _##type##_list_t { type * base_array; size_t elements; size_t max_size; } type##_list_t 
#define list(type) type##_list_t 
#define list_new(type, initial_size) { calloc(initial_size, sizeof(type)), 0, initial_size } 
#define list_free(list) free(list.base_array) 
#define list_set(list, place, element) if (list.elements < list.max_size) { list.base_array[place] = element; } else { /* Array index out of bounds */ } 
#define list_add(list, element) if (list.elements < list.max_size) { list.base_array[list.elements++] = element; } else { /* Expand array then add */ } 
#define list_get(list, n) list.base_array[n] 

/* Sample usage: */ 

list_declare(int); 

int main(void) 
{ 
    list(int) integers = list_new(int, 10); 
    printf("list[0] = %d\n", list_get(integers, 0)); 
    list_add(integers, 4); 
    printf("list[0] = %d\n", list_get(integers, 0)); 
    list_set(integers, 0, 3); 
    printf("list[0] = %d\n", list_get(integers, 0)); 
    list_free(integers); 

    return EXIT_SUCCESS; 
} 

... तथापि, वहाँ किसी और ने इस से पहले किया गया है किया जाना चाहिए। मुझे कुछ अलग-अलग कतारों के लिए एक समान अवधारणा के फ्रीबीएसडी sys/queue.h कार्यान्वयन के बारे में पता है, लेकिन मुझे एरे के लिए ऐसा कुछ नहीं मिल रहा है।

क्या कोई यहां कोई बुद्धिमान है?

+4

कम से कम, या तो मैक्रो से छुटकारा पाने के लिए और उन्हें कार्यों के साथ बदल सकते हैं या इतना है कि वे की तरह काम उन्हें ठीक कार्य करता है। उत्तरार्द्ध में किसी भी मैक्रो को लपेटना शामिल है जो 'डू {...} के साथ एक अभिव्यक्ति/कथन से अधिक है (0) '। –

+1

मै मैक्रोज़ से छुटकारा क्यों लेना चाहूंगा? उन्हें कार्यों के साथ बदलना स्वतंत्रता प्रकार को हरा देगा, यह अब एक सामान्य समाधान नहीं होगा। इसके अलावा, मैं क्यों करना चाहता हूं ... जबकि? इससे फ़ंक्शन-जैसी मैक्रोज़ से असंभव वापसी मूल्य बन जाएंगे। – Christoffer

+0

@ क्रिस्टोफर: आर की टिप्पणी दोबारा पढ़ें। "या" के उपयोग पर ध्यान दें - उन फ़ंक्शन मैक्रोज़ भयानक हैं, आपको उन्हें "फिक्सिंग" करके सुधारना चाहिए, जैसा आर कहते हैं। यह एक समारोह मैक्रो कम आश्चर्यजनक का उपयोग कर बनाता है। अच्छे उपाय के लिए, फ़ंक्शन मैक्रोज़ को पूंजीकृत किया गया था, तो मैं व्यक्तिगत रूप से पसंद करूंगा। – Arafangion

उत्तर

9

ग्लिब GArray प्रकार प्रदान करता है, जो एक गतिशील रूप से बढ़ती सरणी लागू करता है। यदि आप बाहरी तृतीय पक्ष पुस्तकालयों का उपयोग कर सकते हैं, तो ग्लिब हमेशा सी के लिए "मानक" लाइब्रेरी के रूप में एक अच्छी पसंद है। यह सभी मूल डेटा संरचनाओं के लिए प्रकार प्रदान करता है, यूनिकोड तारों के लिए, दिनांक और समय मानों के लिए, आदि।

+0

अच्छा सुझाव, लेकिन हम किसी तीसरे पक्ष के पुस्तकालयों का उपयोग नहीं कर सकते हैं (ठीक है, कम से कम एक ग्लिब का आकार कम से कम नहीं)। इसके अलावा, गैरेरे प्रकार पर निर्भर प्रतीत नहीं होता है, जब तक उनके पास समान आकार होता है, तब तक विभिन्न प्रकार की वस्तुओं को एक सरणी में स्टोर करना संभव लगता है :-) (जैसे 'int' और 'float') – Christoffer

+6

@ क्रिस्टोफर: जेनेरिक, लेकिन सुरक्षित कंटेनर टाइप करें सी सी के प्रकार प्रणाली में लागू नहीं किया जा सकता है बहुत प्राचीन है और किसी भी तरह के सामान्य प्रकार या टेम्पलेट का समर्थन नहीं करता है। एकमात्र जेनेरिक चीज सी शून्य पॉइंटर्स हैं, और ये सुरक्षित नहीं हैं। आपको इस तथ्य के लिए उपयोग करना होगा कि सी केवल एक कमजोर टाइप की गई भाषा है :) – lunaryorn

+0

@ लूनरीर्न कुछ चाल के साथ (उदाहरण के प्रकार कास्ट और 'टाइपोफ') कुछ सुंदर ठोस प्रकार की सुरक्षा को लागू करना संभव है। हालांकि, मैं इस बात से सहमत हूं कि सी – YoYoYonnY

2

वहाँ sglib है, जो एक सामान्य फैशन में विभिन्न सूचियों, हैशैप्स और आरबीटीआर लागू करता है (यानी एक प्रकार के विशेषज्ञ द्वारा)। वहाँ भी सरणियों के लिए एक तेजी से छँटाई समारोह है:

+0

में टाइप सुरक्षित डेटाटाइप लागू करने के लिए लगभग असंभव होने जा रहा है, भले ही इसमें विशेष डेटा प्रकार की कमी न हो, भले ही: I) – Christoffer

1
यहाँ एक सरल वेक्टर प्रतिस्थापन

, सभी के लिए अपने एक समारोह, इसकी सख्ती से C89 और threadsafe; libs मेरे लिए बहुत मुश्किल हैं, मैं अपना खुद का उपयोग करता हूं; कोई प्रदर्शन है, लेकिन आसान है, उपयोग करने के लिए

/* owner-structs too */ 
typedef struct { 
    char name[20],city[20]; 
    int salary; 
} My,*Myp; 

typedef char Str80[80]; 

/* add here your type with its size */ 
typedef enum {SPTR,INT=sizeof(int),DOUBLE=sizeof(double),S80=sizeof(Str80),MY=sizeof(My)} TSizes; 

typedef enum {ADD,LOOP,COUNT,FREE,GETAT,GET,REMOVEAT,REMOVE} Ops; 

void *dynarray(char ***root,TSizes ts,Ops op,void *in,void *out) 
{ 
    size_t d=0,s=in?ts?ts:strlen((char*)in)+1:0; 
    char **r=*root; 
    while(r && *r++) ++d; 
    switch(op) { 
    case ADD: if(!*root) *root=calloc(1,sizeof r); 
       *root=realloc(*root,(d+2)*sizeof r); 
       memmove((*root)+1,*root,(d+1)*sizeof r); 
       memcpy(**root=malloc(s),in,s); 
       break; 
    case LOOP: while(d--) ((void (*)(char*))in)((*root)[d]); break; 
    case COUNT: return *(int*)out=d,out; 
    case FREE: if(r) { 
       ++d; while(d--) realloc((*root)[d],0); 
       free(*root);*root=0; 
       } break; 
    case GETAT: { size_t i=*(size_t*)in; 
       if(r && i<=--d) 
        return (*root)[d-i]; 
       } break; 
    case GET: { int i=-1; 
       while(++i,d--) 
       if(!(ts?memcmp:strncmp)(in,(*root)[d],s)) 
        return *(int*)out=i,out; 
       return *(int*)out=-1,out; 
       } 
    case REMOVEAT: { size_t i=*(size_t*)in; 
        if(r && i<=--d) { 
        free((*root)[d-i]); 
        memmove(&(*root)[d-i],&(*root)[d-i+1],(d-i+1)*sizeof r); 
        return in; 
        } 
       } break; 
    case REMOVE: while(*(int*)dynarray(root,ts,GET,in,&d)>=0) 
       dynarray(root,ts,REMOVEAT,&d,0); 
    } 
    return 0; 
} 

void outmy(Myp s) 
{ 
    printf("\n%s,%s,%d",s->name,s->city,s->salary); 
} 

main() 
{ 
    My z[]={{"Buffet","Omaha",INT_MAX},{"Jobs","Palo Alto",1},{"Madoff","NYC",INT_MIN}}; 
    Str80 y[]={ "123","456","7890" }; 
    char **ptr=0; 
    int x=1; 

    /* precondition for first use: ptr==NULL */ 
    dynarray(&ptr,SPTR,ADD,"test1.txt",0); 
    dynarray(&ptr,SPTR,ADD,"test2.txt",0); 
    dynarray(&ptr,SPTR,ADD,"t3.txt",0); 

    dynarray(&ptr,SPTR,REMOVEAT,&x,0); /* remove at index/key ==1 */ 
    dynarray(&ptr,SPTR,REMOVE,"test1.txt",0); 

    dynarray(&ptr,SPTR,GET,"t3.txt",&x); 
    dynarray(&ptr,SPTR,LOOP,puts,0); 

    /* another option for enumerating */ 
    dynarray(&ptr,SPTR,COUNT,0,&x); 
    while(x--) 
     puts(ptr[x]); 
    dynarray(&ptr,SPTR,FREE,0,0); /* frees all mallocs and set ptr to NULL */ 

    /* start for another (user)type */ 
    dynarray(&ptr,S80,ADD,y[0],0); 
    dynarray(&ptr,S80,ADD,y[1],0); 
    dynarray(&ptr,S80,ADD,y[2],0); 
    dynarray(&ptr,S80,ADD,y[0],0); 
    dynarray(&ptr,S80,LOOP,puts,0); 
    dynarray(&ptr,S80,FREE,0,0); /* frees all mallocs and set ptr to NULL */ 

    /* start for another (user)struct-type */ 
    dynarray(&ptr,MY,ADD,&z[0],0); 
    dynarray(&ptr,MY,ADD,&z[1],0); 
    dynarray(&ptr,MY,ADD,&z[2],0); 
    dynarray(&ptr,MY,ADD,&z[0],0); 
    dynarray(&ptr,MY,LOOP,outmy,0); 
    dynarray(&ptr,MY,FREE,0,0); 

    return 0; 
} 
+0

क्या यह पैकिंग और संरेखण के मुद्दों को ध्यान में रखता है? – Arafangion

+0

यह आकार का उपयोग करता है, सभी पैक/संरेखित सामग्री को अनदेखा करने का सबसे अच्छा तरीका – user411313

+5

भगवान! मुझे यह कोड 'साक्षात्कार क्या है?' प्रश्न के साथ एक साक्षात्कार में दिया गया है। – Sam

1

मैं आमतौर पर इस जैसे उद्देश्यों के लिए अपने खुद के कोड रोल की तरह तुमने किया था। यह विशेष रूप से कठिन नहीं है, लेकिन टाइप सुरक्षा आदि पूरी ओओ ढांचे के बिना आसानी से प्राप्त नहीं किया जा सकता है।

जैसा कि पहले बताया गया है, ग्लिब आपको जो चाहिए वह प्रदान करता है - यदि glib2 आपके लिए बहुत बड़ा है, तो आप अभी भी glib1.2 के साथ जा सकते हैं। यह काफी पुराना है, लेकिन बाहरी निर्भरता नहीं है (यदि आपको थ्रेड समर्थन की आवश्यकता है तो पर्थ्रेड को छोड़कर)। यदि आवश्यक हो, तो कोड को बड़ी परियोजनाओं में भी एकीकृत किया जा सकता है। यह एलजीपीएल लाइसेंस प्राप्त है।

2

qLibc शुद्ध सी में वेक्टर लागू करता है। डेटा संरचना इसे किसी भी प्रकार की ऑब्जेक्ट (शून्य * ऑब्जेक्ट) को स्टोर करने की अनुमति देती है और यह स्ट्रिंग, स्वरूपित स्ट्रिंग और पूर्णांक प्रकारों के लिए सुविधाजनक रैपर प्रदान करती है।

यहां आपके विचार के लिए नमूना कोड है।

qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE); 
vector->addstr(vector, "Hello"); 
vector->addstrf(vector, "World %d", 123); 
char *finalstring = vector->tostring(vector); 

printf("%s", finalstring); 
free(finalstring) 
vector->free(vector); 
ऑब्जेक्ट प्रकार के लिए

:

int a = 1, b = 2; 
qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE); 
vector->add(vector, (void *)&a, sizeof(int)); 
vector->add(vector, (void *)&b, sizeof(int)); 
int *finalarray = vector->toarray(vector); 

printf("a = %d, b = %d", finalarray[0], finalarray[1]); 
free(finalarray) 
vector->free(vector); 

नोट) मैं सिर्फ अपने संदर्भ के लिए यह नमूना कोड बनाया है, इसके उदाहरण कोड से कॉपी। इसमें टाइपो त्रुटियां हो सकती हैं।

आप अब तक समस्याओं के बिना http://wolkykim.github.io/qlibc/

0

मैं निम्नलिखित मैक्रो कार्यान्वयन उपयोग कर रहा हूँ पर पूर्ण API संदर्भ की जाँच कर सकते हैं। यह एक पूर्ण कार्यान्वयन नहीं है, लेकिन सरणी स्वचालित रूप से बढ़ता है:

#define DECLARE_DYN_ARRAY(T) \ 
    typedef struct \ 
    { \ 
     T *buf; \ 
     size_t n; \ 
     size_t reserved; \ 
    } T ## Array; 

#define DYN_ARRAY(T) T ## Array 

#define DYN_ADD(array, value, errorLabel) DYN_ADD_REALLOC(array, value, errorLabel, realloc) 

#define DYN_ADD_REALLOC(array, value, errorLabel, realloc) \ 
    { \ 
     if ((array).n >= (array).reserved) \ 
     { \ 
      if (!(array).reserved) (array).reserved = 10; \ 
      (array).reserved *= 2; \ 
      void *ptr = realloc((array).buf, sizeof(*(array).buf)*(array).reserved); \ 
      if (!ptr) goto errorLabel; \ 
      (array).buf = ptr; \ 
     } \ 
     (array).buf[(array).n++] = value; \ 
    } 

आप पहली बार लिखने का उपयोग करें: DECLARE_DYN_ARRAY(YourType)

चर आप DYN_ARRAY(YourType) array = {0} लिखने की घोषणा करने के लिए।

आप DYN_ADD(array, element, errorLabel) के साथ तत्व जोड़ते हैं।

आप array.buf[i] के साथ तत्वों तक पहुंचते हैं।

आपको array.n के साथ तत्वों की संख्या मिलती है।

काम पूरा हो जाने आप free(array.buf) के साथ मुक्त कर (या जो भी समारोह आप इसे आवंटित करने के लिए प्रयोग किया जाता है।)

+0

दुर्भाग्य से, यह कार्यान्वयन सूचक प्रकार के लिए अनुमति नहीं देता है। – YoYoYonnY

संबंधित मुद्दे