2010-08-15 10 views
17

मान लीजिए मैं संकेत की एक सरणी सी में चार करने के लिए है:सी में char के लिए पॉइंटर्स की एक सरणी qsort कैसे?

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" }; 

और मैं qsort का उपयोग कर इस सरणी क्रमित करना चाहते हैं:

qsort(data, 5, sizeof(char *), compare_function); 

मैं तुलना समारोह के साथ आने में असमर्थ हूँ। किसी कारण से यह काम नहीं करता है:

int compare_function(const void *name1, const void *name2) 
{ 
    const char *name1_ = (const char *)name1; 
    const char *name2_ = (const char *)name2; 
    return strcmp(name1_, name2_); 
} 

मैं खोज के एक बहुत कुछ किया और पाया कि मैं qsort के अंदर ** का इस्तेमाल किया था:

int compare_function(const void *name1, const void *name2) 
{ 
    const char *name1_ = *(const char **)name1; 
    const char *name2_ = *(const char **)name2; 
    return strcmp(name1_, name2_); 
} 

और यह काम करता है।

क्या कोई इस समारोह में *(const char **)name1 के उपयोग की व्याख्या कर सकता है? मैं इसे बिल्कुल समझ में नहीं आता। डबल पॉइंटर क्यों? मेरा मूल कार्य क्यों नहीं हुआ?

धन्यवाद, बोडा साइडो।

+2

के संदर्भ में होगा 'डेटा'' const' घोषित किया जाना चाहिए। –

+0

बिली, अगर यह स्थिर है, तो क्या इसे अभी भी हल किया जा सकता है? – bodacydo

+1

हां। सरणी गैर 'const' हो सकती है, लेकिन उस सरणी के भीतर निहित पॉइंटर्स' const' होना चाहिए। आपको संकलन-समय निरंतर अक्षरों को संशोधित करने की अनुमति नहीं है (ऐसा करने के लिए यह अनिर्धारित व्यवहार है)। इसे पाने के लिए, आप 'const char * डेटा [5]' चाहते हैं। यदि आप सरणी को भी स्थिर रखना चाहते हैं, तो आप 'const char * const data [5]' करेंगे। –

उत्तर

17

यदि यह चीजों को सीधे आपके सिर में रखने में मदद करता है, तो आपको अपने तुलनित्र में पॉइंटर्स डालने के प्रकार को qsort (जिसे qsort दस्तावेज़ base पर कॉल करते हैं) के मूल प्रकार के समान है। लेकिन qsort जेनेरिक होने के लिए, यह सब कुछ "वास्तव में" है, इस पर ध्यान दिए बिना, यह सब कुछ void* के रूप में संभालता है।

तो, यदि आप इनट्स की एक सरणी सॉर्ट कर रहे हैं, तो आप int* (void* में परिवर्तित) में गुजरेंगे। qsort आपको तुलनात्मक रूप से दो void* पॉइंटर्स प्रदान करेगा, जिसे आप int* में कनवर्ट करते हैं, और int मानों को वास्तव में तुलना करने के लिए अस्वीकार करते हैं।

अब char* साथ int बदल देते हैं:

आप char* की एक सरणी छँटाई कर रहे हैं, तो आप में एक char** (void* करने के लिए परिवर्तित) पारित करेंगे। qsort आपको तुलनात्मक रूप से दो void* पॉइंटर्स प्रदान करेगा, जिसे आप char** में कनवर्ट करते हैं, और char* मानों को वास्तव में तुलना करने के लिए अस्वीकार करते हैं।

आपके उदाहरण में, क्योंकि आप एक सरणी का उपयोग कर रहे हैं, char** जो आप पास करते हैं, char* "क्षय" के पहले तत्व में पॉइंटर को "क्षय" का परिणाम है। चूंकि पहला तत्व char* है, इसके लिए एक पॉइंटर char** है।

3

कल्पना करें कि आपका डेटा double data[5] था।

आपकी तुलना विधि तत्वों (डबल) को पॉइंटर्स (डबल *, शून्य के रूप में पास *) प्राप्त करेगी।
अब चार * के साथ डबल को प्रतिस्थापित करें।

2

qsort पॉइंटर्स की तुलना में अन्य चीजों से युक्त सरणी को सॉर्ट करने के लिए सामान्य है। यही कारण है कि आकार पैरामीटर है। यह सरणी तत्वों को सीधे तुलना फ़ंक्शन पर पास नहीं कर सकता है, क्योंकि यह संकलित समय पर कितना बड़ा नहीं है, यह नहीं जानता है। इसलिए यह पॉइंटर्स पास करता है। आपके मामले में आपको पॉइंटर्स char *, char ** पर प्राप्त होते हैं।

+0

मुझे समझ में नहीं आता, क्षमा करें। 'Qsort' का पहला तर्क' * 'है। मैं '**' पास करता हूं। जिसका अर्थ है कि मैं प्रभावी रूप से केवल एक '*' पास करता हूं। लेकिन एक '*' बिल्कुल 'char *' है। देख? यही कारण है कि मैं उलझन में हूँ। – bodacydo

+0

@ बोडासीडो: महत्वपूर्ण बात यह है कि तुलनात्मक कार्य सरणी के * तत्व * को पॉइंटर्स लेता है। चूंकि आपके सरणी का प्रत्येक तत्व एक पॉइंटर-टू-चार है, तुलना फ़ंक्शन पॉइंटर्स-टू-पॉइंटर्स-टू-चार पर चलती है। – jamesdlin

0
man qsort से

: तुलना समारोह सरणी तत्वों की ओर इशारा हो जाता है की तरह

The contents of the array are sorted in ascending 
order according to a comparison function pointed to by 
compar, which is called with two arguments that **point** 
to the objects being compared. 

तो यह लग रहा है। अब char * पर एक पॉइंटर char ** (यानी किसी चरित्र के लिए पॉइंटर के लिए पॉइंटर) है।

0

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

एक बयान चरित्र संकेत के 5 आकार की एक सरणी के लिए संकलक पूछ है। आपने उन पॉइंटर्स को स्ट्रिंग अक्षर के लिए प्रारंभ किया है, लेकिन कंपाइलर के लिए, यह अभी भी पांच पॉइंटर्स की एक सरणी है।

जब आप उस सरणी को qsort में पास करते हैं, तो पॉइंटर्स की सरणी पहले तत्व को इंगित करने वाले पॉइंटर में क्षय हो जाती है, सी सर पैरामीटर पासिंग नियमों के अनुसार।

इसलिए आपको स्थिरांक वाले वास्तविक वर्ण सरणी प्राप्त करने से पहले एक स्तर के संकेत को संसाधित करना होगा।

2

तुलना फ़ंक्शन उस ऑब्जेक्ट के प्रकार पर पॉइंटर्स लेता है जो उस सरणी में है जिसे आप सॉर्ट करना चाहते हैं। चूंकि सरणी में char * है, इसलिए आपकी तुलना फ़ंक्शन पॉइंटर्स को char *, उर्फ ​​char ** पर ले जाती है।

0

@bodacydo यहां एक कार्यक्रम समझा जा सकता है कि क्या अन्य प्रोग्रामर संप्रेषित करने के लिए कोशिश कर रहे हैं, लेकिन इस "पूर्णांक"

#include <stdio.h> 


int main() 
{ 
    int i , j; 
    int *x[2] = {&i, &j}; 

    i = 10; j = 20; 

    printf("in main() address of i = %p, address of j = %p \r\n", &i, &j); 

    fun(x); 
    fun(x + 1); 

    return 0; 
} 


void fun(int **ptr) 
{ 
    printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr); 
    printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr); 
}