2010-08-05 11 views
6

नीचे सी प्रोग्राम में, मुझे समझ में नहीं आता कि क्यों मैं foo को कॉल करने के बाद buf [0] = 'ए' क्यों करता हूं। पास-दर-मूल्य कर नहीं कर रहा है?सी प्रोग्रामिंग - पास-बाय-रेफरेंस

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

    void foo(char buf[]) 
    { 
     buf[0] = 'A'; 
    } 

    int main(int argc, char *argv[]) 
    { 
     char buf[10]; 

     buf[0] = 'B'; 
     printf("before foo | buf[0] = %c\n", buf[0]); 
     foo(buf); 
     printf("after foo | buf[0] = %c\n", buf[0]); 

     system("PAUSE"); 
     return 0; 
     } 

उत्पादन:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A' 

उत्तर

12
void foo(char buf[]) 

रूप

void foo(char* buf) 

जब आप इसे कहते हैं, foo(buf) ही, आप मूल्य से एक सूचक भेज देंगे ताकि सूचक की एक प्रति किया जाता है।

पॉइंटर पॉइंट की प्रति मूल पॉइंटर (या, इस मामले में, सरणी के प्रारंभिक तत्व) के समान बिंदु पर इंगित करती है।

सी संदर्भ अर्थशास्त्र द्वारा पास नहीं किया गया है कि सी ++ संदर्भ अर्थशास्त्र द्वारा पास किया गया है। सी में सबकुछ मूल्य से गुजरता है। प्वाइंटर्स का उपयोग संदर्भ अर्थशास्त्र द्वारा पारित करने के लिए किया जाता है।

+0

उत्तर के लिए, विशेष रूप से जेम्स, सभी के लिए धन्यवाद। कोई भी मूल्य के आधार पर कॉल का उपयोग क्यों करेगा यदि यह इनपुट के मूल्य को नहीं बदलेगा? –

+0

क्योंकि आपको किसी चीज़ के मूल्य की आवश्यकता हो सकती है लेकिन इसे बदलने की आवश्यकता नहीं है। – Javier

+2

@ केविन: क्योंकि फ़ंक्शन को केवल मूल्य की आवश्यकता हो सकती है। साइड इफेक्ट्स के बिना फ़ंक्शंस के बारे में तर्क करना आसान नहीं है (यह नहीं कि आप सी को कार्यात्मक प्रोग्रामिंग भाषा के रूप में बहुत दूर कर पाएंगे), और मूल्य से गुजरने से संभावित साइड इफेक्ट्स हटा दिए जाते हैं। –

1

* [] buf चार वास्तव में चार ** का मतलब है ताकि आप सूचक/संदर्भ द्वारा गुजर रहे हैं। यह आपको देता है कि मुख्य() और foo() फ़ंक्शन दोनों में एक सूचक है।

1

क्योंकि आप buf (मान द्वारा) पर पॉइंटर पास कर रहे हैं। इसलिए buf द्वारा इंगित सामग्री बदल दी गई है।

4

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

0

मूल्य से गुजरने के लिए, फ़ंक्शन को तर्क के आकार को जानने की आवश्यकता होगी। इस मामले में आप बस एक सूचक पास कर रहे हैं।

1

पॉइंटर्स के साथ यह अलग है; आप मूल्य से गुजर रहे हैं, लेकिन जो आप पारित कर रहे हैं वह सूचक का मान है, जो सरणी के मान के समान नहीं है।

तो, सूचक का मान नहीं बदलता है, लेकिन आप यह संशोधित कर रहे हैं कि यह क्या इंगित कर रहा है। समारोह पैरामीटर के रूप में

2

सरणी एक सूचक के बराबर है, इसलिए घोषणा

void foo(char buf[]); 

रूप

void foo(char* buf); 

सरणी तर्क तो है अपनी पहली तत्व को सूचक को सड़ा हुआ ही है ।

0

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

यदि आप मूल सरणी की सामग्री को संरक्षित करना चाहते हैं, तो आप स्ट्रिंग को फ़ंक्शन में अस्थायी संग्रहण में कॉपी कर सकते हैं।

संपादित करें: यदि आप अपनी चार सरणी को संरचना में लपेटते हैं और संरचना पारित करते हैं तो क्या होगा?मेरा मानना ​​है कि यह भी काम कर सकता है, हालांकि मुझे नहीं पता कि किस प्रकार का ओवरहेड संकलक स्तर पर बना सकता है।

0

कृपया एक बात है,

घोषणा

void foo(char buf[]) 

कहते हैं ध्यान दें, [] अंकन का उपयोग किया जाएगा। सरणी का कौन सा तत्व आप उपयोग नहीं करेंगे।

अगर आपको लगता है कि बात करने के लिए चाहते हैं, तो आप तो आप, के रूप में

void foo(char buf[X]); //where X would be a constant. 
बेशक

यह संभव नहीं है इस समारोह की घोषणा करना चाहिए क्योंकि यह ऑपरेटिंग के लिए बेकार (समारोह होगा कुछ विशेष लाभ प्राप्त करना चाहते, सरणी के एन-वें तत्व पर?)। आपको जानकारी लिखना नहीं है कि आप किस सरणी को प्राप्त करना चाहते हैं। (- भाग []), और यह भी करने के लिए सूचक होता है

voi foo(char value); 

तो ...

void foo(char buf[]) 

एक घोषणा का कहना है जो जो अंकन आप उपयोग करना चाहते है: सब कुछ आपको क्या चाहिए सरल घोषणा है कुछ आंकड़े।

इसके अलावा ... आप क्या उम्मीद करेंगे ... आप समारोह के लिए भेजा सरणी

foo(buf); 

का एक नाम जो & buf के बराबर है foo [0]। तो ... यह एक सूचक है।

0

सी में Arrays मूल्य से पारित नहीं होते हैं। वे वैध फ़ंक्शन पैरामीटर भी नहीं हैं। इसके बजाए, कंपाइलर देखता है कि आप एक सरणी पास करने की कोशिश कर रहे हैं और इसे पॉइंटर पर डिमोट कर रहे हैं। यह चुपचाप करता है क्योंकि यह बुरा है। यह पिल्ले लात भी पसंद है।

समारोह मापदंडों में सरणियों का उपयोग करते हुए अपने एपीआई उपयोगकर्ताओं को संकेत देना है कि इस बात n-बाइट आकार टुकड़ों में खंडित किया स्मृति का एक ब्लॉक किया जाना चाहिए, लेकिन अगर आप char *foo वर्तनी देखभाल करने के लिए compilers की उम्मीद नहीं है एक अच्छा तरीका है char foo[] या फ़ंक्शन पैरामीटर में char foo[12]। वे नहीं करेंगे।

2

Arrays का अन्य प्रकारों से अलग व्यवहार किया जाता है; जब इसके बारे में संकार्य है सिवाय

: आप सी

Online C99 standard (draft n1256), खंड 6.3.2.1 में एक सरणी "मूल्य से" पारित नहीं हो सकता, "Lvalues, सरणियों, और समारोह designators", पैरा 3 आकार का ऑपरेटर या यूनरी & ऑपरेटर, या स्ट्रिंग शाब्दिक है जो एक सरणी को प्रारंभ करने के लिए प्रयोग किया जाता है, एक अभिव्यक्ति जिसमें 'प्रकार का सरणी' है, प्रकार '' पॉइंटर टू टाइप '' के साथ एक अभिव्यक्ति में परिवर्तित होता है जो इंगित करता है का प्रारंभिक तत्व सरणी ऑब्जेक्ट और एक अंतराल नहीं है। यदि सरणी ऑब्जेक्ट में स्टोरेज क्लास पंजीकृत है, तो व्यवहार अपरिभाषित है।

कॉल

foo(buf); 

सरणी अभिव्यक्ति buf में sizeof या & के संकार्य नहीं है और न तो यह परोक्ष बदल जाती है ("decays यह एक स्ट्रिंग शाब्दिक एक सरणी प्रारंभ करने में इस्तेमाल किया जा रहा है ")" तत्व के चार-तत्व सरणी "से" सूचक से चार "तक, और पते पहले से तत्व के को foo को पास किया गया है। इसलिए, foo() में buf पर जो कुछ भी आप करते हैं सरणी main() में दिखाई देगा। सरणी सबस्क्राइबिंग को परिभाषित करने के कारण, आप एक पॉइंटर प्रकार पर एक सबस्क्रिप्ट ऑपरेटर का उपयोग कर सकते हैं, इसलिए दिखता है जैसे आप सरणी प्रकार के साथ काम कर रहे हैं, लेकिन आप नहीं हैं।

एक समारोह पैरामीटर घोषणा के संदर्भ में, T a[] और T a[N]T *a का पर्याय बन गया है, लेकिन इस केवल मामले में जहां यह सच है।

1

सरणी और पॉइंटर्स (लगभग) एक ही चीज़ हैं।

int* foo = malloc(...) 

foo[2] रूप *(foo+2*sizeof(int))

किस्सा एक ही है: आप ने लिखा

int main(int argc, char *argv[]) 

यह भी कानूनी है (संकलन और एक ही काम करेंगे)

int main(int argc, char **argv) 

लिखने के लिए और

int main(int argc, char argv[][]) 

वे प्रभावी रूप से वही हैं। इससे थोड़ा अधिक जटिल, क्योंकि एक सरणी जानता है कि उसके कितने तत्व हैं, और एक सूचक नहीं है। लेकिन वे वही इस्तेमाल होते हैं।

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