शून्य * का क्या अर्थ है और इसका उपयोग कैसे करना है?


147

आज जब मैं दूसरों का कोड पढ़ रहा था, तो मैंने कुछ देखा void *func(void* i);, जैसे void*कि फंक्शन के नाम और वेरिएबल टाइप के लिए यहाँ क्या मतलब है?

इसके अलावा, हमें इस तरह के पॉइंटर का उपयोग कब करना है और इसका उपयोग कैसे करना है?


2
आप किस C बुक का उपयोग कर रहे हैं? आप एक पूरे अध्याय के बेहतर भाग के लिए पूछ रहे हैं।
cnicutar

1
एक पर नज़र stackoverflow.com/questions/692564/...
WDan

इसके पहले उत्तर दिया: stackoverflow.com/questions/1043034/… और यहाँ: stackoverflow.com/questions/7324860/use-void-in-c
d33pika


से एक क्यू ले लो mallocऔर calloc। मैन पेज आगे कहता है: "... आवंटित की गई मेमोरी को एक पॉइंटर लौटाएं, जो किसी भी निर्मित डेटा प्रकार के लिए उपयुक्त रूप से संरेखित है।"
automaton

जवाबों:


175

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

void *अक्सर उन स्थानों पर उपयोग किया जाता है जहां आपको एक ही कोड में विभिन्न पॉइंटर प्रकारों के साथ काम करने में सक्षम होना चाहिए। एक आमतौर पर उद्धृत उदाहरण पुस्तकालय समारोह है qsort:

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

baseएक सरणी का पता है, सरणी nmembमें तत्वों की संख्या है, sizeप्रत्येक तत्व का आकार है, और comparएक फ़ंक्शन के लिए एक संकेतक है जो सरणी के दो तत्वों की तुलना करता है। इसे ऐसा कहा जाता है:

int iArr[10];
double dArr[30];
long lArr[50];
...
qsort(iArr, sizeof iArr/sizeof iArr[0], sizeof iArr[0], compareInt);
qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareDouble);
qsort(lArr, sizeof lArr/sizeof lArr[0], sizeof lArr[0], compareLong);

सरणी अभिव्यक्तियाँ iArr, dArrऔर lArrफ़ंक्शन कॉल में सरणी प्रकारों से सूचक प्रकारों में परिवर्तित किया गया है, और प्रत्येक को "सूचक int/ double/ long" से "सूचक" में परिवर्तित किया गया है void

तुलना कार्य कुछ इस तरह दिखेगा:

int compareInt(const void *lhs, const void *rhs)
{
  const int *x = lhs;  // convert void * to int * by assignment
  const int *y = rhs;

  if (*x > *y) return 1;
  if (*x == *y) return 0;
  return -1;
}

स्वीकार करके void *, qsortकिसी भी प्रकार के सरणियों के साथ काम कर सकते हैं।

उपयोग करने void *का नुकसान यह है कि आप खिड़की से और आने वाले ट्रैफिक में टाइप सेफ्टी फेंक देते हैं। गलत तुलना दिनचर्या का उपयोग करने से आपको बचाने के लिए कुछ भी नहीं है:

qsort(dArr, sizeof dArr/sizeof dArr[0], sizeof dArr[0], compareInt);

compareIntअपने तर्कों की अपेक्षा कर रहा है कि वह संकेत दे रहा है int, लेकिन वास्तव में doubles के साथ काम कर रहा है । संकलन समय पर इस समस्या को पकड़ने का कोई तरीका नहीं है; तुम बस एक गलत सरणी के साथ हवा हूँ।


5
यह वास्तव में गारंटी नहीं है कि void*एक फ़ंक्शन पॉइंटर में डाली जा सकती है। लेकिन डेटा पॉइंटर्स के लिए आपने जो कहा है वह है।
वेटिन

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

22

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

send(void * pData, int nLength)

इसका मतलब है कि आप इसे कई तरीकों से कह सकते हैं, उदाहरण के लिए

char * data = "blah";
send(data, strlen(data));

POINT p;
p.x = 1;
p.y = 2;
send(&p, sizeof(POINT));

तो यह अन्य भाषाओं में बहुत पसंद है, लेकिन किसी भी प्रकार की जाँच के साथ, सही नहीं है?
विंगर सेंडोन

3
मुझे लगता है कि यह समान होगा, हालांकि, चूंकि कोई प्रकार की जाँच नहीं है, एक गलती करने से बहुत अजीब परिणाम हो सकते हैं या कार्यक्रम को एकमुश्त दुर्घटना का कारण बना सकते हैं।
22

7

इस संबंध में C उल्लेखनीय है। एक कह सकते हैं voidशून्य है void*सब कुछ (सब कुछ हो सकता है) है।

यह सिर्फ इतना छोटा है *जिससे फर्क पड़ता है।

रेने ने इसे इंगित किया है। A void *कुछ स्थान के लिए एक सूचक है। उपयोगकर्ता को "व्याख्या" करने का तरीका क्या है।

यह सी में अपारदर्शी प्रकारों का एकमात्र तरीका है। बहुत ही प्रमुख उदाहरण उदाहरणों में पाए जा सकते हैं जैसे कि ग्लिब या सामान्य डेटा संरचना पुस्तकालयों में। यह "सी इंटरफेस और कार्यान्वयन" में बहुत विस्तृत माना जाता है।

मेरा सुझाव है कि आप पूरा अध्याय पढ़ें और "इसे प्राप्त करने" के लिए एक पॉइंटर की अवधारणा को समझने की कोशिश करें।


5
void*

'कोई संकेत नहीं है कि किस प्रकार का संग्रह किया गया है' के साथ मेमोरी का पॉइंटर है। आप उपयोग कर सकते हैं, उदाहरण के लिए, यदि आप कार्य करने के लिए एक तर्क पारित करना चाहते हैं और यह तर्क कई प्रकार का हो सकता है और फ़ंक्शन में आप प्रत्येक प्रकार को संभाल लेंगे।


3

आप पॉइंटर्स http://www.cplusplus.com/doc/tutorial/pointers/ के बारे में इस लेख पर नज़र डाल सकते हैं और अध्याय: शून्य पॉइंटर्स पढ़ सकते हैं ।

यह सी भाषा के लिए भी काम करता है।

पॉइंटर प्रकार का पॉइंटर एक विशेष प्रकार का पॉइंटर होता है। C ++ में, शून्य प्रकार की अनुपस्थिति का प्रतिनिधित्व करता है, इसलिए शून्य बिंदु ऐसे बिंदु होते हैं जो उस मान की ओर संकेत करते हैं, जिसका कोई प्रकार नहीं है (और इस प्रकार यह एक अनिर्धारित लंबाई और अनिर्धारित विध्वंस गुण भी है)।

यह किसी भी डेटा प्रकार को इंगित करने की अनुमति देता है, पूर्णांक मान या वर्णों के एक फ़्लोट से। लेकिन बदले में उनके पास एक बड़ी सीमा है: उनके द्वारा इंगित किया गया डेटा सीधे तौर पर नहीं दिया जा सकता है (जो कि तार्किक है, क्योंकि हमारे पास किसी भी प्रकार का हस्तक्षेप नहीं है), और इस कारण से हमें हमेशा शून्य सूचक में पता डालना होगा कुछ अन्य पॉइंटर टाइप जो एक ठोस डेटा प्रकार की ओर इशारा करते हैं जो इसे डीफ्रॉन्फ्रेंस करने से पहले करते हैं।


3

एक शून्य पॉइंटर को जेनेरिक पॉइंटर के रूप में जाना जाता है। मैं एक नमूना pthread परिदृश्य के साथ समझाना चाहूंगा।

थ्रेड फ़ंक्शन के रूप में प्रोटोटाइप होगा

void *(*start_routine)(void*)

थ्रेडेड एपीआई डिजाइनरों ने थ्रेड फ़ंक्शन के तर्क और वापसी मूल्यों पर विचार किया। यदि उन चीज़ों को सामान्य किया जाता है, तो हम तर्क के रूप में भेजते हुए * शून्य को टाइप कर सकते हैं। इसी तरह रिटर्न वैल्यू को शून्य से प्राप्त किया जा सकता है * (लेकिन मैंने थ्रेड फ़ंक्शन से कभी रिटर्न वैल्यू का उपयोग नहीं किया है)।

void *PrintHello(void *threadid)
{
   long tid;

   // ***Arg sent in main is retrieved   ***
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      //*** t will be type cast to void* and send as argument.
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);   
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }    
   /* Last thing that main() should do */
   pthread_exit(NULL);
}

मुख्य के अंत में कॉल pthread_exit(NULL);करने के बजाय क्यों return 0;?
Seabass77

1
@ Seabass77 कृपया देखें stackoverflow.com/questions/3559463/…
Jeyaram

1

a void*एक पॉइंटर है, लेकिन यह किस प्रकार को इंगित करता है यह अनिर्दिष्ट है। जब आप किसी फ़ंक्शन को एक शून्य पॉइंटर पास करते हैं, तो आपको यह जानना होगा कि इसका उपयोग करने के लिए फ़ंक्शन में बाद में इसे सही प्रकार पर वापस लाने के लिए इसका प्रकार क्या था। आप अपने उदाहरण में pthreadsवास्तव में प्रोटोटाइप के साथ उस उपयोग फ़ंक्शन में उदाहरण देखेंगे जो थ्रेड फ़ंक्शन के रूप में उपयोग किए जाते हैं। फिर आप void*अपने चयन के जेनेरिक डेटाटाइप के लिए एक संकेतक के रूप में तर्क का उपयोग कर सकते हैं और फिर इसे अपने थ्रेड फ़ंक्शन के भीतर उपयोग करने के लिए वापस उस प्रकार पर डाल सकते हैं। शून्य बिंदुओं का उपयोग करते समय आपको सावधानी बरतने की आवश्यकता है क्योंकि जब तक आप इसके वास्तविक प्रकार के सूचक पर वापस नहीं जाते हैं तब तक आप सभी प्रकार की समस्याओं को समाप्त कर सकते हैं।


1

C11 मानक (n1570) .26.2.2.3 al1 p55 कहते हैं:

एक पॉइंटर को पॉइंटर से voidया किसी ऑब्जेक्ट प्रकार में परिवर्तित किया जा सकता है। किसी भी ऑब्जेक्ट प्रकार के लिए एक पॉइंटर को शून्य और फिर से वापस करने के लिए एक पॉइंटर में परिवर्तित किया जा सकता है; परिणाम मूल सूचक के बराबर होगा।

आप इस जेनेरिक पॉइंटर का उपयोग किसी भी प्रकार के पॉइंटर को स्टोर करने के लिए कर सकते हैं, लेकिन आप इसके साथ सामान्य अंकगणितीय ऑपरेशन का उपयोग नहीं कर सकते हैं और आप इसे स्थगित नहीं कर सकते।


0

फ़ंक्शन एक सूचक को एक मनमाना प्रकार में ले जाता है और एक ऐसे वापस करता है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.