निर्धारित माप
1. संदर्भ द्वारा पास
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
C ++ में आयाम की जानकारी को खोए बिना संदर्भ द्वारा सरणी को पारित करना शायद सबसे सुरक्षित है, क्योंकि एक कॉलर को एक गलत आयाम (कंपाइलर फ़्लैग जब मिसमैचिंग) से गुजरने की चिंता नहीं है। हालाँकि, यह डायनेमिक (फ्रीस्टोर) सरणियों के साथ संभव नहीं है; यह केवल स्वचालित ( आमतौर पर स्टैक-लिविंग ) सरणियों के लिए काम करता है अर्थात संकलन समय पर आयामीता को जाना जाना चाहिए।
2. सूचक द्वारा पास
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
पिछली पद्धति के बराबर सी पॉइंटर द्वारा सरणी पास कर रहा है। यह सरणी के क्षयकारी सूचक प्रकार (3) से गुजरने के साथ भ्रमित नहीं होना चाहिए , जो कि सामान्य, लोकप्रिय विधि है, यद्यपि यह एक से कम सुरक्षित है लेकिन अधिक लचीला है। जैसा (1) , इस विधि का उपयोग जब सभी सरणी के आयाम तय की और संकलन समय पर जाना जाता है। ध्यान दें कि फ़ंक्शन को कॉल करते समय सरणी का पता पास होना चाहिए process_2d_array_pointer(&a)
न कि क्षय द्वारा पहले तत्व का पताprocess_2d_array_pointer(a)
।
चर आकार
ये C से विरासत में मिले हैं, लेकिन कम सुरक्षित हैं, संकलक के पास जाँच का कोई तरीका नहीं है, यह गारंटी देते हुए कि कॉलर आवश्यक आयामों को पार कर रहा है। फ़ंक्शन केवल उस फोन पर होता है जो कॉलर आयाम (ओं) के रूप में गुजरता है। ये ऊपर वाले की तुलना में अधिक लचीले होते हैं क्योंकि विभिन्न लंबाई के सरणियों को उनके पास पर्याप्त रूप से पारित किया जा सकता है।
यह याद रखना चाहिए कि सी में एक समारोह में सीधे एक सरणी पास करने जैसी कोई चीज नहीं है [जबकि सी ++ में उन्हें एक संदर्भ (1) के रूप में पारित किया जा सकता है ; (2) सरणी के लिए एक सूचक पारित कर रहा है और सरणी को ही नहीं। हमेशा एक सरणी को पास करते-करते एक पॉइंटर-कॉपी ऑपरेशन बन जाता है, जो व्यूअर में आकर क्षय होने की सरणी की प्रकृति द्वारा सुगम होता है ।
3. क्षय प्रकार के लिए एक सूचक द्वारा (मान) पास करें
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
यद्यपि int array[][10]
अनुमति दी गई है, मैं उपरोक्त सिंटैक्स पर इसकी अनुशंसा नहीं करूंगा क्योंकि उपरोक्त सिंटैक्स यह स्पष्ट करता है कि पहचानकर्ता array
10 पूर्णांक वाले सरणी के लिए एक एकल पॉइंटर है, जबकि यह सिंटैक्स ऐसा लगता है कि यह एक 2D व्यूह है लेकिन समान पॉइंटर है 10 पूर्णांकों की एक सरणी। यहां हम एक पंक्ति में तत्वों की संख्या जानते हैं (यानी स्तंभ का आकार, यहां 10) लेकिन पंक्तियों की संख्या अज्ञात है और इसलिए इसे एक तर्क के रूप में पारित किया जाना चाहिए। इस मामले में कुछ सुरक्षा है क्योंकि कंपाइलर फ़्लैग कर सकता है जब एक पॉइंटर को दूसरे आयाम के साथ एक सरणी में रखा जाए जो 10 के बराबर नहीं है। पहला आयाम अलग हिस्सा है और छोड़ा जा सकता है। औचित्य के लिए यहां देखें कि केवल पहले आयाम को छोड़ने की अनुमति क्यों है।
4. एक पॉइंटर को पॉइंटर से पास करें
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
फिर से एक वैकल्पिक वाक्यविन्यास है int *array[10]
जो कि जैसा है int **array
। इस सिंटैक्स में [10]
इसे नजरअंदाज कर दिया जाता है क्योंकि यह एक पॉइंटर में बदल जाता है int **array
। शायद यह कॉलर के लिए सिर्फ एक संकेत है कि पारित सरणी में कम से कम 10 कॉलम होने चाहिए, फिर भी पंक्ति गणना आवश्यक है। किसी भी मामले में कंपाइलर किसी भी लम्बाई / आकार के उल्लंघन के लिए ध्वजांकित नहीं करता है (यह केवल जांचता है कि पास किया गया प्रकार पॉइंटर पॉइंटर है), इसलिए पैरामीटर के रूप में पंक्ति और स्तंभ दोनों की आवश्यकता होती है।
नोट: (4) सबसे कम सुरक्षित विकल्प है क्योंकि इसमें किसी भी प्रकार की जांच और सबसे असुविधाजनक है। कोई इस समारोह में वैध रूप से 2 डी सरणी नहीं दे सकता है; सी-एफएक्यू करने के सामान्य वर्कअराउंड की निंदा करता है int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
क्योंकि यह संभावित रूप से अपरिभाषित व्यवहार का कारण बन सकता है सरणी के चपटे होने के कारण कारण । इस पद्धति में एक सरणी को पास करने का सही तरीका हमें असुविधाजनक भाग में लाता है अर्थात हमें इसके प्रत्येक तत्व के साथ एक अतिरिक्त (सरोगेट) सरणी की आवश्यकता होती है जो वास्तविक, से-पास किए गए सरणी की संबंधित पंक्ति को इंगित करता है; यह सरोगेट तब फ़ंक्शन को दिया जाता है (नीचे देखें); यह सब उपरोक्त विधियों के समान कार्य करने के लिए है जो अधिक सुरक्षित, स्वच्छ और शायद अधिक तेज़ हैं।
उपरोक्त कार्यों का परीक्षण करने के लिए यहां एक ड्राइवर प्रोग्राम है:
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}