2010-07-15 5 views
22

सी में निम्नलिखित घोषणा:सी में सूचक वाक्यविन्यास: क्यों * केवल पहले चर पर लागू होता है?

int* a, b; 

प्रकार int रूप a प्रकार int* के रूप में और b घोषित करेंगे। मैं इस जाल के बारे में अच्छी तरह से जानता हूं, लेकिन मैं क्या जानना चाहता हूं क्यों यह इस तरह से काम करता है। यह b को int* के रूप में भी घोषित नहीं करता है, क्योंकि अधिकांश लोग सहजता से अपेक्षा करते हैं? दूसरे शब्दों में, * क्यों प्रकार के बजाय परिवर्तनीय नाम पर लागू होता है?

सुनिश्चित करें कि आप इसे इस तरह लिख सकता है कि यह कैसे वास्तव में काम करता है के साथ और स्थायी:

int *a, b; 

हालांकि, मैं और सभी को मैं के संदर्भ में सोचने के लिए प्रकार का एक है "बात की है सूचकांक, ए के बजाय सूचक कुछ डेटा के लिए एक सूचक है और उस डेटा का प्रकार "int" है।

क्या यह सी के डिजाइनरों द्वारा बस एक बुरा निर्णय था या क्या इसका कोई अच्छा कारण है कि इसे इस तरह से पार्स किया गया है? मुझे यकीन है कि प्रश्न का उत्तर पहले दिया गया है, लेकिन मुझे खोज का उपयोग करके यह प्रतीत नहीं होता है।

+7

ईमानदार होने के लिए, यदि सी भाषा ने '* 'प्रकार को संशोधित किया है तो हम लोग पूछेंगे कि" int * a * b क्यों नहीं है,' मुझे एक सूचक और पूर्णांक दें? "। – bta

+2

@bta, हाँ, हम करेंगे - लेकिन मुझे लगता है कि यह कम लोगों को भ्रमित कर देगा। वैसे भी, बिंदु 40 साल पहले किए गए फैसले के बारे में बहस नहीं करना है, यह समझने के लिए है कि इसके कारण हैं जिनके बारे में मुझे पता नहीं है। – EMP

+0

आप इसे http://c-faq.com/decl/charstarws.html – Amarghosh

उत्तर

17

The Development of the C Language पर एक वेब पेज है जो कहता है, "इन घोषणाओं का वाक्यविन्यास अवलोकन को दर्शाता है कि I, * pi, और ** ppi सभी अभिव्यक्ति में उपयोग किए जाने पर एक int प्रकार उत्पन्न करते हैं।" इस प्रश्न के बारे में बात करने वाले प्रासंगिक खंड को खोजने के लिए पृष्ठ पर उस वाक्य की खोज करें।

9

एक अतिरिक्त ऐतिहासिक कारण हो सकता है, लेकिन मैं हमेशा इसे इस तरह समझ लिया है:

एक घोषणा, एक प्रकार।

int a, b, c, d; 

फिर लाइन पर सब कुछ करना होगा एक पूर्णांक के रूप में अच्छी तरह से:

तो एक, ख, ग, और घ एक ही प्रकार के यहाँ होना चाहिए।

int a, *b, **c, ***d; 

4 पूर्णांकों:

  1. एक
  2. * ख
  3. ** ग
  4. *** घ

यह ऑपरेटर पूर्वता से संबंधित हो सकता, साथ ही, या यह अतीत में किसी बिंदु पर हो सकता है।

+0

पढ़ना चाहेंगे प्रश्न यह नहीं था कि आप इसे कैसे समझते हैं। –

+0

@georg: यह उपर्युक्त दो का एक अलग शब्द है। आप इसे कैसे समझ गए? – eruciform

+3

@ जॉर्ज, eruciform सही है। के एंड आर सी से, "पॉइंटर आईपी, 'int * ip' की घोषणा, एक स्मारक के रूप में है; यह कहता है कि अभिव्यक्ति' * ip' एक' int' है। एक चर के लिए घोषणा का वाक्यविन्यास वाक्यविन्यास की नकल करता है अभिव्यक्तियों में जिसमें वेरिएबल प्रकट हो सकता है। यह * वाक्यविन्यास का कारण है। –

2

* वेरिएबल नाम संशोधित करता है, प्रकार विनिर्देशक नहीं। यह ज्यादातर * को पार्स किए जाने के कारण है। इन बयानों को लें:

char* x; 
char *x; 

ये कथन समकक्ष हैं। * ऑपरेटर को प्रकार विनिर्देशक और परिवर्तनीय नाम (यह इंफिक्स ऑपरेटर की तरह माना जाता है) के बीच होना चाहिए, लेकिन यह अंतरिक्ष के दोनों तरफ जा सकता है। यह देखते हुए घोषणा

int* a, b; 

b एक सूचक नहीं होगा, क्योंकि वहाँ कोई * यह करने के लिए आसन्न। * केवल इसके दोनों ओर वस्तुओं पर काम करता है।

इसके अलावा, इस बारे में सोचें: जब आप घोषणा int x; लिखते हैं, तो आप संकेत दे रहे हैं कि x एक पूर्णांक है। यदि y एक पूर्णांक के लिए एक सूचक है, तो *y एक पूर्णांक है। जब आप int *y; लिखते हैं, तो आप संकेत दे रहे हैं कि *y एक पूर्णांक है (जो आप चाहते हैं)। बयान char a, *b, ***c; में, आप संकेत दे रहे हैं कि परिवर्तनीय a, b का मानदंड मूल्य, और c का त्रिकोणीय-संदर्भित मान char का प्रकार है। इस तरह से घोषित चर तार ऑपरेटर (लगभग) का उपयोग dereferencing के साथ संगत बनाता है।

मैं मानता हूं कि यह लगभग दूसरी तरह से इसके लिए और अधिक समझ में आता है। इस जाल से बचने के लिए, मैंने खुद को एक लाइन पर पॉइंटर्स घोषित करने के लिए हमेशा एक नियम बना दिया।

+2

यह स्थिति है, लेकिन * क्यों * यह वही है? –

31

सी घोषणाएं इस तरह लिखी गईं ताकि "घोषणा दर्पण का उपयोग किया जा सके"। यही कारण है कि आप इस तरह सरणियों की घोषणा:

int a[10]; 

आप थे बजाय नियम आप का प्रस्ताव है, जहां यह हमेशा

type identifier, identifier, identifier, ... ; 

है के लिए ... तो सरणियों तार्किक इस तरह की घोषणा करना होगा :

int[10] a; 

जो ठीक है, लेकिन दिखाई न दे कि कैसे आपa का उपयोग । , ध्यान दें कि यह कार्यों के लिए रखती है भी - हम इस तरह के कार्यों की घोषणा:

void foo(int a, char *b); 

बजाय

void(int a, char* b) foo; 

सामान्य में, "घोषणा दर्पण का उपयोग" नियम का मतलब केवल एक सेट याद करने के लिए है कि आप एसोसिएटिविटी नियमों का, जो *, [] और () दोनों ऑपरेटरों पर लागू होते हैं, जब आप मान का उपयोग कर रहे हैं, और *, [] और () जैसे घोषणाकर्ताओं में संबंधित टोकन लागू होते हैं।


कुछ आगे सोचा के बाद, मुझे लगता है कि यह भी उनका कहना है कि वर्तनी "सूचक int करने के लिए" के रूप में "int*" केवल "घोषणा दर्पण का उपयोग" वैसे भी का परिणाम है लायक है। यदि आप घोषणा की एक और शैली का उपयोग करने जा रहे थे, तो संभवत: "सूचकांक int" के रूप में "&int" या "@int" जैसी पूरी तरह से अलग करने के लिए अधिक समझदारी होगी।

+1

हम्म, यह मेरे लिए एक बहुत अच्छा कारण नहीं लगता है। मैं * करता हूं * सरणी को 'int [10]' के रूप में घोषित करना चाहता हूं, इस प्रकार जावा और सी # ऐसा करते हैं। घोषणा मिररिंग उपयोग के सी वाक्यविन्यास में अन्य उदाहरण हैं? – EMP

+0

@Evgeny, सी जावा से एक बहुत ही अलग भाषा है। एक जावा सरणी पूरी तरह से अलग है। सरणी चर केवल एक सरणी के लिए एक संशोधित संदर्भ रखता है। एक सी सर चर * * सरणी है। "घोषणापत्र दर्पण का उपयोग" का एक और उदाहरण एक पूर्णांक में सूचक को लौटने वाले फ़ंक्शन की घोषणा है। 'int * foo (int bar);'। यह इस तथ्य को दर्शाता है कि '* foo (3)' एक int है। मेरा सुझाव है कि आप के एंड आर सी 2 एड एड पढ़ें।, जहां यह समझाया गया है। –

+1

@Evgeny: सबसे स्पष्ट अन्य उदाहरण फ़ंक्शन कॉल की तरह दिखने के लिए लिखे गए फ़ंक्शन घोषणाएं हैं। – caf

1

क्योंकि अगर बयान

int* a, b; 

भी b सूचक के रूप में घोषित करने के लिए थे, तो आप एक ही लाइन पर

int* a; 
int b; 

घोषित करने के लिए कोई रास्ता नहीं होगा।

दूसरी ओर, आप आप क्या चाहते हैं पाने के लिए

int*a, *b; 

कर सकते हैं।

इस बारे में सोचें: जिस तरह से यह अभी भी यह करने का सबसे संक्षिप्त और अभी तक अनोखा तरीका है।

int x[20], y; 
int (*fp)(), z; 

इन उदाहरणों में, यह बहुत ज्यादा स्पष्ट है कि संशोधक केवल में से एक को प्रभावित कर रहे महसूस करता है: यह ज्यादातर के बारे में :)

+1

हां, ठीक है, वैसे ही आप एक ही पंक्ति पर एक int और एक फ्लोट घोषित नहीं कर सकते हैं - तो क्या? असल में, आप उन्हें एक ही * कथन * में डिलीयर नहीं कर सकते हैं, लेकिन आपके पास * लाइन * हो सकती है जो 'int * a; int बी; '- कोई समस्या नहीं है। – EMP

2

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

एक तरफ ध्यान दें पर, मैं बस अपने आप को घोषणा प्रति एक चर करने के लिए सीमित की सिफारिश करेंगे:

int *x; 
int y; 
+0

हाँ, यह * यहां अधिक स्पष्ट है, लेकिन वास्तव में, कौन सा नरक एक फंक्शन पॉइंटर और एक ही कथन में एक int घोषित करता है? :) – EMP

+1

@Evgeny - आप बिंदु खो रहे हैं। फ़ंक्शन पॉइंटर सिंटैक्स के लिए यह समझना आसान है कि संशोधक केवल एक चर को क्यों प्रभावित करते हैं। अगर भाषा असंगत थी और कुछ संशोधक एक परिवर्तनीय को प्रभावित करते हैं तो एक अन्य संशोधक प्रभावित होते हैं जो सभी चर को प्रभावित करते हैं, जो खराब डिजाइन होगा। –

0

मैं केवल अनुमान लगा सकते हैं क्यों एक बनाने के लिए हर चर नाम एक लाइन पर उल्लेख के लिए * दोहराने के लिए होता है उन सभी पॉइंटर्स। शायद यह भाषा स्थिरता के फैसले के कारण है?

int foo() { ... } 

यह भी मान लें कि आप इस समारोह के लिए दो समारोह संकेत घोषित करने के लिए चाहते हैं::


मान लेते हैं तो आप एक समारोह foo घोषित इस प्रकार करते हैं: मुझे एक उदाहरण के साथ इस उदाहरण देकर स्पष्ट करते

int (*fooptr1, fooptr2)(); 
// this doesn't work; and even if it did, what would the syntax possibly 
// look like to initializing them to function foo? 
// int (*fooptr1 = foo, fooptr2 = foo)() ? 

int (*fooptr1)() = foo, (*fooptr2)() = foo; 
// this works. 

इस मामले में, आप बस बी के लिए पूरी तरह से घोषणा दोहराएं ओथ चर, और आप गलत नहीं जा सकते क्योंकि ऐसा करने का कोई दूसरा तरीका नहीं है (सी घोषणा घोषणा वाक्य के रूप में दिया गया है)।


अब, शायद यह सोचा गया है, अगर वहाँ मामलों में जहां प्रकार घोषणा सभी चर के लिए बार-बार हो गया है कर रहे हैं, हो सकता है यह सिर्फ सामान्य स्थिति में होना चाहिए।

(यह न भूलें कि मैं सिर्फ यहाँ अनुमान लगा रहा हूँ।)

1

घोषणा पर विचार करें:

int *a[10]; 
int (*b)[10]; 

पहले पूर्णांकों के लिए दस संकेत की एक सरणी है, दूसरा के लिए सूचक है दस पूर्णांक की एक सरणी।

अब, यदि * प्रकार की घोषणा से जुड़ा हुआ था, तो यह उनके बीच एक संश्लेषण रखने के लिए सिंथेटिक रूप से मान्य नहीं होगा। तो आपको दो रूपों के बीच अंतर करने के लिए एक और तरीका खोजना होगा।

+3

"यह ध्यान दिया जाना चाहिए कि एक सरणी के लिए सूचक की घोषणा उपयोगी नहीं है" क्या? 'Int (* बी) [10] 'के साथ, आप उदा। इंगित करने के लिए' b' असाइन कर सकते हैं 'int ar [ROW_COUNT] [10]' का एक मनमाना तत्व, और पॉइंटर अंकगणितीय पंक्ति द्वारा संचालित होगा (उदा। 'ar + = 1' के बाद,' ar' एक पंक्ति से बढ़ाया जाता है)। कृपया "सरल सूचक" के साथ ऐसा करने का तरीका बताएं (सुनिश्चित नहीं है कि "सरल" वास्तव में क्या मतलब है)। –

+0

आप सही हैं, मैं उस पॉइंटर के पैरामीटर के उपयोग के बारे में और सोच रहा था और आपके द्वारा उल्लिखित मामले पर विचार करने में असफल रहा। अभी सुधार रहा है। –

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