यह एक काफी पुराना प्रश्न है, लेकिन मैं अपने 2 सेंट में डालने जा रहा हूं क्योंकि बहुत सारे उत्तर हैं, लेकिन स्पष्ट और संक्षिप्त तरीके से सभी संभव तरीके नहीं दिखा रहे हैं (संक्षिप्त बिट के बारे में निश्चित नहीं है, क्योंकि यह एक बहुत ही अच्छा है। हाथ से थोड़ा बाहर। टीएल; डीआर।)।
मैं यह मान रहा हूं कि ओपी उस सरणी को वापस करना चाहता था जिसे बिना कॉपी किए पास कर दिया गया था क्योंकि इसे सीधे कॉल करने वाले के पास भेजा जा रहा था ताकि कोड लुक को प्रीटियर बनाया जा सके।
हालांकि, इस तरह एक सरणी का उपयोग करने के लिए इसे एक सूचक में क्षय होने देना है और संकलक को एक सरणी की तरह व्यवहार करना है । इसके परिणामस्वरूप सूक्ष्म कीड़े हो सकते हैं यदि आप किसी सरणी में गुजरते हैं, तो फ़ंक्शन के साथ यह अपेक्षा करता है कि इसमें 5 तत्व होंगे, लेकिन आपका कॉलर वास्तव में किसी अन्य नंबर से गुजरता है।
वहाँ कुछ तरीके आप इस बेहतर संभाल कर सकते हैं। पास में std::vector
या std::array
(यह निश्चित नहीं है कि std::array
2010 के आसपास था जब सवाल पूछा गया था)। फिर आप ऑब्जेक्ट को बिना किसी कॉपी / मूविंग के संदर्भ के रूप में पास कर सकते हैं।
std::array<int, 5>& fillarr(std::array<int, 5>& arr)
{
// (before c++11)
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
// Note the following are for c++11 and higher. They will work for all
// the other examples below except for the stuff after the Edit.
// (c++11 and up)
for(auto it = std::begin(arr); it != std::end(arr); ++it)
{ /* do stuff */ }
// range for loop (c++11 and up)
for(auto& element : arr)
{ /* do stuff */ }
return arr;
}
std::vector<int>& fillarr(std::vector<int>& arr)
{
for(auto it = arr.begin(); it != arr.end(); ++it)
{ /* do stuff */ }
return arr;
}
हालांकि, यदि आप सी सरणियों के साथ खेलने पर जोर देते हैं, तो एक टेम्पलेट का उपयोग करें जो सरणी में कितने आइटमों की जानकारी रखेगा।
template <size_t N>
int(&fillarr(int(&arr)[N]))[N]
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
सिवाय इसके कि बट बदसूरत दिखता है, और पढ़ने के लिए सुपर कठिन है। मैं अब उस चीज की मदद के लिए कुछ का उपयोग करता हूं जो 2010 में आसपास नहीं थी, जिसे मैं फ़ंक्शन पॉइंटर्स के लिए भी उपयोग करता हूं:
template <typename T>
using type_t = T;
template <size_t N>
type_t<int(&)[N]> fillarr(type_t<int(&)[N]> arr)
{
// N is easier and cleaner than specifying sizeof(arr)/sizeof(arr[0])
for(int* it = arr; it != arr + N; ++it)
{ /* do stuff */ }
return arr;
}
इस प्रकार जहां एक यह होने की अपेक्षा करेंगे, इस बनाने चालें दूर अधिक पठनीय। बेशक, एक टेम्पलेट का उपयोग करना बहुत ही अच्छा है यदि आप कुछ और नहीं बल्कि 5 तत्वों का उपयोग करने जा रहे हैं, तो आप इसे कठिन कोड कर सकते हैं:
type_t<int(&)[5]> fillarr(type_t<int(&)[5]> arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
जैसा कि मैंने कहा, मेरी type_t<>
चाल उस समय काम नहीं करती थी जब यह प्रश्न पूछा गया था। सबसे अच्छा आप जिस पर वापस जा सकते थे, उसके लिए एक संरचना में एक प्रकार का उपयोग करना था:
template<typename T>
struct type
{
typedef T type;
};
typename type<int(&)[5]>::type fillarr(typename type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
जो फिर से बहुत बदसूरत दिखना शुरू कर देता है, लेकिन कम से कम अभी भी अधिक पठनीय है, हालांकि typename
वैकल्पिक रूप से वापस हो सकता है, फिर कंपाइलर पर निर्भर करता है, जिसके परिणामस्वरूप:
type<int(&)[5]>::type fillarr(type<int(&)[5]>::type arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
और फिर निश्चित रूप से आप मेरे सहायक का उपयोग करने के बजाय एक विशिष्ट प्रकार निर्दिष्ट कर सकते थे।
typedef int(&array5)[5];
array5 fillarr(array5 arr)
{
// Prefer using the compiler to figure out how many elements there are
// as it reduces the number of locations where you have to change if needed.
for(int* it = arr; it != arr + sizeof(arr)/sizeof(arr[0]); ++it)
{ /* do stuff */ }
return arr;
}
फिर, मुफ्त कार्य std::begin()
और std::end()
मौजूद नहीं था, हालांकि आसानी से लागू किया जा सकता था। इसने सरणी पर अधिक सुरक्षित तरीके से पुनरावृत्ति की अनुमति दी होगी क्योंकि वे सी सरणी पर अर्थ रखते हैं, लेकिन सूचक नहीं।
सरणी तक पहुँचने के लिए, आप या तो इसे किसी अन्य फ़ंक्शन में पास कर सकते हैं जो समान पैरामीटर प्रकार लेता है, या इसके लिए एक उपनाम बनाता है (जो कि आपके पास उस दायरे में मूल रूप से पहले से ही बहुत अधिक अर्थ नहीं होगा)। किसी सरणी संदर्भ तक पहुँचना मूल सरणी तक पहुँचने की तरह ही है।
void other_function(type_t<int(&)[5]> x) { /* do something else */ }
void fn()
{
int array[5];
other_function(fillarr(array));
}
या
void fn()
{
int array[5];
auto& array2 = fillarr(array); // alias. But why bother.
int forth_entry = array[4];
int forth_entry2 = array2[4]; // same value as forth_entry
}
संक्षेप में, यदि आप इस पर पुनरावृति करने का इरादा रखते हैं, तो एक सूचक में एक सरणी क्षय की अनुमति नहीं देना सबसे अच्छा है। यह सिर्फ एक बुरा विचार है क्योंकि यह संकलक को पैर में खुद को गोली मारने से बचाने के लिए रखता है और आपके कोड को पढ़ने के लिए कठिन बना देता है। हमेशा कोशिश करें और कंपाइलर की मदद करें जब तक संभव हो तब तक टाइप करके रखें जब तक आपके पास ऐसा न करने का एक बहुत अच्छा कारण न हो।
संपादित करें
ओह, और पूर्णता के लिए, आप इसे एक पॉइंटर को नीचा दिखाने की अनुमति दे सकते हैं, लेकिन यह सरणी को धारण किए गए तत्वों की संख्या से हटाता है। यह सी / सी ++ में बहुत कुछ किया जाता है और आमतौर पर सरणी में तत्वों की संख्या को पारित करके कम किया जाता है। हालांकि, कंपाइलर आपकी मदद नहीं कर सकता है यदि आप गलती करते हैं और तत्वों की संख्या के लिए गलत मान में पास होते हैं।
// separate size value
int* fillarr(int* arr, size_t size)
{
for(int* it = arr; it != arr + size; ++it)
{ /* do stuff */ }
return arr;
}
आकार पास करने के बजाय, आप अंतिम पॉइंटर पास कर सकते हैं, जो आपके सरणी के अंत में एक अतीत को इंगित करेगा। यह उपयोगी है क्योंकि यह कुछ के लिए बनाता है जो एसटीडी एल्गोरिदम के करीब है, जो एक शुरुआत और अंत पॉइंटर लेते हैं, लेकिन आप जो वापसी करते हैं वह अब केवल कुछ है जो आपको याद रखना चाहिए।
// separate end pointer
int* fillarr(int* arr, int* end)
{
for(int* it = arr; it != end; ++it)
{ /* do stuff */ }
return arr;
}
वैकल्पिक रूप से, आप यह दस्तावेज़ कर सकते हैं कि यह फ़ंक्शन केवल 5 तत्वों को ले जाएगा और आशा है कि आपके फ़ंक्शन का उपयोगकर्ता कुछ भी बेवकूफ नहीं करता है।
// I document that this function will ONLY take 5 elements and
// return the same array of 5 elements. If you pass in anything
// else, may nazal demons exit thine nose!
int* fillarr(int* arr)
{
for(int* it = arr; it != arr + 5; ++it)
{ /* do stuff */ }
return arr;
}
ध्यान दें कि वापसी मूल्य खो गया है यह मूल प्रकार है और एक पॉइंटर को नीचा दिखाया गया है। इस वजह से, आप अब यह सुनिश्चित करने के लिए अपने दम पर हैं कि आप सरणी को खत्म नहीं करने जा रहे हैं।
आप एक पास std::pair<int*, int*>
कर सकते हैं, जिसे आप शुरू और अंत के लिए उपयोग कर सकते हैं और उस आस-पास से गुजर सकते हैं, लेकिन फिर यह वास्तव में एक सरणी की तरह दिखता है।
std::pair<int*, int*> fillarr(std::pair<int*, int*> arr)
{
for(int* it = arr.first; it != arr.second; ++it)
{ /* do stuff */ }
return arr; // if you change arr, then return the original arr value.
}
void fn()
{
int array[5];
auto array2 = fillarr(std::make_pair(&array[0], &array[5]));
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
या
void other_function(std::pair<int*, int*> array)
{
// Can be done, but you have the original array in scope, so why bother.
int fourth_element = array2.first[4];
}
void fn()
{
int array[5];
other_function(fillarr(std::make_pair(&array[0], &array[5])));
}
काफी मजेदार है, यह बहुत ही std::initializer_list
काम के समान है (c ++ 11), लेकिन वे इस संदर्भ में काम नहीं करते हैं।