এটি মোটামুটি পুরানো প্রশ্ন, তবে আমি অনেক উত্তর পেয়ে যাচ্ছি তাই আমি আমার 2 সেন্ট স্থাপন করতে যাচ্ছি, তবে স্পষ্ট এবং সংক্ষিপ্ত পদ্ধতিতে সমস্ত সম্ভাব্য পদ্ধতি দেখানো কিছুই নেই (সংক্ষিপ্ত বিট সম্পর্কে নিশ্চিত নয়, যেহেতু এটি পেয়েছে কিছুটা হাতছাড়া T TL; DR 😉)।
আমি ধরে নিচ্ছি যে ওপি কোডটি প্রাকদৃষ্ট দেখতে অন্যরকম ফাংশনে পাস করার জন্য কলটিকে সরাসরি পাস করার কোনও উপায় হিসাবে অনুলিপি ছাড়াই পাস করা অ্যারেটি ফিরিয়ে দিতে চেয়েছিল।
তবে এর মতো অ্যারে ব্যবহার করা হ'ল এটি পয়েন্টারে ক্ষয় হতে দেয় এবং সংকলকটিকে এটি অ্যারের মতো আচরণ করে । সূক্ষ্ম বাগের ফলস্বরূপ আপনি যদি একটি অ্যারে পাস করেন তবে ফাংশনটি আশা করে যে এটিতে 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;
}
তবে, আপনি যদি সি অ্যারে নিয়ে খেলতে জোর দিয়ে থাকেন, তবে একটি টেম্পলেট ব্যবহার করুন যা অ্যারেতে কত আইটেমের তথ্য রাখবে keep
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 টি উপাদান ছাড়া আর কিছু ব্যবহার না করে থাকেন তবে কোনও টেমপ্লেট ব্যবহার করা অতিরিক্ত প্রয়োজন is সুতরাং অবশ্যই আপনি এটি হার্ড কোড করতে পারেন:
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
সংকলকটির উপর নির্ভর করে এর পরে theচ্ছিক পিছনে থাকতে পারে, ফলস্বরূপ:
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
কাজ করা যায় তার সাথে খুব মিল (সি ++ 11) তবে তারা এই প্রসঙ্গে কাজ করে না।