array - what is structure in c in hindi




टाइपपीफ संरचना बनाम संरचना परिभाषा (8)

इस प्रश्न का उत्तर यहां दिया गया है:

मैं सी प्रोग्रामिंग में एक नौसिखिया हूं, लेकिन मैं सोच रहा था कि टाइपपीफ का उपयोग न करने के दौरान एक संरचना को परिभाषित करते समय टाइपपीफ का उपयोग करने के बीच क्या अंतर है। ऐसा लगता है कि वास्तव में कोई फर्क नहीं पड़ता है, वे इसे पूरा करते हैं।

struct myStruct{
    int one;
    int two;
};

बनाम

typedef struct{
    int one;
    int two;
}myStruct;

आप typedef struct साथ आगे की घोषणा का उपयोग नहीं कर सकते हैं।

struct स्वयं एक अज्ञात प्रकार है, इसलिए आपके पास घोषित करने के लिए वास्तविक नाम नहीं है।

typedef struct{
    int one;
    int two;
} myStruct;

इस तरह की एक आगे की घोषणा काम नहीं करेगा:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

आम मुहावरे दोनों का उपयोग कर रहा है:

typedef struct X { 
    int x; 
} X;

वे अलग-अलग परिभाषाएं हैं। चर्चा को स्पष्ट करने के लिए मैं वाक्य को विभाजित कर दूंगा:

struct S { 
    int x; 
};

typedef struct S S;

पहली पंक्ति में आप पहचानकर्ता नाम के भीतर पहचानकर्ता S को परिभाषित कर रहे हैं (सी ++ समझ में नहीं)। आप इसका उपयोग कर सकते हैं और तर्क के प्रकार को परिभाषित करके नए परिभाषित प्रकार के चर या फ़ंक्शन तर्क परिभाषित कर सकते हैं:

void f( struct S argument ); // struct is required here

दूसरी पंक्ति वैश्विक नाम स्थान में एक प्रकार उपनाम S जोड़ती है और इस प्रकार आपको केवल लिखने की अनुमति देती है:

void f( S argument ); // struct keyword no longer needed

ध्यान दें कि चूंकि पहचानकर्ता नाम रिक्त स्थान अलग-अलग हैं, इसलिए दोनों को structs और वैश्विक रिक्त स्थान में परिभाषित करना एक त्रुटि नहीं है, क्योंकि यह समान पहचानकर्ता को फिर से परिभाषित नहीं कर रहा है, बल्कि एक अलग स्थान पर एक अलग पहचानकर्ता बना रहा है।

अंतर स्पष्ट करने के लिए:

typedef struct S { 
    int x; 
} T;

void S() { } // correct

//void T() {} // error: symbol T already defined as an alias to 'struct S'

आप संरचना के समान नाम के साथ एक फ़ंक्शन को परिभाषित कर सकते हैं क्योंकि पहचानकर्ता अलग-अलग रिक्त स्थानों में रखे जाते हैं, लेकिन आप typedef रूप में उसी नाम के साथ फ़ंक्शन को परिभाषित नहीं कर सकते हैं क्योंकि उन पहचानकर्ता टकराते हैं।

सी ++ में, यह थोड़ा अलग है क्योंकि प्रतीक का पता लगाने के नियमों में काफी बदलाव आया है। सी ++ अभी भी दो अलग पहचानकर्ता रिक्त स्थान रखता है, लेकिन सी के विपरीत, जब आप कक्षा पहचानकर्ता अंतरिक्ष के भीतर केवल प्रतीक को परिभाषित करते हैं, तो आपको संरचना / वर्ग कीवर्ड प्रदान करने की आवश्यकता नहीं होती है:

 // C++
struct S { 
    int x; 
}; // S defined as a class

void f( S a ); // correct: struct is optional

खोज नियम क्या परिवर्तन हैं, न कि पहचानकर्ताओं को परिभाषित किया गया है। कंपाइलर वैश्विक पहचानकर्ता तालिका खोजेगा और S बाद यह नहीं मिला है कि यह वर्ग पहचानकर्ताओं के भीतर S खोज करेगा।

पहले प्रस्तुत कोड उसी तरीके से व्यवहार करता है:

typedef struct S { 
    int x; 
} T;

void S() {} // correct [*]

//void T() {} // error: symbol T already defined as an alias to 'struct S'

दूसरी पंक्ति में S फ़ंक्शन की परिभाषा के बाद, संरचना एस को संकलक द्वारा स्वचालित रूप से हल नहीं किया जा सकता है, और किसी ऑब्जेक्ट को बनाने या उस प्रकार के तर्क को परिभाषित करने के लिए आपको struct कीवर्ड समेत वापस आना चाहिए:

// previous code here...
int main() {
    S(); 
    struct S s;
}

जब आप struct उपयोग करते हैं तो अंतर आता है।

आपको पहला तरीका करना है:

struct myStruct aName;

दूसरा तरीका आपको कीवर्ड struct को हटाने की अनुमति देता है।

myStruct aName;

निम्न कोड उपनाम myStruct साथ एक अज्ञात संरचना बनाता है:

typedef struct{
    int one;
    int two;
} myStruct;

आप इसे उपनाम के बिना संदर्भित नहीं कर सकते क्योंकि आप संरचना के लिए पहचानकर्ता निर्दिष्ट नहीं करते हैं।


मुझे इस पर कुछ स्पष्टीकरण दिख रहा है। सी और सी ++ अलग-अलग प्रकारों को परिभाषित नहीं करते हैं। सी ++ मूल रूप से सी के शीर्ष पर शामिल एक अतिरिक्त सेट से अधिक कुछ नहीं था।

समस्या यह है कि लगभग सभी सी / सी ++ डेवलपर्स आज है, ए) विश्वविद्यालय अब मूलभूत सिद्धांतों को पढ़ रहे हैं, और बी) लोग परिभाषा और घोषणा के बीच अंतर को नहीं समझते हैं।

इस तरह की घोषणाओं और परिभाषाओं का एकमात्र कारण मौजूद है ताकि लिंकर संरचना में फ़ील्ड में पता ऑफसेट की गणना कर सके। यही कारण है कि ज्यादातर लोग कोड से दूर हो जाते हैं जो वास्तव में गलत तरीके से लिखा जाता है - क्योंकि संकलक संबोधित करने में सक्षम होता है। समस्या उत्पन्न होती है जब कोई कतार, या एक लिंक्ड सूची की तरह कुछ अग्रिम करने की कोशिश करता है, या एक ओ / एस संरचना को पिगिंग-बैकिंग करता है।

एक घोषणा 'संरचना' से शुरू होती है, एक परिभाषा 'typedef' से शुरू होती है।

इसके अलावा, एक संरचना में एक आगे घोषित घोषणा लेबल, और एक परिभाषित लेबल है। अधिकांश लोग इसे नहीं जानते हैं और आगे की घोषणा लेबल को परिभाषित लेबल के रूप में उपयोग करते हैं।

गलत:

struct myStruct
   {
   int field_1;
   ...
   };

उन्होंने संरचना को लेबल करने के लिए अभी आगे की घोषणा का उपयोग किया है - इसलिए अब संकलक इसके बारे में जानते हैं - लेकिन यह वास्तविक परिभाषित प्रकार नहीं है। संकलक पते की गणना कर सकता है - लेकिन ऐसा नहीं है कि इसका उपयोग कैसे किया जाना चाहिए, कारणों से मैं क्षणिक रूप से दिखाऊंगा।

जो लोग घोषणा के इस रूप का उपयोग करते हैं, उन्हें हमेशा हर संदर्भ में 'संरचना' रखना चाहिए - क्योंकि यह एक अपमानजनक नया प्रकार नहीं है।

इसके बजाए, कोई भी संरचना जो खुद को संदर्भित नहीं करती है, को इस तरह घोषित और परिभाषित किया जाना चाहिए:

typedef struct
   {
   field_1;
   ...
   }myStruct;

अब यह एक वास्तविक प्रकार है, और जब इस्तेमाल किया जाता है तो आप इसे 'स्ट्रक्चर' शब्द के साथ प्रीपेड किए बिना 'myStruct' के रूप में उपयोग कर सकते हैं।

यदि आप उस संरचना में पॉइंटर चर चाहते हैं, तो एक द्वितीयक लेबल शामिल करें:

typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;

अब आपके पास उस संरचना के लिए एक पॉइंटर चर है, इसके लिए कस्टम।

फॉरवर्ड डिसक्लेरेशन -

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

typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;

अब, संकलक जानता है कि हालांकि यह नहीं जानता कि पूरा प्रकार अभी तक क्या है, फिर भी यह आगे संदर्भ का उपयोग करके इसका संदर्भ दे सकता है।

कृपया अपनी संरचनाओं को सही तरीके से घोषित करें और टाइप करें। वास्तव में एक कारण है।


यदि आप struct बिना struct उपयोग करते हैं, तो आपको हमेशा लिखना होगा

struct mystruct myvar;

लिखना अवैध है

mystruct myvar;

यदि आप typedef उपयोग करते हैं तो आपको अब struct उपसर्ग की आवश्यकता नहीं है।


सी में, संरचनाओं, यूनियनों और गणनाओं के विशिष्ट विनिर्देशक कीवर्ड अनिवार्य हैं, यानी आपको प्रकार के संदर्भ union struct , union या enum साथ हमेशा प्रकार के नाम (इसके टैग ) को उपसर्ग करना होगा।

आप typedef का उपयोग करके कीवर्ड से छुटकारा पा सकते हैं, जो एक वस्तु का वास्तविक प्रकार है, जो किसी ऑब्जेक्ट के वास्तविक प्रकार के रूप में छुपाए जाने पर दिखाई नहीं दे रहा है।

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

जब आपको typedef उपयोग करना चाहिए तो इसका एक उदाहरण एक अपारदर्शी प्रकार होगा जिसका उपयोग केवल इसी एक्सेसर फ़ंक्शंस / मैक्रोज़ के साथ किया जाता है।


struct और typedef दो अलग-अलग चीजें हैं।

struct कीवर्ड को संरचना प्रकार को परिभाषित करने या संदर्भित करने के लिए उपयोग किया जाता है। उदाहरण के लिए, यह:

struct foo {
    int n;
};

struct foo नामक एक नया प्रकार बनाता है। नाम foo एक टैग है ; यह केवल अर्थपूर्ण है जब यह तुरंत struct कीवर्ड द्वारा किया जाता है, क्योंकि टैग और अन्य पहचानकर्ता अलग-अलग नाम रिक्त स्थान पर होते हैं । (यह समान है, लेकिन namespace की सी ++ अवधारणा से कहीं अधिक प्रतिबंधित है।)

एक typedef , नाम के बावजूद, एक नए प्रकार को परिभाषित नहीं करता है; यह केवल मौजूदा प्रकार के लिए एक नया नाम बनाता है। उदाहरण के लिए, दिया गया:

typedef int my_int;

my_int int लिए एक नया नाम है; my_int और int बिल्कुल वही प्रकार हैं। इसी प्रकार, उपरोक्त struct परिभाषा को देखते हुए, आप लिख सकते हैं:

typedef struct foo foo;

इस प्रकार के पास पहले से ही एक नाम है, struct footypedef घोषणा उसी प्रकार को एक नया नाम देती है, foo

वाक्यविन्यास आपको एक एकल घोषणा में एक struct और typedef को गठबंधन करने की अनुमति देता है:

typedef struct bar {
    int n;
} bar;

यह एक आम मुहावरे है। अब आप इस संरचना प्रकार को या तो struct bar या struct bar रूप में देख सकते हैं।

ध्यान दें कि टाइप किए गए नाम को घोषणा के अंत तक दिखाई नहीं देता है। यदि संरचना में स्वयं के लिए एक सूचक शामिल है, तो आपने इसे संदर्भित करने के लिए struct संस्करण का उपयोग किया है:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;

कुछ प्रोग्रामर स्ट्रक्चर टैग के लिए और टाइप किए गए नाम के लिए अलग पहचानकर्ताओं का उपयोग करेंगे। मेरी राय में, इसके लिए कोई अच्छा कारण नहीं है; एक ही नाम का उपयोग पूरी तरह से कानूनी है और यह स्पष्ट करता है कि वे एक ही प्रकार के हैं। यदि आपको विभिन्न पहचानकर्ताओं का उपयोग करना चाहिए, कम से कम एक सतत सम्मेलन का उपयोग करें:

typedef struct node_s {
    /* ... */
} node;

(व्यक्तिगत रूप से, मैं टाइपिफ़ को छोड़ना पसंद करता हूं और प्रकार को struct bar रूप में संदर्भित करता हूं। typedef थोड़ा टाइपिंग सहेजता है, लेकिन यह इस तथ्य को छुपाता है कि यह एक संरचना प्रकार है। अगर आप टाइप अपारदर्शी होना चाहते हैं, तो यह अच्छा हो सकता है अगर ग्राहक कोड नाम से सदस्य n जिक्र करने जा रहा है, तो यह अपारदर्शी नहीं है; यह स्पष्ट रूप से एक संरचना है, और मेरी राय में इसे एक संरचना के रूप में संदर्भित करना समझ में आता है। लेकिन बहुत से स्मार्ट प्रोग्रामर मुझसे असहमत हैं इस बिंदु पर। किसी भी तरह से लिखे गए कोड को पढ़ने और समझने के लिए तैयार रहें।)

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





typedef