অকার্যকর * এর অর্থ কী এবং কীভাবে এটি ব্যবহার করবেন?


147

আজ যখন আমি অন্যের কোড পড়ছিলাম, তখন আমি এরকম কিছু দেখতে পেলাম void *func(void* i);, void*এখানে ফাংশনটির নাম এবং ভেরিয়েবল টাইপের জন্য এখানে যথার্থ অর্থ কী?

তদাতিরিক্ত, কখন আমাদের এই ধরণের পয়েন্টার ব্যবহার করা উচিত এবং কীভাবে এটি ব্যবহার করব?


2
আপনি কোন সি বই ব্যবহার করছেন? আপনি একটি সম্পূর্ণ অধ্যায়ের আরও ভাল অংশের জন্য জিজ্ঞাসা করছেন।
cnicutar

1
একটি সময়ে কটাক্ষপাত আছে stackoverflow.com/questions/692564/...
WDan

তার আগে উত্তর stackoverflow.com/questions/1043034/... এবং এখানে: stackoverflow.com/questions/7324860/using-void-in-c
d33pika


mallocএবং থেকে একটি কিউ নিন calloc। ম্যান পেজটি আরও বলেছে: "... বরাদ্দ মেমরিটিতে একটি পয়েন্টার ফিরিয়ে দিন, যা কোনও বিল্ট-ইন ডেটা টাইপের জন্য উপযুক্তভাবে সাজানো আছে।"
অটোমেটনে

উত্তর:


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, তবে আসলে doubleএস এর সাথে কাজ করছে । সংকলনের সময় এই সমস্যাটি ধরার কোনও উপায় নেই; আপনি কেবল একটি মিসরেড অ্যারে দিয়ে শেষ করবেন।


5
এটি আসলে কোনও গ্যারান্টিযুক্ত নয় যে void*কোনও ফাংশন পয়েন্টারটিতে কাস্ট করা যেতে পারে। তবে ডেটা পয়েন্টারগুলির জন্য আপনি যা বলেছিলেন তা হোল্ড করে।
ভ্যাটাইন

অকার্যকর পয়েন্টারগুলি উপলভ্য হওয়ার আগে পরিবর্তে "চর *" ব্যবহৃত হত। তবে অকার্যকর আরও ভাল কারণ এটি সরাসরি কোনও কিছু পরিবর্তনের জন্য ব্যবহার করা যায় না।
ব্যবহারকারী 50619

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
আমি মনে করি এটি একই রকম হবে তবে যেহেতু কোনও ধরণের চেকিং নেই, একটি ভুল করা খুব অদ্ভুত ফলাফলের কারণ হতে পারে বা প্রোগ্রামটিকে পুরোপুরি ক্রাশ করতে পারে।
থেস্টেভ

7

সি এ ক্ষেত্রে লক্ষণীয়। একজন বলতে পারেন voidকিছুই না void*হ'ল সবকিছু (সব কিছু হতে পারে)।

এটি কেবল এই ক্ষুদ্র *যা পার্থক্য তৈরি করে।

রেনি এটা উল্লেখ করেছেন। এ void *কোনও স্থানে পয়েন্টার। কীভাবে "ব্যাখ্যা" করা যায় তা ব্যবহারকারীর কাছে রেখে দেওয়া হয়।

সি তে অস্বচ্ছ ধরণের একমাত্র উপায় হ'ল গ্লোব বা সাধারণ ডেটা স্ট্রাকচার গ্রন্থাগারগুলিতে খুব বিশিষ্ট উদাহরণ পাওয়া যায়। এটি "সি ইন্টারফেস এবং বাস্তবায়ন" তে খুব বিশদভাবে চিকিত্সা করা হয়।

আমি আপনাকে সম্পূর্ণ অধ্যায়টি পড়ার পরামর্শ দিচ্ছি এবং "এটি পেতে" পয়েন্টারের ধারণাটি বোঝার চেষ্টা করব।


5
void*

এটি 'মেমোরিটির পয়েন্টার যা কোনও ধরণের কোনও অনুমান ছাড়াই সেখানে কী ধরণের রয়েছে তা'। আপনি ব্যবহার করতে পারেন, উদাহরণস্বরূপ, আপনি যদি কোন কার্যকারিতা যুক্ত করতে চান এবং এই যুক্তিটি বিভিন্ন ধরণের এবং কার্যক্রমে আপনি প্রতিটি ধরণের পরিচালনা করতে পারেন।


3

পয়েন্টারগুলি সম্পর্কে এই নিবন্ধটি একবার দেখে নিতে পারেন: http://www.cplusplus.com/doc/tutorial/pointers/ এবং অধ্যায়টি: শূন্য পয়েন্টার পড়তে পারেন ।

এটি সি ভাষার পক্ষেও কাজ করে।

পয়েন্টার শূন্য প্রকারের একটি বিশেষ ধরণের পয়েন্টার। সি ++ এ, শূন্যপদটি প্রকারের অনুপস্থিতিকে প্রতিনিধিত্ব করে, তাই শূন্য পয়েন্টারগুলি এমন পয়েন্টার যা এমন কোনও মানকে নির্দেশ করে যা কোনও প্রকার নেই (এবং এইভাবে একটি নির্ধারিত দৈর্ঘ্য এবং নির্ধারিত বিন্যাস বৈশিষ্ট্যও রয়েছে)।

এটি অকার্যকর পয়েন্টারগুলিকে কোনও ডেটা টাইপের দিকে ইন্টিজার মান বা ভাসা থেকে শুরু করে অক্ষরের একটি স্ট্রিংয়ে নির্দেশ করতে সহায়তা করে। তবে বিনিময়ে তাদের একটি দুর্দান্ত সীমাবদ্ধতা রয়েছে: তাদের দ্বারা নির্দেশিত তথ্যগুলি সরাসরি অবহেলা করা যায় না (যা যৌক্তিক, যেহেতু আমাদের কাছে কোনওভাবে অবহেলার কোনও প্রকার নেই), এবং সেই কারণে আমাদের সর্বদা শূন্য পয়েন্টারে ঠিকানাটি ফেলে দিতে হবে কিছু অন্যান্য পয়েন্টার টাইপ যা কনক্রিটের ডেটা-রেফারেন্স করার আগে কোনও ডেটা টাইপ করে।


3

একটি শূন্য পয়েন্টার জেনেরিক পয়েন্টার হিসাবে পরিচিত। আমি একটি নমুনা pthread দৃশ্যের সাথে ব্যাখ্যা করতে চাই।

থ্রেড ফাংশনটিতে প্রোটোটাইপ থাকবে

void *(*start_routine)(void*)

Pthread API ডিজাইনাররা থ্রেড ফাংশনের যুক্তি এবং রিটার্ন মানগুলি বিবেচনা করে considered যদি সেই জিনিসটি জেনেরিক করা হয়, আমরা যুক্তি হিসাবে প্রেরণের সময় অকার্যকর * এ কাস্ট টাইপ করতে পারি। একইভাবে রিটার্ন মান অকার্যকর * থেকে পুনরুদ্ধার করা যায় (তবে আমি থ্রেড ফাংশন থেকে রিটার্ন মানগুলি কখনই ব্যবহার করি না)।

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

একটি void*পয়েন্টার, তবে এটি কী ধরণের নির্দেশ করে তা অনির্দিষ্ট। আপনি যখন কোনও ফাংশনে শূন্য পয়েন্টারটি পাস করেন তখন আপনাকে এটির সঠিকভাবে টাইপটি ব্যবহার করার জন্য এটি টাইপ করার জন্য এটির ধরনটি কী তা জানতে হবে। pthreadsথ্রেড ফাংশন হিসাবে ব্যবহৃত আপনার উদাহরণে ঠিক সেই প্রোটোটাইপ সহ সেইগুলি ব্যবহার ফাংশনগুলির উদাহরণগুলি দেখতে পাবেন । তারপরে আপনি নিজের void*পছন্দমতো জেনেরিক ডেটাটাইপের জন্য পয়েন্টার হিসাবে আর্গুমেন্টটি ব্যবহার করতে পারেন এবং তারপরে আপনার থ্রেড ফাংশনটির মধ্যে ব্যবহার করতে আবার এটিকে আবার ফেলে দিতে পারেন। অকার্যকর পয়েন্টার ব্যবহার করার সময় আপনাকে সতর্কতা অবলম্বন করা উচিত যদিও যতক্ষণ না আপনি যদি এর সত্য ধরণের পয়েন্টারটিতে ফিরে না এসে থাকেন তবে আপনি সব ধরণের সমস্যার সাথে শেষ করতে পারেন।


1

সি 11 স্ট্যান্ডার্ড (n1570) §6.2.2.3 al1 p55 বলেছেন:

একটি পয়েন্টারকে কোনও পয়েন্টার থেকে voidবা কোনও বস্তুর প্রকারে রূপান্তর করা যেতে পারে। যে কোনও অবজেক্টের ধরণের পয়েন্টারটি পয়েন্টারটিকে অকার্যকর হয়ে আবার ফিরে যেতে পারে; ফলাফলটি মূল পয়েন্টারের সমান তুলনা করবে।

আপনি এই জেনেরিক পয়েন্টারটি কোনও বস্তুর ধরণের পয়েন্টার সঞ্চয় করতে ব্যবহার করতে পারেন তবে আপনি এটির সাথে সাধারণ গাণিতিক ক্রিয়াকলাপগুলি ব্যবহার করতে পারবেন না এবং আপনি এটির সুনির্দিষ্ট করতে পারবেন না।


0

ফাংশনটি একটি নির্বিচারে টাইপের দিকে একটি পয়েন্টার নেয় এবং এরকম একটি প্রদান করে।


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.