सेल्फ रेफ़रल स्ट्रक्चर परिभाषा?


134

मैं बहुत लंबे समय से सी नहीं लिख रहा हूं, और इसलिए मुझे यकीन नहीं है कि मुझे इन प्रकार की पुनरावर्ती चीजों के बारे में कैसे जाना चाहिए ... मैं चाहूंगा कि प्रत्येक सेल में एक और सेल शामिल हो, लेकिन मुझे एक त्रुटि मिलती है "फ़ील्ड 'चाइल्ड' की पंक्तियों में अपूर्ण प्रकार है"। क्या हो रहा है?

typedef struct Cell {
  int isParent;
  Cell child;
} Cell;

9
PS असल में यह "स्ट्रक्चर सेल" से "सेल" टाइप करता है (यह एक सामान्य पैटर्न है)
David Z

वह शायद C ++ कंपाइलर का उपयोग कर रहा है। वह भी _Bool का उपयोग करना चाहिए अगर यह वास्तव में सी है
nabiy

अगर वह वास्तव में C :-)
paxdiablo

2
क्यों? C99 में बूल है - आपको बस <stdbool.h> शामिल करने की आवश्यकता है
जोनाथन

जवाबों:


184

स्पष्ट रूप से एक सेल में दूसरा सेल नहीं हो सकता क्योंकि यह एक कभी न खत्म होने वाली पुनरावृत्ति बन जाता है।

हालाँकि एक सेल में दूसरे सेल में पॉइंटर हो सकता है।

typedef struct Cell {
  bool isParent;
  struct Cell* child;
} Cell;

7
@ cs01 नहीं, Cellअभी तक दायरे में नहीं है।
फ्रेडओवरफ्लो

1
यह होगा मतलब। अजगर इसे अनुमति देता है और यहां तक ​​कि इस तरह की वस्तु को क्रमबद्ध करने की भी अनुमति देता है। C ++ क्यों नहीं?
no --zɐɹƆ

1
जब मैं असाइन Cell*करने का प्रयास करता हूं तो मुझे चेतावनी मिलती है cell->child
टॉम ज़ातो -

3
@ no @z point क्योंकि पायथन अमूर्त बिंदुओं को दूर करता है ताकि आप उन्हें नोटिस न करें। चूंकि structसी में मूल रूप से बस उनके सभी मूल्यों को एक-दूसरे के बगल में संग्रहीत किया जाता है, इसलिए वास्तव में एक संरचना को अपने आप में संग्रहीत करना असंभव होगा (क्योंकि उस संरचना में एक और एक को शामिल करना होगा और अनंत आकार की स्मृति संरचना के लिए अग्रणी होगा) ।
जैज़पी

1
के उपयोग की व्याख्या के लिए struct Cell, इस उत्तर को देखें ।
wizzwizz4

26

C में, आप उस टाइपफ़ीड को संदर्भित नहीं कर सकते हैं जिसे आप स्वयं संरचना बना रहे हैं। आपको निम्न परीक्षण कार्यक्रम में संरचना नाम का उपयोग करना होगा:

#include <stdio.h>
#include <stdlib.h>

typedef struct Cell {
  int cellSeq;
  struct Cell* next; /* 'tCell *next' will not work here */
} tCell;

int main(void) {
    int i;
    tCell *curr;
    tCell *first;
    tCell *last;

    /* Construct linked list, 100 down to 80. */

    first = malloc (sizeof (tCell));
    last = first;
    first->cellSeq = 100;
    first->next = NULL;
    for (i = 0; i < 20; i++) {
        curr = malloc (sizeof (tCell));
        curr->cellSeq = last->cellSeq - 1;
        curr->next = NULL;
        last->next = curr;
        last = curr;
    }

    /* Walk the list, printing sequence numbers. */

    curr = first;
    while (curr != NULL) {
        printf ("Sequence = %d\n", curr->cellSeq);
        curr = curr->next;
    }

    return 0;
}

हालाँकि यह मानक में इससे कहीं अधिक जटिल है, आप इसे संकलक के रूप में सोच सकते struct Cellहैं, typedefलेकिन tCellअंतिम पंक्ति के बारे में नहीं जानते हैं , लेकिन अंतिम नियम के बारे में नहीं जानते हैं कि कैसे मैं उस नियम को याद रखता हूं।


c ++ के बारे में क्या आप सी + + के बारे में जवाबों को लिंक कर सकते हैं
rimalonfire

@rimiro, सवाल एक सी एक था। यदि आप C ++ संस्करण के लिए उत्तर चाहते हैं, तो आपको इसे एक प्रश्न के रूप में पूछना चाहिए ।
paxdiablo

16

सैद्धांतिक दृष्टिकोण से, भाषाएं केवल आत्म-संदर्भित संरचनाओं का समर्थन कर सकती हैं, न कि आत्म-समावेशी संरचनाएं।


व्यावहारिक दृष्टिकोण से, 'स्ट्रक्चर सेल' का ऐसा उदाहरण वास्तव में कितना बड़ा होगा?
मार्श रे

26
अधिकांश मशीनों पर, चार बाइट्स अपने आप से बड़ी होती हैं।
टोनीके

13

इसके चारों ओर एक तरह से है:

struct Cell {
  bool isParent;
  struct Cell* child;
};

struct Cell;
typedef struct Cell Cell;

यदि आप इसे इस तरह से घोषित करते हैं, तो यह कंपाइलर को ठीक से बताता है कि स्ट्रक्चर सेल और प्लेन-ओएल-सेल समान हैं। तो आप सामान्य की तरह ही सेल का उपयोग कर सकते हैं। हालांकि अभी भी प्रारंभिक घोषणा के अंदर ही स्ट्रक्चर सेल का उपयोग करना है।


9
आपने struct Cell;फिर से क्यों लिखा ?
MAKZ

@MAKZ क्योंकि उस समय कंपाइलर द्वारा टाइप किए गए एफआईएफ को निष्पादित नहीं किया गया है, जिसकी परिभाषा वह संकलित कर रहा है struct Cell
टायलर क्रॉम्पटन

2
@TylerCrompton यदि उपरोक्त कोड ब्लॉक को एकल सी स्रोत फ़ाइल में डाल दिया जाता है, तो अतिरिक्त कंपाउंड द्वारा टाइप किए गए "कंपाइलर द्वारा निष्पादित" किया गया है struct Cell;। यदि, हालांकि, किसी कारण से आपने हेडर फ़ाइल में अंतिम दो पंक्तियाँ डाल दी हैं, जिसे आप पहले चार पंक्तियों के साथ संरचना को परिभाषित करने से पहले शामिल करते हैं Cell, तो अतिरिक्त struct Cell;नीरस है।
19

यह भी C99 मानक के तहत संकलन नहीं करता है।
टॉम ज़ातो -

2
@YoYoYonnY नहीं, आप अभी भी लिख सकते हैं typedef struct Cell Cell;और यह Cellएक उपनाम बना देगा struct Cell। इससे कोई फर्क नहीं पड़ता कि संकलक ने struct Cell { .... }पहले देखा है या नहीं ।
मेलपोमीन

8

मुझे पता है कि यह पोस्ट पुरानी है, हालांकि, जिस प्रभाव की तलाश में हैं, उसे प्राप्त करने के लिए, आप निम्नलिखित प्रयास करना चाह सकते हैं:

#define TAKE_ADVANTAGE

/* Forward declaration of "struct Cell" as type Cell. */
typedef struct Cell Cell;

#ifdef TAKE_ADVANTAGE
/*
   Define Cell structure taking advantage of forward declaration.
*/
struct Cell
{
   int isParent;
   Cell *child;
};

#else

/*
   Or...you could define it as other posters have mentioned without taking
   advantage of the forward declaration.
*/
struct Cell
{
   int isParent;
   struct Cell *child;
};

#endif

/*
    Some code here...
*/

/* Use the Cell type. */
Cell newCell;

ऊपर दिए गए कोड के टुकड़े में वर्णित दोनों में से किसी भी मामले में, आपको अपने बच्चे के सेल संरचना को सूचक के रूप में घोषित करना होगा। यदि आप नहीं करते हैं, तो आपको "फ़ील्ड 'बच्चा' अधूरा प्रकार" त्रुटि मिलेगा। कारण यह है कि "स्ट्रक्चर सेल" को संकलक के लिए परिभाषित किया जाना चाहिए ताकि यह पता चल सके कि इसका उपयोग करने पर कितना स्थान आवंटित करना है।

यदि आप "स्ट्रक्चर सेल" की परिभाषा के अंदर "स्ट्रक्चर सेल" का उपयोग करने का प्रयास करते हैं, तो कंपाइलर को अभी तक पता नहीं चल सकता है कि "स्ट्रक्चर सेल" को कितना स्पेस लेना है। हालांकि, संकलक को पहले से ही पता है कि एक पॉइंटर कितना स्थान लेता है, और (आगे की घोषणा के साथ) यह जानता है कि "सेल" एक प्रकार का "स्ट्रक्चर सेल" है (हालांकि यह अभी तक नहीं पता है कि एक "स्ट्रक्चर सेल" कितना बड़ा है) )। इसलिए, कंपाइलर परिभाषित किए जा रहे ढांचे के भीतर "सेल *" को परिभाषित कर सकता है।


3

टंकण की मूल परिभाषा के माध्यम से चलें। एक मौजूदा डेटा प्रकार के लिए एक उपनाम को परिभाषित करने के लिए टाइपडिफ का उपयोग या तो यह उपयोगकर्ता द्वारा परिभाषित या इनबिल्ट है।

typedef <data_type> <alias>;

उदाहरण के लिए

typedef int scores;

scores team1 = 99;

एक ही डेटा प्रकार के एक सदस्य के कारण भ्रम यहां आत्म-संदर्भ संरचना के साथ है, जो पहले परिभाषित नहीं है। तो मानक तरीके से आप अपना कोड इस प्रकार लिख सकते हैं: -

//View 1
typedef struct{ bool isParent; struct Cell* child;} Cell;

//View 2
typedef struct{
  bool isParent;
  struct Cell* child;
} Cell;

//Other Available ways, define stucture and create typedef
struct Cell {
  bool isParent;
  struct Cell* child;
};

typedef struct Cell Cell;

लेकिन अंतिम विकल्प कुछ अतिरिक्त पंक्तियों और शब्दों को बढ़ाते हैं, आमतौर पर हम ऐसा नहीं करना चाहते हैं (हम बहुत आलसी हैं जो आप जानते हैं;))। तो देखें 2 पसंद करते हैं।


typedefवाक्यविन्यास की आपकी व्याख्या गलत है (उदाहरण के लिए typedef int (*foo)(void);)। आपका दृश्य 1 और दृश्य 2 उदाहरण काम नहीं करते: वे struct Cellएक अपूर्ण प्रकार बनाते हैं , इसलिए आप वास्तव childमें अपने कोड में उपयोग नहीं कर सकते ।
मेलपोमिन

3

एक अन्य सुविधाजनक तरीका है संरचना के साथ टाइप-पूर्व टाइप करना, संरचना टैग इस प्रकार है:

//declare new type 'Node', as same as struct tag
typedef struct Node Node;
//struct with structure tag 'Node'
struct Node
{
int data;
//pointer to structure with custom type as same as struct tag
Node *nextNode;
};
//another pointer of custom type 'Node', same as struct tag
Node *node;

1

एक संरचना जिसमें खुद के लिए एक संदर्भ होता है। एक संरचना में इसका एक सामान्य घटना है जो एक लिंक सूची के लिए नोड का वर्णन करता है। प्रत्येक नोड को श्रृंखला में अगले नोड के लिए एक संदर्भ की आवश्यकता होती है।

struct node
{
       int data;
       struct node *next; // <-self reference
};

1

पिछले सभी उत्तर महान हैं, मैंने सिर्फ इस बात पर एक अंतर्दृष्टि देने के लिए सोचा कि एक संरचना में अपने स्वयं के प्रकार (संदर्भ नहीं) का उदाहरण क्यों नहीं हो सकता है।

यह ध्यान रखना बहुत महत्वपूर्ण है कि संरचनाएं 'मूल्य' प्रकार की होती हैं अर्थात उनमें वास्तविक मूल्य होता है, इसलिए जब आप एक संरचना की घोषणा करते हैं तो संकलक को यह तय करना होगा कि इसका एक उदाहरण के लिए कितनी मेमोरी आवंटित की जाए, इसलिए यह अपने सभी सदस्यों के माध्यम से जाता है और जोड़ता है संरचना की सभी मेमोरी को समाप्त करने के लिए उनकी मेमोरी को बढ़ाएं, लेकिन यदि कंपाइलर को उसी संरचना का एक उदाहरण मिला है तो यह एक विरोधाभास है (यानी यह जानने के लिए कि मेमोरी मेमोरी आपको कितनी मेमोरी तय करनी है? संरचना ए लेता है!)।

लेकिन संदर्भ प्रकार भिन्न होते हैं, यदि किसी संरचना 'ए' में अपने स्वयं के प्रकार के उदाहरण के लिए एक 'संदर्भ' होता है, हालांकि हम अभी तक यह नहीं जानते हैं कि इसके लिए कितनी मेमोरी आवंटित की गई है, हम जानते हैं कि एक मेमोरी को कितनी मेमोरी आवंटित की जाती है पता (यानी संदर्भ)।

HTH

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.