सी

2010-11-22 12 views
9

में एक समारोह के लिए चार * पासिंग चार बनाम ** पैरामीटर के रूप में मैं सी मेंसी

stackoverflow: passing-an-array-of-strings-as-parameter-to-a-function-in-c
stackoverflow: how-does-an-array-of-pointers-to-pointers-work
stackoverflow: whats-your-favorite-programmer-ignorance-pet-peeve
drexel.edu: Character arrays

से कई गुजर चार * के कई विचार विमर्श पढ़ा है उनमें सरणी की चर्चा शामिल है, लेकिन मैं उससे दूर रहना चाहता हूं।

मैं सी में char * और char ** के उत्तीर्ण होने के बारे में खुद को सिखाने के लिए एक नमूना कार्यक्रम लिख रहा हूं। यह चार * पास करने में एक अभ्यास है (बिना पॉइंटर्स) सरणी के। निष्पादन दक्षता के लिए भी कोई चिंता नहीं है। :-)

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

void get_args_works(int, char **, char **); 
void get_args_broken(int, char **, char *); 
char *get_string(int, char **); 

int main(int argc, char **argv) 
{ 
    char *string_works; 
    char *string_broken; 

    get_args_works(argc, argv, &string_works); 
    get_args_broken(argc, argv, string_broken); 

    printf("in main string_works (%p) = %s\n",string_works,string_works); 
    free(string_works); 

    printf("in main string_broken (%p) = %s\n",string_broken,string_broken); 
    free(string_broken); 
} 

void get_args_works(int argc, char **argv, char **string) 
{ 
    *string = get_string(argc, argv); 
    printf("in get_args_works %p string %s\n",*string,*string); 
} 

void get_args_broken(int argc, char **argv, char *string) 
{ 
    string = get_string(argc, argv); 
    printf("in get_args_broken %p string %s\n",string,string); 
} 

char * get_string(int argc, char **argv) 
{ 
    int i; 
    char *string; 
    string = malloc(40); 

    // placeholder in case -s switch not found below 
    strcpy(string,"-s switch not found below"); 

    for(i = 0; i < argc; i++) 
    { 
     if(argv[i][0] == '-') 
     { 
      switch(argv[i][1]) 
      { 
      case 's': 
       // release above malloc(40) for "-s switch not found below" 
       free(string); 
       // make room for storing variable 
       string = malloc(strlen(argv[++i]) + 1); 
       // the argv just after -s 
       strcpy (string,argv[i]); 
       break; 
      } 
     } 
    } 
    return string; 
} 

तुम भी देख सकते हैं same code on github

उपरोक्त कोड को कुछ हद तक आत्म दस्तावेज़ीकृत है। main() दो char * चर घोषित करता है, और उन्हें अपने संबंधित get_args() कार्यों के पैरामीटर के रूप में पास करता है।

प्रत्येक get_args() समारोह char * get_string(int, char **) कहता है, ठीक उसी कॉल का उपयोग कर (लेकिन अलग तरह से वापसी मान इकट्ठा करने के लिए)।

get_string() ठीक काम करता है; यह malloc() करता है और पॉइंटर को कॉलिंग फ़ंक्शन पर वापस देता है। वह कोड काम करता है, और प्रत्येक get_args() फ़ंक्शन को रिटर्न वैल्यू प्राप्त होता है जैसा कि मैं अपेक्षा करता हूं।

लेकिन तब, जब get_args() फ़ंक्शन main() पर लौटने, क्यों dereferenced सूचक मूल्य वापस मुख्य (करने के लिए get_args_works() से प्राप्त करता है, लेकिन नहीं सूचक के मूल्य (get_args_broken() से)?

(यानी मैं देख सकता हूँ कि अगर मैं भिन्नता सूचक (&string_works) जब एक पैरामीटर के रूप भेजने, यह काम करता है। लेकिन क्यों? नहीं char * string_broken पहले से ही एक सूचक है? ऐसा क्यों है जब एक पैरामीटर के रूप भेजने "अतिरिक्त" भिन्नता आवश्यकता क्यों है?)

मैं मैं एक विजेता उत्तर की उम्मीद कर रहा हूं जो बताता है कि आप कैसे (हां, आप) पैरा * को पैरामीटर के रूप में प्राप्त करने के बारे में अवधारणा बनाते हैं नक्शन का वापसी मूल्य।

उत्तर

4
int get_args_broken(int argc, char **argv, char *string) 
{ 
    string = get_string(argc, argv); 
    printf("in get_args_broken %p string %s\n",string,string); 
} 

आप केवल string स्थानीय (स्वचालित) चर संशोधित कर रहे हैं। यह कॉलर को किसी भी तरह से दिखाई नहीं दे रहा है। ध्यान दें कि इसका मतलब है कि आप मुख्य रूप से जंगली सूचक को मुक्त कर रहे हैं।

यह इसी कारण से गलत है:

int get_sum(int sum, int a, int b) 
{ 
    sum = a + b; 
} 

है; पैरामीटर मूल्य द्वारा कॉपी किया गया है। इसके अलावा, आप एक int वापस नहीं कर रहे हैं (जैसा कि आपने घोषित किया था)।

int get_args_works(int argc, char **argv, char **string) 
{ 
    *string = get_string(argc, argv); 
    printf("in get_args_works %p string %s\n",*string,*string); 
} 

सही है (लापता वापसी को छोड़कर)। आप string संशोधित नहीं कर रहे हैं, जो व्यर्थ होगा। आप ऑब्जेक्ट पर string में स्थान संशोधित कर रहे हैं, जो इस मामले में char * है।

संपादित करें: यदि फ़ंक्शन कॉल करने वाला कोई फ़ंक्शन होता है तो आपको * argv को तीन गुना करने की आवश्यकता होगी, और आप उस फ़ंक्शन के चर को एक अलग चार ** पर सेट करना चाहते थे। E.G.

void trip_main(int *argc, char ***argv) 
{ 
    *argc = 10; 
    *argv = malloc(*argc * sizeof(char *)); 
} 

void caller() 
{ 
    char **argv; 
    int argc; 
    trip_main(&argc, &argv); 
} 
+0

hmmm। मुझे लगता है कि इसे समझने का एक अच्छा आसान तरीका हो सकता है। यह किसी भी तरह से char * के बारे में बात नहीं करता है। लेकिन फिर हमें argv * ट्रिपल करने की आवश्यकता क्यों नहीं है? hmmmm। –

+0

ओएमजी !!! मुझे अमान्य रिटर्न प्रकार को कैसे याद आया? ? मैं इस प्रश्न को * दिन * के लिए लिख रहा हूं ... !!!! डी 'ओह !!!! –

+2

@ थंडरब्रिट: सीखने का समय कि आपके कंपाइलर से अधिक चेतावनियां कैसे चालू करें, या बेहतर कंपाइलर प्राप्त करें। यदि आपका कंपाइलर किसी मान को वापस किए बिना वापस लौटने वाले कार्यों को वापस करने के लिए घोषित कार्यों के बारे में शिकायत नहीं करता है, तो यह ... ठीक है, ठीक से टूटा नहीं है, लेकिन यह उतना सहायक नहीं होना चाहिए जितना होना चाहिए। कंपाइलर चेतावनियां आपका मित्र हैं - इसे सुनें, और सुनिश्चित करें कि यह वर्बोज़ है। जीसीसी के साथ, एक अच्छा प्रारंभिक बिंदु '-वॉल' है; मैं आमतौर पर '-Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition' का उपयोग करता हूं (आखिरी क्योंकि मैं पुरातन कोड पर काम करता हूं)। '-Wshadow' भी अच्छा है ... –

1

जरूरतों में से एक सूचक, एक समारोह से (यहाँ get_args_works()) एक सूचक को उपयोग करने के लिए संशोधित करने के लिए है (या वापसी) चर पर अधिक से अधिक सी में के रूप में यह एक से अधिक चर वापस जाने के लिए संभव नहीं है।

get_args_works() काम करता है 'coz, आप एक सूचक & इसे करने के लिए एक संदर्भ के अपने main() में वहाँ है करने के लिए सूचक गुजर रहे हैं।

लेकिन get_args_broken() में आप केवल एक सूचक पास कर रहे हैं। यहां कुछ भी गलत नहीं है, अब आप malloc() & मेमोरी आवंटित स्ट्रिंग को get_args_broken() पर वापस लौटाएं, अभी भी कुछ भी गलत नहीं है। लेकिन अब, यह ज्ञापन आवंटित स्ट्रिंग स्थानीय & main() इस var का संदर्भ नहीं है। तो जब आप मुख्य रूप से char *string_broken; को अव्यवस्थित करते हैं() यह अपरिभाषित व्यवहार का कारण बन सकता है।

आशा है कि यह स्पष्ट है।