Trả về mảng trong một hàm


212

Tôi có một mảng int arr[5]được truyền cho một hàm fillarr(int arr[]):

int fillarr(int arr[])
{
    for(...);
    return arr;
}
  1. Làm thế nào tôi có thể trả lại mảng đó?
  2. Làm thế nào tôi sẽ sử dụng nó, nói rằng tôi đã trả lại một con trỏ làm thế nào tôi sẽ truy cập nó?

46
Nói đúng ra trong ngữ cảnh này, bạn không cần trả về mảng vì mảng được truyền bằng tham chiếu nên mọi thay đổi đối với các phần tử bên trong 'mảng' sẽ được nhìn thấy bên ngoài hàm.
BuggerMe

12
trả về mảng là thuận tiện cho các chức năng chuỗi.
seand

5
Miễn là bạn không phạm sai lầm khi tạo một mảng trên ngăn xếp và trả về một con trỏ cho nó.
gièm pha

2
@ismail: Nó không thể trả về một mảng mới, trừ khi mảng đó được phân bổ động. Và nếu đó là trường hợp, sử dụng std::vector.
GManNickG

4
@BuggerMe: Mảng không được chuyển qua tham chiếu (trừ khi bạn yêu cầu nó với cú pháp hài hước hơn nhiều), trong mã, mảng phân rã thành một con trỏ đến phần tử đầu tiên và được truyền cho hàm. Các 5trong chữ ký chức năng bị loại bỏ bởi trình biên dịch.
David Rodríguez - dribeas

Câu trả lời:


204

Trong trường hợp này, biến mảng của bạn arrthực sự cũng có thể được coi là một con trỏ đến đầu khối của mảng trong bộ nhớ, bằng một chuyển đổi ngầm định. Cú pháp mà bạn đang sử dụng:

int fillarr(int arr[])

Là loại chỉ cú pháp đường. Bạn thực sự có thể thay thế nó bằng cái này và nó vẫn hoạt động:

int fillarr(int* arr)

Vì vậy, theo nghĩa tương tự, những gì bạn muốn trả về từ hàm của bạn thực sự là một con trỏ đến phần tử đầu tiên trong mảng:

int* fillarr(int arr[])

Và bạn vẫn có thể sử dụng nó giống như một mảng bình thường:

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

45
Để làm rõ, "tuyên bố C ++ cổ điển" là sai; mảng không phải là con trỏ.
GManNickG

25
nhớ a [i] == * (a + i) quy tắc
seand

8
@Brent Nash, không. một mảng là một mảng. Một con trỏ đến đầu mảng là một con trỏ. Nó chỉ xảy ra rằng trình biên dịch có một số đường cú pháp thực hiện dịch cho bạn trong một số tình huống. array&arraycó thể hoán đổi cho nhau trong rất nhiều trường hợp.
Carl Norum

20
@Brent: Không. Một mảng là kiểu riêng, nó không phải là một loại con trỏ đặc biệt. Các loại atrong int a[10]int[10]. Những gì bạn có thể nói là mảng "phân rã" thành con trỏ đến phần tử đầu tiên của chúng. (Đây là một chuyển đổi mảng-con trỏ ngầm định.) Sau đó, câu trả lời của bạn sẽ đi dọc theo dòng của tôi. Nếu bạn chỉnh sửa câu trả lời của mình để phân biệt giữa các mảng, chuyển đổi mảng sang con trỏ và con trỏ, tôi sẽ xóa câu trả lời của mình vì chúng sẽ có cùng thông tin cốt lõi và bạn là người đầu tiên.
GManNickG

8
@seand hãy nhớ quy tắc [i] == * (a + sizeof (a) * i)
Amir

114

Các hàm C ++ không thể trả về các mảng kiểu C theo giá trị. Điều gần nhất là trả về một con trỏ. Hơn nữa, một kiểu mảng trong danh sách đối số chỉ đơn giản được chuyển đổi thành một con trỏ.

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

Bạn có thể cải thiện nó bằng cách sử dụng một tham chiếu mảng cho đối số và trả về, điều này ngăn sự phân rã:

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

Với Boost hoặc C ++ 11, tham chiếu qua chỉ là tùy chọn và cú pháp ít gây chú ý hơn:

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

Các arraymẫu đơn giản tạo ra một structchứa một mảng C-phong cách, vì vậy bạn có thể áp dụng ngữ nghĩa hướng đối tượng nhưng giữ lại sự đơn giản ban đầu của mảng.


4
+1 để đưa ra một ví dụ về cách một mảng có thể được truyền bằng tham chiếu. Nhưng bạn đã sai ở chỗ bạn không thể trả về một mảng bằng cách tham chiếu. Cú pháp đơn giản nhất để đạt được nó là bằng cách sử dụng một typedef: typedef int array[5]; array& foo();Nhưng bạn thậm chí không cần typedef nếu bạn quan tâm để viết điều này : int (&foo())[5] { static int a[5] = {}; return a; }, ví dụ trong câu hỏi sẽ là : int (&foo( int (&a)[5] ))[5] { return a; }. Đơn giản phải không?
David Rodríguez - dribeas

@David: cảm ơn, tôi đã nhận được sự đánh giá sai từ thông điệp Comeau error: function returning array is not allowedxảy ra nếu bạn bỏ qua các dấu ngoặc ngoài trong cú pháp không typedef. May mắn thay, hôm nay tôi đã xem lại quy tắc bên trái cho một câu hỏi khác và quản lý để xây dựng điều đúng đắn sau khi thấy bạn nói điều đó có thể xảy ra trước khi thấy rằng bạn đã đưa ra mã: vP.
Potatoswatter

1
Câu trả lời của chubsdad có trích dẫn chính xác từ tiêu chuẩn: bạn không thể trả về một mảng, nhưng bạn có thể trả về một tham chiếu hoặc con trỏ tới một mảng. Mảng không thể sao chép (dưới dạng một loại) và vì vậy chúng không thể được trả về - trong đó sẽ ngụ ý một bản sao-- và khi cú pháp đó xuất hiện, trình biên dịch sẽ chuyển đổi đối số thành một con trỏ.
David Rodríguez - dribeas

3
@David: Nó cũng vậy. Trang này đang trở nên dài một cách kỳ lạ. Không bao giờ có nhiều người tự nguyện viết quá nhiều hàm tầm thường trả về một mảng ở một nơi.
Potatoswatter

@Potatoswatter Tôi mới sử dụng cpp, Bạn có thể giải thích chi tiết về đoạn mã thứ 2 không? Tôi không thể chia nó thành nhiều phần để hiểu.
KPMG

23

Trong C ++ 11, bạn có thể quay lại 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
Trích dẫn OP:(...) you can consider the array returned arr2, totally another array (...)
cubuspl42

22

$ 8,3,5 / 8 tiểu bang-

"Các hàm sẽ không có kiểu trả về của mảng hoặc hàm kiểu, mặc dù chúng có thể có kiểu trả về của con trỏ kiểu hoặc tham chiếu đến những thứ đó. Sẽ không có mảng các hàm, mặc dù có thể có các mảng con trỏ tới các hàm."

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
Hàm thứ hai của bạn trả về một con trỏ tới một int, không phải là một mảng.
GManNickG

một lần nữa, tại sao trả về kiểu khi mảng thực tế được cập nhật bên trong hàm? Đó có phải là một vấn đề thực hành tốt nhất?
Dan

14

câu trả lời có thể phụ thuộc một chút vào cách bạn dự định sử dụng chức năng đó. Đối với câu trả lời đơn giản nhất, hãy quyết định rằng thay vì một mảng, thứ bạn thực sự muốn là một vectơ. Các vectơ là tốt bởi vì cái nhìn cho tất cả thế giới như nhàm chán, giá trị thông thường bạn có thể lưu trữ trong con trỏ thông thường. Chúng tôi sẽ xem xét các tùy chọn khác và lý do tại sao bạn muốn chúng sau đó:

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

Điều này sẽ làm chính xác những gì bạn mong đợi nó làm. Ưu điểm là std::vectorđảm bảo mọi thứ được xử lý sạch sẽ. Nhược điểm là điều này sao chép một lượng dữ liệu rất lớn, nếu mảng của bạn lớn. Trong thực tế, nó sao chép mọi phần tử của mảng hai lần. đầu tiên nó sao chép vectơ để hàm có thể sử dụng nó làm tham số. sau đó nó sao chép lại để trả lại cho người gọi. Nếu bạn có thể tự mình quản lý vector, bạn có thể thực hiện mọi việc dễ dàng hơn một chút. (nó có thể sao chép lần thứ ba nếu người gọi cần lưu trữ nó trong một biến số nào đó để tính toán nhiều hơn)

Có vẻ như những gì bạn đang thực sự cố gắng chỉ là đưa vào một bộ sưu tập. nếu bạn không có lý do cụ thể để trả về một phiên bản mới của bộ sưu tập thì không. chúng ta có thể làm như thế này

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

bằng cách này bạn có được một tham chiếu đến mảng được truyền cho hàm, không phải là bản sao riêng của nó. bất kỳ thay đổi nào bạn thực hiện đối với tham số đều được người gọi nhìn thấy. Bạn có thể trả lại một tham chiếu đến nó nếu bạn muốn, nhưng đó không thực sự là một ý tưởng tuyệt vời, vì nó ngụ ý rằng bạn đang nhận được một cái gì đó khác với những gì bạn đã vượt qua.

Nếu bạn thực sự cần một phiên bản mới của bộ sưu tập, nhưng muốn tránh có nó trên ngăn xếp (và tất cả các bản sao đòi hỏi), bạn cần tạo một loại hợp đồng để xử lý trường hợp đó. cách dễ nhất để làm điều đó là sử dụng một con trỏ thông minh, giữ cho cá thể được tham chiếu xung quanh miễn là bất cứ ai đang giữ nó. Nó biến mất sạch sẽ nếu nó đi ra khỏi phạm vi. Điều đó sẽ trông như thế này.

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;
}

Đối với hầu hết các phần, sử dụng *myArrcác tác phẩm giống hệt nhau để sử dụng một vectơ vanilla đơn giản. Ví dụ này cũng sửa đổi danh sách tham số bằng cách thêm consttừ khóa. Bây giờ bạn có được một tham chiếu mà không cần sao chép nó, nhưng bạn không thể sửa đổi nó, vì vậy người gọi biết rằng nó sẽ giống như trước khi chức năng có được nó.

Tất cả điều này là sưng lên, nhưng thành ngữ c ++ hiếm khi hoạt động với các bộ sưu tập nói chung. Thông thường hơn, bạn sẽ sử dụng các trình vòng lặp trên các bộ sưu tập đó. nó sẽ trông giống như thế này

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

Sử dụng nó có vẻ hơi kỳ lạ nếu bạn không quen nhìn phong cách này.

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

foo bây giờ 'chỉ vào' bắt đầu sửa đổi arr.

Điều thực sự tốt về điều này là nó hoạt động tốt như nhau trên vector như trên mảng C đơn giản và nhiều loại bộ sưu tập khác, ví dụ

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

Mà bây giờ trông rất nhiều như các ví dụ con trỏ đơn giản được đưa ra ở nơi khác trong câu hỏi này.


Cú pháp sai, &biểu tượng phải xuất hiện sau loại:void fillarr(std::vector<int> & arr)
David Rodríguez - dribeas

9

Điều này:

int fillarr(int arr[])

thực sự được đối xử giống như:

int fillarr(int *arr)

Bây giờ nếu bạn thực sự muốn trả về một mảng, bạn có thể thay đổi dòng đó thành

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

Nó không thực sự trả về một mảng. bạn đang trả về một con trỏ để bắt đầu địa chỉ mảng.

Nhưng hãy nhớ khi bạn vượt qua trong mảng, bạn chỉ chuyển qua một con trỏ. Vì vậy, khi bạn sửa đổi dữ liệu mảng, bạn thực sự sửa đổi dữ liệu mà con trỏ đang trỏ tới. Do đó trước khi bạn chuyển vào mảng, bạn phải nhận ra rằng bạn đã có bên ngoài kết quả được sửa đổi.

ví dụ

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;
}

Tôi đề nghị bạn có thể muốn xem xét đưa độ dài vào hàm fillarr của bạn như thế này.

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

Bằng cách đó, bạn có thể sử dụng chiều dài để điền vào mảng theo chiều dài của nó bất kể đó là gì.

Để thực sự sử dụng nó đúng cách. Làm một cái gì đó như thế này:

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.

Nếu tất cả những gì bạn muốn làm là đặt mảng thành một số giá trị mặc định, hãy xem xét sử dụng chức năng ghi nhớ tích hợp.

một cái gì đó như: memset ((int *) & Array, 5, sizeof (int));

Trong khi tôi đang ở chủ đề này. Bạn nói rằng bạn đang sử dụng C ++. Có một cái nhìn vào việc sử dụng các vectơ stl. Mã của bạn có khả năng mạnh mẽ hơn.

Có rất nhiều hướng dẫn. Đây là một trong đó cung cấp cho bạn một ý tưởng về cách sử dụng chúng. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html


Sử dụng std::copyhơn memset, nó an toàn và dễ dàng hơn. (Và cũng nhanh như vậy nếu không nhanh hơn.)
GManNickG

5

để trả về một mảng từ một hàm, chúng ta hãy định nghĩa mảng đó trong một cấu trúc; Vì vậy, nó trông giống như thế này

struct Marks{
   int list[5];
}

Bây giờ chúng ta hãy tạo các biến của cấu trúc kiểu.

typedef struct Marks marks;
marks marks_list;

Chúng ta có thể truyền mảng cho một hàm theo cách sau và gán giá trị cho nó:

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

Chúng tôi cũng có thể trả về mảng. Để trả về mảng, kiểu trả về của hàm phải là kiểu cấu trúc tức là dấu. Điều này là do trong thực tế, chúng ta đang chuyển qua cấu trúc có chứa mảng. Vì vậy, mã cuối cùng có thể trông như thế này.

marks getMarks(){
 return marks_list;
}

5

Đây là một câu hỏi khá cũ, nhưng tôi sẽ đặt vào 2 xu của mình vì có rất nhiều câu trả lời, nhưng không có câu trả lời nào cho thấy tất cả các phương pháp có thể một cách rõ ràng và súc tích (không chắc chắn về bit ngắn gọn, vì điều này có một bit ra khỏi tay. TL; DR).

Tôi giả định rằng OP muốn trả về mảng đã được truyền vào mà không cần sao chép vì một số phương tiện truyền trực tiếp này cho người gọi để được chuyển đến một chức năng khác để làm cho mã trông đẹp hơn.

Tuy nhiên, để sử dụng một mảng như thế này là để cho nó phân rã thành một con trỏ và trình biên dịch coi nó như một mảng. Điều này có thể dẫn đến các lỗi tinh vi nếu bạn truyền vào một mảng như thế, với chức năng hy vọng rằng nó sẽ có 5 phần tử, nhưng trình gọi của bạn thực sự chuyển qua một số khác.

Có một vài cách bạn có thể xử lý việc này tốt hơn. Chuyển qua một std::vectorhoặc std::array(không chắc chắn std::arraylà khoảng năm 2010 khi câu hỏi được hỏi). Sau đó, bạn có thể truyền đối tượng làm tham chiếu mà không cần sao chép / di chuyển đối tượng.

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;
}

Tuy nhiên, nếu bạn khăng khăng chơi với mảng C, thì hãy sử dụng một mẫu sẽ giữ thông tin có bao nhiêu mục trong mảng.

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;
}

Ngoại trừ, nó trông mông xấu xí, và siêu khó đọc. Bây giờ tôi sử dụng một cái gì đó để giúp với những thứ không có trong năm 2010, mà tôi cũng sử dụng cho các con trỏ hàm:

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;
}

Này di chuyển loại nơi người ta mong chờ nó được, làm cho này xa dễ đọc hơn. Tất nhiên, sử dụng một mẫu là không cần thiết nếu bạn sẽ không sử dụng bất cứ thứ gì ngoài 5 yếu tố, do đó, tất nhiên bạn có thể mã cứng nó:

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;
}

Như tôi đã nói, type_t<>mánh khóe của tôi sẽ không có tác dụng vào thời điểm câu hỏi này được hỏi. Điều tốt nhất bạn có thể hy vọng trở lại sau đó là sử dụng một loại trong một cấu trúc:

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;
}

Cái này bắt đầu trông khá xấu xí một lần nữa, nhưng ít nhất vẫn dễ đọc hơn, mặc dù typenamecó thể là tùy chọn trở lại sau đó tùy thuộc vào trình biên dịch, dẫn đến:

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;
}

Và dĩ nhiên sau đó bạn có thể đã chỉ định một loại cụ thể, thay vì sử dụng trình trợ giúp của tôi.

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;
}

Trước đó, các chức năng miễn phí std::begin()std::end()không tồn tại, mặc dù có thể dễ dàng thực hiện. Điều này sẽ cho phép lặp qua mảng một cách an toàn hơn vì chúng có ý nghĩa trên mảng C, nhưng không phải là một con trỏ.

Đối với việc truy cập mảng, bạn có thể chuyển nó sang một hàm khác có cùng loại tham số hoặc tạo bí danh cho nó (điều này sẽ không có ý nghĩa nhiều như bạn đã có bản gốc trong phạm vi đó). Truy cập một tham chiếu mảng cũng giống như truy cập vào mảng ban đầu.

void other_function(type_t<int(&)[5]> x) { /* do something else */ }

void fn()
{
    int array[5];
    other_function(fillarr(array));
}

hoặc là

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
}

Tóm lại, tốt nhất là không cho phép một mảng phân rã thành một con trỏ nếu bạn có ý định lặp lại nó. Nó chỉ là một ý tưởng tồi vì nó giữ cho trình biên dịch bảo vệ bạn khỏi bị bắn vào chân và làm cho mã của bạn khó đọc hơn. Luôn cố gắng và giúp trình biên dịch giúp bạn bằng cách giữ các loại càng lâu càng tốt trừ khi bạn có lý do rất chính đáng để không làm như vậy.

Biên tập

Ồ, và để hoàn thiện, bạn có thể cho phép nó biến thành một con trỏ, nhưng điều này tách rời mảng khỏi số phần tử mà nó giữ. Điều này được thực hiện rất nhiều trong C / C ++ và thường được giảm thiểu bằng cách chuyển số lượng phần tử trong mảng. Tuy nhiên, trình biên dịch không thể giúp bạn nếu bạn mắc lỗi và chuyển sai giá trị cho số phần tử.

// separate size value
int* fillarr(int* arr, size_t size)
{
    for(int* it = arr; it != arr + size; ++it)
    { /* do stuff */ }
    return arr;
}

Thay vì vượt qua kích thước, bạn có thể vượt qua con trỏ kết thúc, nó sẽ trỏ đến một điểm qua cuối mảng của bạn. Điều này rất hữu ích vì nó làm cho một cái gì đó gần với các thuật toán tiêu chuẩn hơn, lấy con trỏ bắt đầu và kết thúc, nhưng những gì bạn trả về bây giờ chỉ là thứ bạn phải nhớ.

// separate end pointer
int* fillarr(int* arr, int* end)
{
    for(int* it = arr; it != end; ++it)
    { /* do stuff */ }
    return arr;
}

Ngoài ra, bạn có thể tài liệu rằng chức năng này sẽ chỉ có 5 yếu tố và hy vọng rằng người dùng chức năng của bạn sẽ không làm điều gì ngu ngốc.

// 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;
}

Lưu ý rằng giá trị trả về đã mất loại ban đầu và bị biến thành con trỏ. Vì điều này, giờ đây bạn phải tự mình đảm bảo rằng bạn sẽ không vượt qua mảng.

Bạn có thể vượt qua một std::pair<int*, int*>cái mà bạn có thể sử dụng để bắt đầu và kết thúc và vượt qua nó, nhưng sau đó nó thực sự dừng lại trông giống như một mảng.

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];
}

hoặc là

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])));
}

Hài hước lắm, điều này rất giống với cách std::initializer_listlàm việc (c ++ 11), nhưng chúng không hoạt động trong bối cảnh này.


3

Cách đơn giản nhất để thực hiện việc này là trả về bằng tham chiếu, ngay cả khi bạn không viết biểu tượng '&', nó sẽ tự động được trả về bằng tham chiếu

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

  }

2
int *fillarr(int arr[])

Bạn vẫn có thể sử dụng kết quả như

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

Tôi không nghĩ rằng 'int [] fillarr ...' là hợp pháp. 'Int * fillarr' là những gì bạn sẽ sử dụng do tương đương với con trỏ mảng.
seand

1

Như đã nói ở trên là đúng. Nhưng tôi nghĩ rằng nếu chúng ta chỉ trả về một biến mảng cục bộ của hàm thì đôi khi nó trả về các giá trị rác như là các phần tử của nó.

để tránh điều đó tôi phải tạo ra mảng một cách linh hoạt và tiến hành. Đó là một cái gì đó như thế này.

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

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




0

0

Nguồn: https://www.tutorialspoint.com/cplusplus/cpp_return_arrays_from_fifts.htmlm

C ++ không cho phép trả về toàn bộ một mảng làm đối số cho hàm. Tuy nhiên, bạn có thể trả về một con trỏ tới một mảng bằng cách chỉ định tên của mảng mà không có chỉ mục.

  1. Nếu bạn muốn trả về một mảng một chiều từ một hàm, bạn sẽ phải khai báo một hàm trả về một con trỏ như trong ví dụ sau:
int * myFunction()    {
   .
   .
   .
}
  1. C ++ không ủng hộ việc trả lại địa chỉ của biến cục bộ ra bên ngoài hàm nên bạn sẽ phải xác định biến cục bộ là biến tĩnh.

Áp dụng các quy tắc này cho câu hỏi hiện tại, chúng ta có thể viết chương trình như sau:

# 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;
 }

Đầu ra sẽ là:

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

0

và thế còn:

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

    return f;
}

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

0

Thực tế khi bạn truyền một mảng bên trong một hàm, con trỏ tới mảng ban đầu được truyền vào tham số hàm và do đó những thay đổi được thực hiện cho mảng bên trong hàm đó thực sự được thực hiện trên mảng ban đầu.

#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';
}

Chạy nó và bạn sẽ thấy những thay đổi


1
Vui lòng sử dụng từ ngữ tiếng Anh thích hợp (bạn sẽ thay vì bạn sẽ) và bỏ qua các cụm từ trống như "bạn thân".
hellow

Ngoài ra: "sau đó thực sự nó được thông qua như một tài liệu tham khảo" là sai. Bản ythân biến được truyền dưới dạng bản sao của chính nó, nhưng vì là con trỏ nên bạn sẽ trực tiếp thao tác trên mảng. Vui lòng chỉnh sửa câu trả lời của bạn.
hellow

stackoverflow.com/questions/5573310/ TL TL; DR "Do đó, hai hình thức giống hệt nhau."
hellow

Vâng, về mặt kỹ thuật, đó là một mảng, bạn đúng, nhưng những gì được sao chép là một con trỏ tới mảng, chứ không phải chính mảng đó.
hellow

0

Dưới đây là một ví dụ đầy đủ về loại vấn đề này để giải quyết

#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

Chỉ cần xác định một loại [] là giá trị trả về, như:

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

        string[] x = {one, two};


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

        return x;
    }

. . . chức năng gọi:

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

5
Đây không phải là C ++
Adrian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.