2009-06-22 20 views
32

मैं मॉलोक कार्यान्वयन के लिए शून्य पॉइंटर के उपयोग को समझता हूं।एक शून्य पॉइंटर का उपयोग कब करें?

void* malloc (size_t size); 

क्या कोई अन्य कारण सुझा सकता है या कुछ परिदृश्य प्रदान कर सकता है जहां यह अभ्यास में उपयोगी है।

धन्यवाद

उत्तर

11

आप सी कोड के साथ इंटरफ़ेस तो कर रहे हैं और एक सी ++ वस्तु के माध्यम से पारित करने की जरूरत है, लेकिन एक सी पुस्तकालय केवल एक सामान्य सूचक ले जाएगा, फिर जब आप सूचक को पुनः प्राप्त करने के लिए आप इसे फिर से कास्ट करने के लिए की जरूरत है उचित प्रकार

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

3

शून्य * और अन्य सी विषयों के बारे में सब कुछ सीखने का एक शानदार तरीका आईट्यून्स-यू पर शानदार स्टैनफोर्ड "प्रोग्रामिंग पैराडिगम्स" के पहले भाग को देखना है। यह वास्तव में सामान्य रूप से शून्य * (सी जेनेरिक) और पॉइंटर्स बताता है! यह निश्चित रूप से मुझे सी सीखने में मदद करता है ...

यदि आप किसी फ़ंक्शन में विभिन्न प्रकार के डेटा स्वीकार करने में सक्षम होना चाहते हैं तो सबसे बड़ा उपयोग शून्य * का उपयोग करना है। (यहाँ एक उदाहरण है: http://142.132.30.225/programming/node87.html):

int i; 
    char c; 
    void *the_data; 

    i = 6; 
    c = 'a'; 

    the_data = &i; 
    printf("the_data points to the integer value %d\n", *(int*) the_data); 

    the_data = &c; 
    printf("the_data now points to the character %c\n", *(char*) the_data); 

तुम मुक्त स्टैनफोर्ड वर्गों को देखने के लिए नहीं करना चाहते हैं, मैं googling शून्य की सलाह देते हैं

यहाँ तुम क्या उनके लिए उपयोग कर सकते हैं का एक और उदाहरण है सूचक और वहां सभी सामग्री पढ़ना।

+0

हां, हम इसे प्राप्त करते हैं लेकिन आप उचित सूचक प्रकार के साथ चर क्यों बनाते हैं? एक शून्य * में किस प्रकार का डेटा संग्रहीत किया जाता है, यह जानने के लिए परेशानी क्यों हो रही है? आप सिर्फ int * या char * का उपयोग क्यों नहीं करते? – Kekoa

+0

शून्य * सबसे सामान्य हैं जब आप एक सामान्य कार्य करना चाहते हैं (जो कि विभिन्न प्रकार लेता है/देता है)। आपके पास एक ऐसा फ़ंक्शन हो सकता है जो प्रत्येक के लिए फ़ंक्शन न किए बिना स्याही, या युगल या लम्बाई ले सकता है! – micmoo

1

शून्य पॉइंटर्स उपयोगी होते हैं जब आप कोड लिखते हैं जिन्हें एकाधिक ऑपरेटिंग सिस्टम पर चलाने की आवश्यकता होती है और अंतर्निहित फ्रेमवर्क एपीआई के काफी अज्ञेय होने की आवश्यकता होती है।

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

लेकिन, हाँ, जैसा कि अन्य ने इस धागे में कहा है, इस तरह की चीज निश्चित रूप से जहां भी जरूरी है, से बचा जाना चाहिए।

8

void पॉइंटर्स का उपयोग किसी भी समय डेटा के ब्लॉक की सामग्री महत्वपूर्ण नहीं होना चाहिए। उदाहरण के लिए जब डेटा कॉपी करना स्मृति क्षेत्र की सामग्री की प्रतिलिपि बनाई जाती है लेकिन डेटा का प्रारूप महत्वपूर्ण नहीं है।

void पॉइंटर्स का उपयोग कर सामग्री को समझने के बिना स्मृति के ब्लॉक पर काम करने वाले कार्यों के लिए उपयोगकर्ताओं को डिज़ाइन स्पष्ट करता है ताकि वे जान सकें कि फ़ंक्शन किसी भी डेटा प्रारूप की परवाह नहीं करता है। अक्सर फ़ंक्शन वास्तव में सामग्री अज्ञेयवादी होने पर स्मृति के ब्लॉक को संभालने के लिए char * लेने के लिए कोड किया गया है।

1

sqlite3_exec() पर देखें। आप एक एसक्यूएल क्वेरी शुरू करते हैं और परिणामों को किसी तरह से संसाधित करना चाहते हैं (उन्हें एक कंटेनर में स्टोर करें)। आप sqlite3_exec() को कॉल करते हैं और किसी भी ऑब्जेक्ट को कॉलबैक पॉइंटर और एक शून्य * पॉइंटर पास करते हैं (कंटेनर शामिल)। जब sqlite3_exec() चलता है तो यह प्रत्येक पुनर्प्राप्त पंक्ति के लिए कॉलबैक को कॉल करता है और उस शून्य * पॉइंटर को पास करता है ताकि कॉलबैक पॉइंटर डाले और जो भी आप चाहते हैं उसे कर सकें।

महत्वपूर्ण बात यह है कि sqlite3_exec() परवाह नहीं है कि कॉलबैक क्या करता है और आप किस पॉइंटर को पास करते हैं। शून्य * बिल्कुल इस तरह के पॉइंटर्स के लिए है।

29

एक अच्छा परिदृश्य void* उपयोग तब होता है जब आप किसी भी सामान्य एडीटी को कार्यान्वित करना चाहते हैं, अगर आपको पता नहीं है कि यह किस डेटाटाइप को रखने और निपटने के लिए जा रहा है। उदाहरण के लिए, निम्नलिखित की तरह एक लिंक्ड सूची:

typedef struct node_t node; 
struct 
{ 
    void* data; 
    node* prev, next; 
} node_t; 

typedef struct list_t list; 
typedef void* (func)(void*) cpy_func; 
typedef void (func)(void*) del_func; 
struct 
{ 
    node* head, tail, curr; 
    cpy_func copy; 
    del_func delete; 
} list_t; 

initializeLinkedList(cpy_func cpy, del_func del); 
//here you keep going defining an API 

यहाँ उदाहरण के लिए आप प्रारंभ समारोह संकेत के अन्य कार्य करता है जो अपनी सूची में अपने डेटा-प्रकार को कॉपी करने और बाद में मुक्त कराने में सक्षम हो जाएगा करने के लिए पारित करेंगे। तो void* का उपयोग करके आप अपनी सूची को अधिक सामान्य बनाते हैं।

मुझे लगता है कि void* पिछड़े संगतता के कारण केवल सी ++ में रहा, क्योंकि सी ++ में आपके पास टेम्पलेट्स, मज़ेदार इत्यादि जैसे ही परिणाम प्राप्त करने के लिए अधिक सुरक्षित और परिष्कृत तरीके हैं, और प्रोग्रामिंग के दौरान आपको मॉलोक का उपयोग करने की आवश्यकता नहीं है सी ++।

सी ++ के संबंध में, मेरे पास कोई विशिष्ट उपयोगी उदाहरण नहीं हैं।

+0

धन्यवाद आर्टम। बात करता है। सी के मामले में भी, एक ही चीज char * का उपयोग करके लागू की जा सकती है। मैं उस परिदृश्य के बारे में सोचने में असमर्थ था जहां एक char * का उपयोग नहीं किया जा सकता था। (मॉलोक पर लागू होता है)। – Mac13

+0

सी ++ मुहावरे टेम्पलेट का उपयोग करना है, और मानक पुस्तकालय एक बहुत उपयोगी उपयोगी प्रदान करता है (एक लिंक्ड सूची सहित)। –

+2

'char *' के बजाय 'शून्य *' का उपयोग करके एक निश्चित प्रकार की सुरक्षा प्रदान करता है। आप संकलक को बता रहे हैं "मुझे इन पॉइंटर्स में से किसी एक को अस्वीकार करने की अनुमति नहीं दी जानी चाहिए।" – Novelocrat

2

यह आमतौर पर, संख्यात्मक कोड में प्रयोग किया जाता है, उदाहरण के लिए एक सी जड़ solver समारोह है कि ऐसा दिखाई देगा:

double find_root(double x0, double (*f)(double, void*), void* params) 
{ 
/* stuff */ 
y = f(x, params); 
/* other stuff */ 
} 

params कुछ संरचना इसके बारे में पता करने के लिए f द्वारा डाली है, लेकिन find_root नहीं करता है। पूर्णांक, लंबे, डबल, चार * या कुछ:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); 

आप किसी भी प्रकार की एक सरणी सॉर्ट कर सकते हैं:

+3

अधिक आम तौर पर, 'शून्य *' कॉलबैक फ़ंक्शंस और अन्य कई चीजों के लिए अच्छे तर्क देते हैं जहां किसी को किसी फ़ंक्शन को तर्क देने की आवश्यकता होगी , लेकिन उस तर्क के प्रकार को जानने की आवश्यकता नहीं है। – Novelocrat

3

इस तरह के सी 'जेनरिक ", शून्य * के साथ लागू का एक और उदाहरण, एक मानक qsort समारोह है संरचना पॉइंटर्स ...

2

सी के साथ इंटरफेसिंग करने के बाद, मुझे अपने आप को केवल शून्य पॉइंटर्स का उपयोग करना पड़ता है जब मुझे कुछ कोड डीबग/ट्रेस करने की आवश्यकता होती है और किसी निश्चित पॉइंटर के पते को जानना होता है।

SomeClass * myInstance; 
// ... 
std::clog << std::hex << static_cast< void* >(myInstance) << std::endl; 

तरह

0x42A8C410 

कुछ प्रिंट और, मेरी राय में, अच्छी तरह से दस्तावेजों मैं क्या (सूचक पता, उदाहरण के बारे में कुछ भी पता नहीं)

+2

क्या आपने डीबगर का उपयोग करने पर विचार किया है? – Eva

-3
int (*f) (void); 
f =(void*) getprocaddress(dll,"myfunction"); 
कोशिश कर रहा हूँ जाएगा

कंपाइलर को खुश करने के लिए

+5

यह संकलित नहीं होगा। यह कंपाइलर खुश करने के लिए कैसे पूरी तरह अस्पष्ट है। – AnT

1

void * वास्तव में एक सी-आईएसएम है, और सी को कुछ करने की अनुमति देता है यह है कि यह अन्यथा उचित रूप से नहीं कर सका।

char * portably, कुछ भी के लिए इस्तेमाल नहीं किया जा सकता के रूप में विभिन्न प्लेटफार्मों संकेत के विभिन्न प्रकार के कर सकते हैं - एक char * जरूरी ही नहीं संभाला है (या यहां तक ​​कि एक ही आकार है) एक void * के रूप में।

तो जब डेटा का प्रकार सी (या पॉलिमॉर्फिक या अन्यथा गतिशील है) में ज्ञात नहीं है, तो void * आपको सही अंतर्निहित सूचक प्रकार उत्पन्न करने की अनुमति देता है - वह जो कुछ भी सही ढंग से इंगित कर सकता है।

सी ++ void * में आमतौर पर लीगेसी सी कोड के साथ एक रूप में या दूसरे में इंटरफेसिंग के संदर्भ में कभी नहीं आना चाहिए।

1

शून्य पॉइंटर का उपयोग करने का बहुत बड़ा फायदा है। सूचक चर एक चरक है जो एक और चर के पते को स्टोर करता है। उदाहरण:

int a; 
int *x= &a; 

अब 'एक्स' पूर्णांक चर के पते संग्रहीत करता है।

लेकिन यह एक विफल रहता है:

float f; 
int *x = &f; 

क्योंकि पूर्णांक सूचक चर केवल पूर्णांक चर पता स्टोर कर सकते हैं। इसी तरह से यह अन्य डेटा प्रकारों के लिए लागू होता है।

जब आप शून्य * पॉइंटर का उपयोग करते हैं, तो यह किसी भी प्रकार के प्रकार के पते को स्टोर करने के लिए किनारे देता है।

void *pointer = &i; 
void *pointer = &f; 

इसे पुनर्प्राप्त करते समय इसे संदर्भित किया जाना चाहिए।

*((int*)pointer) 

तो ध्यान से शून्य सूचक का उपयोग करें।

यह आपकी मदद कर सकता है, धन्यवाद।

7

सी ++ में, मुझे शून्य * पॉइंटर्स के लिए सबसे अधिक आकर्षक उपयोग केस मिला है, कोड को किसी ऑब्जेक्ट पर मनमाने ढंग से "उपयोगकर्ता डेटा" स्टोर करने का विकल्प देना है जो वे पहले से उपयोग कर रहे हैं।

मान लीजिए कि आप सॉफ्टवेयर है जो Car वस्तुओं के साथ उपयोगी काम करता है में इस्तेमाल के लिए एक वर्ग के एक Car का प्रतिनिधित्व लिखा है, चलो (यातायात सिमुलेशन, किराये की कार सूची, जो कुछ भी)। अब मान लीजिए कि आप खुद को ऐसे परिस्थिति में ढूंढें जहां आपका एप्लिकेशन Car के ट्रंक की मनमानी सामग्री का ट्रैक रखना चाहता है। ट्रंक में संग्रहीत किए गए विवरण का विवरण Car वर्ग के लिए महत्वपूर्ण नहीं है, और कुछ भी हो सकता है - यह वास्तव में कार वर्ग का उपयोग कर एप्लिकेशन के उद्देश्य पर निर्भर करता है। शून्य * सूचक दर्ज करें।

class Car 
{ 
    public: 

     // Existing methods of your Car class 

     void setContentsOfTrunk(void* contentsOfTrunk); 
     void* contentsOfTrunk() const; 

    private: 

     void* m_contentsOfTrunk; 
} 

अब, अपने Car वर्ग का उपयोग कर किसी भी आवेदन के लिए एक मौजूदा Car वस्तु ऐसी है कि वह जो Car वस्तु है किसी भी कोड से प्राप्त किया जा सकता करने के लिए एक मनमाने ढंग से डेटा वस्तु संलग्न करने का विकल्प है। ट्रंक की सामग्री Car ऑब्जेक्ट के साथ "यात्रा" करें, जहां भी यह आपके कोड में जाती है।

इस मामले में शून्य * का उपयोग करने के दो विकल्प हैं।

पहले ट्रंक सामग्री के प्रकार के आधार पर अपने वर्ग टेम्पलेट है आपत्ति:

template <class TrunkContentsType> 
class Car 
{ 
    public: 

     // Existing methods of your Car class 

     void setContentsOfTrunk(TrunkContentsType contentsOfTrunk); 
     TrunkContentsType contentsOfTrunk() const; 

    private: 

     TrunkContentsType m_contentsOfTrunk; 
} 

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

दूसरा विकल्प है जो ट्रंक सामग्री के लिए एक डेटा सदस्य और accessors कहते हैं कार से एक नया वर्ग प्राप्त करने के लिए है:

class Car 
{ 
    public: 

     // Existing methods of your Car class 
     // No methods having anything to do with trunk contents. 

    private: 

     // No data member representing trunk contents. 
} 

class CarWithTrunkContents 
{ 
    public: 

     // Existing methods of your Car class 

     void setContentsOfTrunk(TrunkContentsType contentsOfTrunk); 
     TrunkContentsType contentsOfTrunk() const; 

    private: 

     TrunkContentsType m_contentsOfTrunk; 
} 

नई CarWithTrunkContents वर्ग एक एप्लिकेशन-विशिष्ट वर्ग जिनमें से एक डेटा सदस्य कहते है कार पर ट्रंक सामग्री को स्टोर करने के लिए एप्लिकेशन की आवश्यकताएं टाइप करें। यह अनावश्यक हेवीवेट भी लगता है। आपको डेटा का एक अतिरिक्त टुकड़ा जोड़ने के लिए एक पूरी नई कक्षा क्यों प्राप्त करनी है जो कक्षा के व्यवहार को प्रभावित नहीं करती है? और यदि ट्रंक सामग्री को स्टोर करना चाहते हैं तो Car कक्षा का उपयोग कर अनुप्रयोगों के लिए यह काफी आम है, तो प्रत्येक एप्लिकेशन को उनके विशेष प्रकार की ट्रंक सामग्री के लिए एक नई कक्षा प्राप्त करने के लिए मजबूर क्यों करें?

अंत में, जबकि ट्रंक सामग्री की मेरी काल्पनिक उदाहरण शायद व्यवहार में Car वस्तु के साथ यात्रा कर मनमाने ढंग से ट्रंक सामग्री का एक ज्वलंत चित्र, पेंट आप की संभावना एक और भी अधिक सामान्य तंत्र Car लिए आवेदन विशेष डेटा संलग्न के लिए प्रदान करेगा:

class Car 
{ 
    public: 

     // Existing methods of your Car class 

     void setUserData(void* userData); 
     void* userData() const; 

    private: 

     void* m_userData; 
} 

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

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