2016-08-11 7 views
5

कोई ऐसा क्यों करेगा? बेहतर अभी तक यह कैसे काम करता है? मुझे लगता है कि यह किसी भी तरह से केवल पहले सदस्य परिभाषित किए गए तीन संरचनाओं की एक सरणी बना देगा। मुझे सरणी के पहले तत्व को पॉइंटर पॉइंट का एहसास है, और मैं देखता हूं कि यह कैसे काम कर सकता है लेकिन यह कैसे परिभाषित किया गया है मुझे फेंक रहा है! (जीसीसी 4.8.4)संरचना की एक सरणी का प्रारंभ एक तत्व के सभी सदस्यों को शुरू करता है, क्यों?

void do_something(const void *); 

typedef struct{ 

int a; 
char b; 
int c; 

} the_data_t; 

int main(int argc, char *argv[]) 
{ 
    the_data_t my_data[] = {10, 'a', 30}; 
    do_something((const void *)my_data); 
} 

void do_something(const void *data) 
{ 
    printf("data a: %d\ndata b: %c\ndata c: %d\n", ((the_data_t*)data)->a, 
     ((the_data_t*)data)->b, ((the_data_t*)data)->c); 
} 

आउटपुट

डेटा एक: 10
डेटा ख: एक
डेटा c: 30

भले ही, मैं इसे इस के लिए बदल दिया है।

int main(int argc, char *argv[]) 
{ 
    the_data_t my_data = {10, 'a', 30}; 
    do_something(&my_data); 
} 
+1

आपको असली कोड दिखाना चाहिए। यह हो सकता है कि सहायक कार्य को सरणी के साथ काम करने के लिए डिज़ाइन किया गया हो।इसलिए यदि किसी सरणी में एक तत्व भी है तो आपको इसे एक ही संरचना के बजाय सरणी के रूप में घोषित करना चाहिए। –

+2

संरचना के केवल भाग को शुरू करने का कोई तरीका नहीं है, यह सब कुछ या कुछ भी नहीं है। – molbdnilo

उत्तर

8

मैं इस किसी भी तरह केवल पहले सदस्य के साथ तीन संरचनाओं की एक सरणी बनाने मान लिया है |

नहीं परिभाषित है, यह उस तरह से नहीं है। असल में यह सभी तत्वों के साथ, एक तत्व की एक सरणी बनाता है।

का हवाला देते हुए C11, अध्याय §6.7.9

प्रत्येक ब्रेस संलग्न प्रारंभकर्ता सूची एक संबद्ध मौजूदा वस्तु है। जब कोई पदनाम मौजूद नहीं हैं, तो मौजूदा ऑब्जेक्ट के प्रकार के लिए के अनुसार वर्तमान ऑब्जेक्ट का सबोबजेक्ट प्रारंभ किया गया है: सबस्क्रिप्ट ऑर्डर बढ़ाने में सरणी तत्व, घोषणा क्रम में सदस्यों और संघ के पहले नामित सदस्य। [...]

और

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

और

[...] एक subaggregate के प्रारंभकर्ता या निहित संघ एक छोड़ दिया ब्रेस के साथ शुरू होता है, तो initializers कि संभालो और उसके मिलान दायां कोष्ठक से घिरा तत्वों को प्रारंभ या उपसमूह या निहित संघ के सदस्य। अन्यथा, सूची से केवल पर्याप्त प्रारंभकर्ता उपनिवेश के तत्वों या सदस्यों के लिए खाते गए हैं या निहित संघ के पहले सदस्य हैं; [...]

मूल रूप से, अपने कोड आदर्श

की तरह लग रहे
the_data_t my_data[] = {{10, 'a', 30}}; 

एक तत्व आरंभ कल्पना करने के लिए करना चाहिए।

OTOH, जिसकी आपको उम्मीद से

the_data_t my_data[] = {{10}, {'a'}, {30}}; 

जहां यह 3 तत्वों की एक सरणी बनाता है, सभी सदस्य चर a प्रारंभ होने से प्राप्त किया जा सकता है।


जिसके अनुसार,

the_data_t my_data[] = {{10, 'a', 30}}; 

भाग को छोड़कर

the_data_t my_data = {10, 'a', 30}; 

लेखन के बराबर है, my_data एक सरणी अब और नहीं होगा (लेकिन क्या अच्छा एक एक तत्व सरणी है, सामान्य रूप से, या तो?)।

+1

"सामान्य रूप से एक तत्व सरणी कितनी अच्छी है," -> यह कोड को "संदर्भ" [जीएमपी उदाहरण] द्वारा पारित करने की अनुमति देता है (https://gmplib.org/list-archives/gmp-discuss/2008- मार्च /003085.html) अनुसंधान कैसे करें 'mpz_t' घोषित किया गया है। – chux

+0

यह उत्तर अनिवार्य रूप से सही है, लेकिन यह बहुत स्पष्ट होगा यदि उसने सी2011 6.7.9/20 का भी उल्लेख किया है, जो उस मामले के लिए अर्थशास्त्र का स्पष्ट रूप से वर्णन करता है जहां सदस्य के प्रारंभिककर्ता के आसपास कोई ब्रेसिज़ नहीं है, जैसा कि यहां देखा गया है। –

+0

@ जॉन बोलिंगर अपडेट किया गया, अगर यह मदद करता है। –

2

यह उचित नहीं है। जीसीसी आपको इसके लिए चेतावनी देगा:

warning: missing braces around initializer 
warning: (near initialization for ‘my_data[0]’) 

यह क्या करेगा 1 तत्व सरणी बनाना।

+0

जीसीसी चेतावनी देता है, और मैं इसके साथ सहमत हूं और आपके साथ सदस्य प्रारंभकर्ताओं के चारों ओर ब्रेसिज़ को छोड़कर खराब शैली है। लेकिन यह सब * यह है। कोड इस अर्थ में पूरी तरह से उचित है कि यह मानक के अनुरूप है। –

3

संकलक व्यवहार करेगा

the_data_t my_data[] = {10, 'a', 30}; 

रूप

the_data_t my_data[1] = {{ 10, 'a', 30 }}; // Though it will raise warning. 

तो, my_data एक the_data_t प्रकार की एक सरणी है।

यह जब एक दो आयामी सरणी a के आकार की तरह इस

int a[][3] = { 1, 2, 3 }; 

तो संकलक यह मानकर चलेगा

int a[1][3] = { { 1, 2, 3 } }; 

प्रिंट घोषित किया जाता है और आप 12 मिल जाएगा के समान है (यदि आकार उस मशीन पर int4 है)।

+0

स्पष्ट रूप से उपयोग में विशेष कंपाइलर * जैसा कि आप वर्णन करते हैं, प्रारंभकर्ता की व्याख्या करता है, लेकिन मुझे यह देखने में परेशानी हो रही है कि मानक द्वारा उस व्यवहार का वर्णन कैसे किया जाता है। –

+0

@ जॉन बोलिंगर; यह धारा ** 6.7.9/20 ** में वर्णित है: * यदि एक उपनिवेश या निहित संघ का प्रारंभकर्ता बाएं ब्रेस के साथ शुरू होता है, तो उस ब्रेस और उसके मिलान करने वाले दाएं ब्रेस द्वारा प्रारंभ किए गए प्रारंभिक तत्व उप-योग के तत्वों या सदस्यों को प्रारंभ करते हैं या निहित संघ। अन्यथा, सूची से केवल पर्याप्त प्रारंभकर्ता तत्वों या उपनिवेश के सदस्यों या निहित संघ के पहले सदस्य के लिए खाते में लिया जाता है; किसी भी शेष प्रारंभकर्ता को अगले तत्व या कुल के सदस्य को प्रारंभ करने के लिए छोड़ दिया जाता है, जिसमें वर्तमान उप-योग या [...]। * – haccks

2

जीसीसी आपको चेतावनी स्विच का उपयोग करने पर इस मुद्दे के बारे में चेतावनी देगा।

$ gcc -Wall test.c 
test.c: In function ‘main’: 
test.c:14:25: warning: missing braces around initializer [-Wmissing-braces] 
the_data_t my_data[] = {10, 'a', 30}; 
         ^
test.c:14:25: note: (near initialization for ‘my_data’) 
$ 

इसे ठीक करने के लिए या तो आप ठीक ढंग से के रूप में सरणी को प्रारंभ कर सकते हैं:

the_data_t my_data[] = {{10, 'a', 30}}; 

या, जैसा कि आप पोस्ट में पता चला, तो आप एक struct चर को my_data बदल सकते हैं।

the_data_t my_data = {10, 'a', 30}; // And call do_something as 
do_something((const void *)&my_data); 
संबंधित मुद्दे

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