কোনও ফাংশনে অ্যারে রিটার্ন করুন


212

আমার একটি অ্যারে রয়েছে int arr[5]যা একটি ফাংশনে স্থানান্তরিত হয় fillarr(int arr[]):

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. আমি কীভাবে সেই অ্যারেটি ফিরিয়ে দিতে পারি?
  2. আমি এটি কীভাবে ব্যবহার করব, বলুন যে আমি কীভাবে এটি ব্যবহার করতে যাচ্ছি একটি পয়েন্টার ফিরিয়েছি?

46
এই প্রসঙ্গে কঠোরভাবে বলতে গেলে আপনাকে অ্যারে ফিরিয়ে দেওয়ার দরকার নেই যেহেতু অ্যারেটি রেফারেন্স দিয়ে পাস করা হয়েছে তাই ফাংশনের বাইরে 'অ্যারে'র উপাদানগুলিতে কোনও পরিবর্তন দেখা যাবে।
বুগমারমে

12
অ্যারে ফিরিয়ে দেওয়া চেইন ফাংশনগুলির জন্য সুবিধাজনক।

5
যতক্ষণ আপনি স্ট্যাকের মধ্যে একটি অ্যারে তৈরি করা এবং এটিতে কোনও পয়েন্টার ফিরিয়ে দেওয়ার ভুল করছেন না।
অবধি

2
@ ইসমাইল: এটি অ্যারেটিকে আর ফিরিয়ে দিতে পারে না, যদি না সেই অ্যারেটিকে গতিশীলভাবে বরাদ্দ দেওয়া হয়। এবং যদি এটি হয়, ব্যবহার করুন std::vector
GManNickG

4
@BuggerMe: অ্যারে না রেফারেন্স দ্বারা পাস (যদি না আপনি এটি একটি অনেক মজাদার সিনট্যাক্স সঙ্গে অনুরোধ করুন), কোডে, এরে decays প্রথম উপাদান একটি পয়েন্টার মধ্যে এবং যে ফাংশন পাস করা হয়েছে। 5ফাংশন স্বাক্ষরে কম্পাইলার দ্বারা বাতিল করা হয়।
ডেভিড রদ্রিগেজ - ড্রিবিস

উত্তর:


204

এই ক্ষেত্রে, আপনার অ্যারে ভেরিয়েবলটি arrপ্রকৃত রূপান্তর দ্বারা মেমরিতে আপনার অ্যারে ব্লকের শুরুতে পয়েন্টার হিসাবে বিবেচিত হতে পারে। আপনি ব্যবহার করছেন এই সিনট্যাক্স:

int fillarr(int arr[])

একমাত্র সিনট্যাকটিক চিনি। আপনি সত্যিই এটির সাথে এটি প্রতিস্থাপন করতে পারেন এবং এটি এখনও কার্যকর হবে:

int fillarr(int* arr)

সুতরাং একই অর্থে, আপনি যা আপনার ফাংশন থেকে ফিরে আসতে চান তা আসলে অ্যারের প্রথম উপাদানটির একটি পয়েন্টার:

int* fillarr(int arr[])

এবং আপনি এখনও এটি আপনার যেমন সাধারণ অ্যারের মতো ব্যবহার করতে সক্ষম হবেন:

int main()
{
  int y[10];
  int *a = fillarr(y);
  cout << a[0] << endl;
}

45
স্পষ্ট করতে, যে "ক্লাসিক সি ++ বিবৃতি" মিথ্যা; অ্যারেগুলি পয়েন্টার নয়।
GManNickG

25
একটি [i] == * (a + i) বিধিটি মনে রাখবেন

8
@ ব্রেন্ট ন্যাশ, না একটি অ্যারে একটি অ্যারে হয়। অ্যারের শুরুতে একটি পয়েন্টার একটি পয়েন্টার। এটি কেবল ঘটে যায় যে সংকলকটিতে কিছু সিনট্যাকটিক চিনি রয়েছে যা কিছু পরিস্থিতিতে আপনার জন্য অনুবাদ করে। arrayএবং &arrayঅনেক ক্ষেত্রে বিনিময়যোগ্য।
কার্ল নরুম

20
@ ব্রেন্ট: না। একটি অ্যারে এটি নিজস্ব ধরণের, এটি কোনও বিশেষ ধরণের পয়েন্টার নয়। aইন টাইপ int a[10]হয় int[10]। আপনি যা বলতে পারেন তা হ'ল অ্যারে "ক্ষয়" তাদের প্রথম উপাদানটির পয়েন্টারে। (এটি একটি অন্তর্নিহিত অ্যারে-টু-পয়েন্টার রূপান্তর)) তারপরে আপনার উত্তরটি আমার যে লাইনগুলিতে থাকবে সেগুলি চালিয়ে যাবে। আপনি যদি অ্যারে, অ্যারে-টু-পয়েন্টার রূপান্তর এবং পয়েন্টারগুলির মধ্যে পার্থক্য করার জন্য আপনার উত্তরটি সম্পাদনা করেন তবে আমি আমার উত্তরটি মুছব কারণ তাদের একই মূল তথ্য থাকবে এবং আপনি প্রথম ছিলেন।
GManNGG

8
@ এবং মনে রাখবেন একটি [i] == * (a + আকারের (ক) * i) বিধি
আমির

114

সি ++ ফাংশনগুলি মান দ্বারা সি-স্টাইল অ্যারেগুলি ফিরিয়ে দিতে পারে না। নিকটতম জিনিসটি একটি পয়েন্টারটি ফেরত দেওয়া। তদ্ব্যতীত, আর্গুমেন্ট তালিকার একটি অ্যারে টাইপ কেবল একটি পয়েন্টারে রূপান্তরিত হয়।

int *fillarr( int arr[] ) { // arr "decays" to type int *
    return arr;
}

আপনি আর্গুমেন্ট এবং রিটার্নের জন্য অ্যারে রেফারেন্স ব্যবহার করে এটি উন্নত করতে পারেন যা ক্ষয় রোধ করে:

int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
    return arr;
}

বুস্ট বা সি ++ 11 দিয়ে, পাস-বাই-রেফারেন্সটি কেবলমাত্র alচ্ছিক এবং বাক্য গঠনটি কম মন-বাঁকানো:

array< int, 5 > &fillarr( array< int, 5 > &arr ) {
    return arr; // "array" being boost::array or std::array
}

arrayটেমপ্লেট কেবল একটি উত্পন্ন structযাতে আপনি অবজেক্ট ওরিয়েন্টেড শব্দার্থবিদ্যা আবেদন এখনো অ্যারের মূল সরলতা বজায় রাখা করতে পারেন ধারণকারী একটি সি-শৈলী অ্যারে।


4
রেফারেন্স দিয়ে অ্যারে কীভাবে পাস করা যায় তার উদাহরণ দেওয়ার জন্য +1 তবে আপনি ভুল হয়ে গেছেন যে আপনি রেফারেন্স দিয়ে কোনও অ্যারে ফিরিয়ে দিতে পারবেন না। সবচেয়ে সহজ সিনট্যাক্স অর্জনে এটা একটি typedef ব্যবহার করা: typedef int array[5]; array& foo();কিন্তু আপনি এমনকি হয় typedef প্রয়োজন হবে না যদি এই লিখতে পরোয়া: int (&foo())[5] { static int a[5] = {}; return a; }, প্রশ্নে উদাহরণ হবে: int (&foo( int (&a)[5] ))[5] { return a; }। সরল, তাই না?
ডেভিড রদ্রিগেজ -

@ ডেভিড: ধন্যবাদ, আমি কমেউ বার্তাটি থেকে ভুল ধারণা পেয়েছি error: function returning array is not allowedযা ঘটে যদি আপনি নন-টাইপডেফ সিনট্যাক্সে বাইরের পেরেনগুলি ছেড়ে যান। সৌভাগ্যক্রমে, আজ আমি অন্য প্রশ্নের ডান-বাম নিয়ম পর্যালোচনা করেছি এবং সঠিক জিনিসটি তৈরি করতে পরিচালিত করেছি ... আপনাকে দেখার পরে এটি সম্ভব হয়েছে… আপনি কোডটি দিয়েছেন তা দেখার আগে: ভিপি।
পোটোসওয়টার

1
চুবসদাদের উত্তরের মান থেকে সঠিক উদ্ধৃতি রয়েছে: আপনি কোনও অ্যারে ফিরিয়ে দিতে পারবেন না, তবে আপনি কোনও অ্যারেতে রেফারেন্স বা পয়েন্টারটি ফিরিয়ে দিতে পারেন। অ্যারেগুলি অনুলিপিযোগ্য (এক ধরণের হিসাবে) এবং এগুলি হিসাবে তাদের ফেরত দেওয়া যাবে না - যা একটি অনুলিপি বোঝায় - এবং যখন সিনট্যাক্স উপস্থিত থাকে সংকলকটি যুক্তিটিকে পয়েন্টারে রূপান্তরিত করে।
ডেভিড রদ্রিগেজ - ড্রিবিস

3
@ ডেভিড: তাই হয়। এই পৃষ্ঠাটি উদ্ভট দীর্ঘ হতে চলেছে। কখনও এত লোক স্বেচ্ছায় এতগুলি তুচ্ছ কাজ লিখেছেন না যে কোনও স্থানে অ্যারে ফিরবে।
পোটোসওয়টার

@ পোটাটোসওয়টার আমি সিপিপিতে নতুন, আপনি কি দ্বিতীয় কোড স্নিপেট বিস্তারিতভাবে ব্যাখ্যা করতে পারবেন? বোঝার জন্য আমি এটিকে কিছু ভাঙ্গতে পারছি না।
কেপিএমজি

23

সি ++ 11 এ আপনি ফিরে আসতে পারেন std::array

#include <array>
using namespace std;

array<int, 5> fillarr(int arr[])
{
    array<int, 5> arr2;
    for(int i=0; i<5; ++i) {
        arr2[i]=arr[i]*2;
    }
    return arr2;
}

2
(...) you can consider the array returned arr2, totally another array (...)
ওপিকে

22

$ 8.3.5 / 8 রাজ্য-

"ফাংশনগুলির মধ্যে রিটার্ন ধরণের অ্যারে বা ফাংশন থাকবে না, যদিও তাদের কাছে রিটার্নের ধরণের পয়েন্টার বা এ জাতীয় বিষয়গুলির উল্লেখ থাকতে পারে। ফাংশনের কোনও অ্যারে থাকবে না, যদিও ফাংশনে পয়েন্টারের অ্যারে থাকতে পারে।"

int (&fn1(int (&arr)[5]))[5]{     // declare fn1 as returning refernce to array
   return arr;
}

int *fn2(int arr[]){              // declare fn2 as returning pointer to array
   return arr;
}


int main(){
   int buf[5];
   fn1(buf);
   fn2(buf);
}

7
আপনার দ্বিতীয় ফাংশন intএকটি অ্যারে নয়, একটি পয়েন্টার দেয় ।
GManNickG

আবার, যখন ফাংশনের ভিতরে আসল অ্যারে আপডেট করা হয় তখন টাইপটি কেন ফিরিয়ে দিন? এটা কি সেরা অনুশীলনের বিষয়?
ড্যান

14

আপনি কীভাবে সেই ফাংশনটি ব্যবহার করার পরিকল্পনা করছেন তার উপর উত্তরটি কিছুটা নির্ভর করতে পারে। সহজ উত্তরের জন্য, সিদ্ধান্ত নেওয়া যাক যে অ্যারের পরিবর্তে, আপনি যা চান তা সত্যই ভেক্টর। ভেক্টরগুলি দুর্দান্ত কারণ সমস্ত বিশ্বের চেহারা যেমন বিরক্তিকর, সাধারণ মান আপনি নিয়মিত পয়েন্টারে সঞ্চয় করতে পারেন। আমরা অন্যান্য বিকল্পগুলি এবং এরপরে কেন আপনি সেগুলি চান তা দেখব:

std::vector<int> fillarr( std::vector<int> arr ) {
    // do something
    return arr;
}

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

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

void fillarr(std::vector<int> &  arr) {
    // modify arr
    // don't return anything
}

এইভাবে আপনি ফাংশনে পাস করা অ্যারের একটি রেফারেন্স পাবেন, এটির কোনও ব্যক্তিগত অনুলিপি নয়। প্যারামিটারে আপনি যে কোনও পরিবর্তন করেন তা কলকারী দেখেন। আপনি চাইলে আপনি এটির কোনও রেফারেন্স ফিরিয়ে দিতে পারেন, তবে এটি সত্যিই দুর্দান্ত ধারণা নয়, কারণ এটি সাজিয়ে বোঝায় যে আপনি যা করেছেন তার থেকে আলাদা কিছু পাচ্ছেন।

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

std::auto_ptr<std::vector<int> > fillarr( const std::vector<int> & arr) {
    std::auto_ptr<std::vector<int> > myArr(new std::vector<int>);
    // do stuff with arr and *myArr
    return myArr;
}

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

এগুলি সমস্তই ফুলে যায় তবে পুরো সংগ্রহে খুব কমই আইডিয়োমেটিক সি ++ কাজ করে। আরও সাধারণভাবে, আপনি এই সংগ্রহগুলির উপর পুনরাবৃত্তি ব্যবহার করবেন। এটি আরও কিছু দেখতে হবে

template <class Iterator>
Iterator fillarr(Iterator arrStart, Iterator arrEnd) {
    Iterator arrIter = arrStart;
    for(;arrIter <= arrEnd; arrIter++)
       ;// do something
    return arrStart;
}

আপনি যদি এই স্টাইলটি দেখতে অভ্যস্ত না হন তবে এটি ব্যবহার করে কিছুটা বিশ্রী দেখায়।

vector<int> arr;
vector<int>::iterator foo = fillarr(arr.begin(), arr.end());

foo এখন পরিবর্তিত প্রারম্ভের দিকে 'নির্দেশ করে' arr

এটি সম্পর্কে সত্যই দুর্দান্ত যা হ'ল এটি ভেক্টর হিসাবে সমানভাবে সি প্যাকেজ অ্যারে এবং অন্যান্য অনেক ধরণের সংগ্রহের মতো কাজ করে for

int arr[100];
int *foo = fillarr(arr, arr+100);

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


বাক্য &void fillarr(std::vector<int> & arr)
গঠনটি

9

এই:

int fillarr(int arr[])

আসলে একইরকম আচরণ করা হয়:

int fillarr(int *arr)

এখন আপনি যদি সত্যিই কোনও অ্যারে ফিরিয়ে দিতে চান তবে আপনি সেই লাইনটি পরিবর্তন করতে পারেন

int * fillarr(int arr[]){
    // do something to arr
    return arr;
}

এটি আসলে কোনও অ্যারে ফিরিয়ে দিচ্ছে না। আপনি অ্যারের ঠিকানার শুরুতে একটি পয়েন্টার ফিরিয়ে দিচ্ছেন।

তবে মনে রাখবেন আপনি অ্যারেতে যাওয়ার সময় আপনি কেবল পয়েন্টারে যাচ্ছেন passing সুতরাং আপনি যখন অ্যারের ডেটাটি সংশোধন করবেন, আপনি আসলে সেই তথ্যটি সংশোধন করছেন যা পয়েন্টারটি নির্দেশ করছে। সুতরাং অ্যারেতে যাওয়ার আগে আপনাকে অবশ্যই বুঝতে হবে যে আপনার ইতিমধ্যে পরিবর্তিত ফলাফলের বাইরে রয়েছে।

যেমন

int fillarr(int arr[]){
   array[0] = 10;
   array[1] = 5;
}

int main(int argc, char* argv[]){
   int arr[] = { 1,2,3,4,5 };

   // arr[0] == 1
   // arr[1] == 2 etc
   int result = fillarr(arr);
   // arr[0] == 10
   // arr[1] == 5    
   return 0;
}

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি আপনার ফিলার ফাংশনটির মতো দৈর্ঘ্য স্থাপন বিবেচনা করতে পারেন।

int * fillarr(int arr[], int length)

আপনি দৈর্ঘ্যটি অ্যারে পূরণ করতে দৈর্ঘ্যটি ব্যবহার করতে পারেন এটি যাই হোক না কেন।

আসলে এটি সঠিকভাবে ব্যবহার করতে। এরকম কিছু করুন:

int * fillarr(int arr[], int length){
   for (int i = 0; i < length; ++i){
      // arr[i] = ? // do what you want to do here
   }
   return arr;
}

// then where you want to use it.
int arr[5];
int *arr2;

arr2 = fillarr(arr, 5);

// at this point, arr & arr2 are basically the same, just slightly
// different types.  You can cast arr to a (char*) and it'll be the same.

আপনি যা করতে চাইছেন তা যদি কিছু ডিফল্ট মানগুলিতে অ্যারে সেট করা থাকে তবে মেমসেট ফাংশনটি অন্তর্নিহিত ব্যবহার করে বিবেচনা করুন।

এর মতো কিছু: মেমসেট ((ইনট *) & এআরআর, 5, মাপের (পূর্বে);

যদিও আমি বিষয়টিতে আছি। আপনি বলছেন আপনি সি ++ ব্যবহার করছেন। Stl ভেক্টর ব্যবহার করে দেখুন। আপনার কোড সম্ভবত আরও শক্তিশালী হতে পারে।

টিউটোরিয়াল প্রচুর আছে। এখানে সেগুলি আপনি কীভাবে ব্যবহার করবেন সে সম্পর্কে একটি ধারণা দেয়। http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html


std::copyওভার ব্যবহার করুন memset, এটি নিরাপদ এবং সহজ। (এবং দ্রুত না হলে ঠিক তত দ্রুত))
GManNGG

5

একটি ফাংশন থেকে একটি অ্যারের ফিরে পেতে, আসুন একটি কাঠামোর মধ্যে অ্যারে সংজ্ঞায়িত করা যাক; সুতরাং এটি কিছু দেখাচ্ছে

struct Marks{
   int list[5];
}

এখন টাইপ স্ট্রাকচারের ভেরিয়েবল তৈরি করি।

typedef struct Marks marks;
marks marks_list;

আমরা নিম্নলিখিত পদ্ধতিতে কোনও ফাংশনে অ্যারে পাস করতে পারি এবং এর মান নির্ধারণ করতে পারি:

void setMarks(int marks_array[]){
   for(int i=0;i<sizeof(marks_array)/sizeof(int);i++)
       marks_list.list[i]=marks_array[i];
}

আমরা অ্যারেও ফিরিয়ে দিতে পারি। অ্যারেটি ফিরিয়ে আনার জন্য, ফাংশনের রিটার্ন টাইপটি কাঠামোর ধরণের অর্থাৎ চিহ্নের হওয়া উচিত। এটি কারণ বাস্তবে আমরা সেই কাঠামোটি পেরিয়ে যাচ্ছি যাতে অ্যারে রয়েছে contains সুতরাং চূড়ান্ত কোডটি দেখতে পারে।

marks getMarks(){
 return marks_list;
}

5

এটি মোটামুটি পুরানো প্রশ্ন, তবে আমি অনেক উত্তর পেয়ে যাচ্ছি তাই আমি আমার 2 সেন্ট স্থাপন করতে যাচ্ছি, তবে স্পষ্ট এবং সংক্ষিপ্ত পদ্ধতিতে সমস্ত সম্ভাব্য পদ্ধতি দেখানো কিছুই নেই (সংক্ষিপ্ত বিট সম্পর্কে নিশ্চিত নয়, যেহেতু এটি পেয়েছে কিছুটা হাতছাড়া T TL; DR 😉)।

আমি ধরে নিচ্ছি যে ওপি কোডটি প্রাকদৃষ্ট দেখতে অন্যরকম ফাংশনে পাস করার জন্য কলটিকে সরাসরি পাস করার কোনও উপায় হিসাবে অনুলিপি ছাড়াই পাস করা অ্যারেটি ফিরিয়ে দিতে চেয়েছিল।

তবে এর মতো অ্যারে ব্যবহার করা হ'ল এটি পয়েন্টারে ক্ষয় হতে দেয় এবং সংকলকটিকে এটি অ্যারের মতো আচরণ করে । সূক্ষ্ম বাগের ফলস্বরূপ আপনি যদি একটি অ্যারে পাস করেন তবে ফাংশনটি আশা করে যে এটিতে 5 টি উপাদান থাকবে তবে আপনার কলারটি অন্য কোনও সংখ্যায় আসলে পাস করবে।

এটি আরও ভালভাবে পরিচালনা করতে পারে এমন কয়েকটি উপায়। একটি মধ্যে পাস std::vectorবা std::array(যদি নিশ্চিত না std::array2010 সালে প্রায় ছিল যখন প্রশ্ন জিজ্ঞাসা করা হল)। তারপরে আপনি অবজেক্টটির কোনও অনুলিপি / চলন ছাড়াই রেফারেন্স হিসাবে বস্তুকে পাস করতে পারেন।

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) তবে তারা এই প্রসঙ্গে কাজ করে না।


3

এটি করার সহজতম উপায় হ'ল রেফারেন্সের মাধ্যমে এটি ফিরিয়ে দেওয়া, আপনি '&' চিহ্নটি না লিখলেও তা স্বয়ংক্রিয়ভাবে রেফারেন্স দ্বারা ফিরে আসে

     void fillarr(int arr[5])
  {
       for(...);

  }

2
int *fillarr(int arr[])

আপনি এখনও ফলাফলটি পছন্দ মতো ব্যবহার করতে পারেন

int *returned_array = fillarr(some_other_array);
if(returned_array[0] == 3)
    do_important_cool_stuff();

আমি মনে করি না যে 'ইনট [] ফিলার ...' আইনী। অ্যারে-পয়েন্টার সমতুলতার কারণে আপনি 'ইনট * ফিলার' ব্যবহার করেন।

1

উপরে উল্লিখিত পাথ সঠিক হিসাবে। তবে আমি মনে করি যদি আমরা কেবল কোনও ফাংশনের স্থানীয় অ্যারে ভেরিয়েবলটি ফিরে পাই তবে এটি কখনও কখনও আবর্জনার মানগুলিকে তার উপাদান হিসাবে ফিরিয়ে দেয়।

যাতে এড়ানোর জন্য আমাকে গতিশীল অ্যারে তৈরি করে এগিয়ে যেতে হয়েছিল। যা এরকম কিছু।

int* func()
{
  int* Arr = new int[100];
  return Arr;
}

int main()
{
  int* ArrResult = func();
  cout << ArrResult[0] << " " << ArrResult[1] << endl;
  return 0;
} 




0

0

সূত্র: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_function.htm

সি ++ কোনও ক্রিয়াকলাপের আর্গুমেন্ট হিসাবে পুরো অ্যারেটি ফেরত দেওয়ার অনুমতি দেয় না। তবে, আপনি বিন্যাস ছাড়াই অ্যারের নাম উল্লেখ করে একটি বিন্দুতে অ্যারেতে ফিরে আসতে পারেন।

  1. আপনি যদি কোনও ফাংশন থেকে একটি একক মাত্রার অ্যারেটি ফিরিয়ে দিতে চান তবে আপনাকে নীচের উদাহরণের মতো একটি পয়েন্টার ফিরিয়ে ফাংশনটি ঘোষণা করতে হবে:
int * myFunction()    {
   .
   .
   .
}
  1. সি ++ ফাংশনের বাইরে স্থানীয় ভেরিয়েবলের ঠিকানা ফেরত দেওয়ার পক্ষে সমর্থন করে না যাতে আপনার স্থানীয় ভেরিয়েবলটিকে স্থির পরিবর্তনশীল হিসাবে সংজ্ঞায়িত করতে হয়।

বর্তমান প্রশ্নের উপর এই নিয়মগুলি প্রয়োগ করে, আমরা প্রোগ্রামটি নিম্নরূপে লিখতে পারি:

# include <iostream>

using namespace std;

int * fillarr( );


int main ()
{

   int *p;

   p = fillarr();

   for ( int i = 0; i < 5; i++ )
       cout << "p[" << i << "] : "<< *(p + i) << endl;

    return 0;
}


int * fillarr( )
{
    static int  arr[5];

    for (int i = 0; i < 5; ++i)
        arr[i] = i;

    return arr;
 }

আউটপুটটি হবে:

p[0]=0
p[1]=1
p[2]=2
p[3]=3
p[4]=4

0

এবং কি সম্পর্কে:

int (*func())
{
    int *f = new int[10] {1,2,3};

    return f;
}

int fa[10] = { 0 };
auto func2() -> int (*) [10]
{
    return &fa;
}

0

আসলে আপনি যখন কোনও ফাংশনের অভ্যন্তরে অ্যারে পাস করেন তখন ফাংশন প্যারামিটারে মূল অ্যারের নির্দেশকটি পাস হয়ে যায় এবং সুতরাং সেই ফাংশনের অভ্যন্তরে অ্যারেতে করা পরিবর্তনগুলি আসলে আসল অ্যারেতে করা হয়।

#include <iostream>

using namespace std;

int* func(int ar[])
{
    for(int i=0;i<100;i++) 
        ar[i]=i;
    int *ptr=ar;
    return ptr;
}


int main() {
    int *p;
    int y[100]={0};    
    p=func(y);

    for(int i=0;i<100;i++) 
        cout<<i<<" : "<<y[i]<<'\n';
}

এটি চালান এবং আপনি পরিবর্তনগুলি দেখতে পাবেন


1
দয়া করে যথাযথ ইংরাজী শব্দযুক্ত শব্দ ব্যবহার করুন (আপনি পরিবর্তে ইউল্ট হবেন) এবং "বন্ধু" এর মতো খালি বাক্যাংশ বাদ দিন।
হেলো

এছাড়াও: "তাহলে আসলে এটি একটি রেফারেন্স হিসাবে পাস করা হয়েছে" ভুল। ভেরিয়েবলটি yনিজেই একটি অনুলিপি হিসাবে পাস করা হয় তবে এটি একটি পয়েন্টার হওয়ায় আপনি সরাসরি অ্যারেতে পরিচালনা করবেন। আপনার উত্তর সম্পাদনা করুন।
হেলো

stackoverflow.com/questions/5573310/… টিএল; ডিআর; ডিআর "সুতরাং, দুটি রূপ একরকম" "
হেলো

হ্যাঁ এটি প্রযুক্তিগতভাবে একটি অ্যারে, আপনি ঠিক বলেছেন, তবে যা অনুলিপি করা হয়েছে তা অ্যারের কাছে একটি পয়েন্টার, নিজেই অ্যারে নয়।
হেলো

0

এই ধরণের সমস্যার সমাধানের সম্পূর্ণ উদাহরণ এখানে

#include <bits/stdc++.h>
using namespace std;
int* solve(int brr[],int n)
{
sort(brr,brr+n);
return brr;
}

int main()
{
int n;
cin>>n;
int arr[n];
for(int i=0;i<n;i++)
{
    cin>>arr[i];
}
int *a=solve(arr,n);
for(int i=0;i<n;i++)
{
    cout<<a[i]<<endl;
}

return 0;
}

-2

রিটার্ন মান হিসাবে কেবল একটি প্রকারকে সংজ্ঞায়িত করুন, যেমন:

        private string[] functionReturnValueArray(string one, string two)
    {

        string[] x = {one, two};


        x[0] = "a";
        x[1] = "b";

        return x;
    }

। । । ফাংশন কল:

string[] y;
y = functionReturnValueArray(stringOne, stringTwo)

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