2010-01-26 46 views
9

OK, tôi đang cố gắng để có được một mảng phụ từ một mảng hiện có và tôi chỉ không chắc chắn làm thế nào để làm điều đó. Trong ví dụ của tôi, tôi có một mảng rất lớn, nhưng tôi muốn tạo một mảng từ 5 phần tử cuối cùng của mảng.Cách tốt nhất để tạo mảng phụ từ mảng hiện có trong C++ là gì?

Một ví dụ về những gì tôi đang nói về sẽ là:

int array1 = {1,2,3,...99,100}; 
int array2[5] = array1+95; 

Tôi biết điều này là không đúng, nhưng tôi đang gặp một số sự cố khi nhận nó đúng. Tôi muốn lấy các phần tử từ 96 đến 100 trong mảng 1 và đặt chúng vào mảng2 nhưng tôi không muốn sao chép mảng. Tôi chỉ muốn mảng2 bắt đầu tại phần tử 96 sao cho mảng1 [96] và mảng2 [0] sẽ trỏ đến cùng một vị trí.

+0

Hãy nhớ rằng bạn sẽ không thể tạo ra một mảng phụ bằng cách trỏ đến một phần tử. – GManNickG

+0

Phần tử thứ 96 của 'mảng1' là' mảng1 [95] '. Khi bạn nói "đặt chúng trong mảng2", nó * có nghĩa là * sao chép, làm cách nào khác bạn sẽ đặt chúng trong mảng2? Không có cách nào để làm những gì bạn muốn. Bạn cần sao chép các phần tử, hoặc có một con trỏ trỏ tới phần tử thứ 96 của 'mảng1', hoặc có một mảng gồm 5 con trỏ, và có con trỏ' i' trỏ đến phần tử '95 + i' của' mảng1 '. –

+0

bạn là chính xác, bằng cách "đặt chúng array2" Tôi không có nghĩa là để sao chép. Tôi xin lỗi vì sự hỗn hợp trong thuật ngữ. –

Trả lời

18

cho việc này:

"such that array1[96] and array2[0] would be pointing to the same location." 

bạn có thể làm:

int *arr2 = arr1 + 96; 
assert(arr2[0] == arr1[96] == 97); 
+3

Đó là 'khẳng định' nên là một nhà toán học khẳng định, chứ không phải C :-) –

+0

công trình này! Cảm ơn bạn! –

+1

+1 cho giải pháp đơn giản hoạt động. –

0

Bạn nói bạn không muốn sao chép mảng, nhưng có được một con trỏ đến năm yếu tố cuối cùng. Bạn gần như đã có nó:

int array1[] = {1,2,3,...99,100}; 
int* array2 = &array1[95]; 
+0

khi tôi thử rằng tôi nhận được lỗi này: không thể chuyển đổi từ 'int *' thành 'int []' –

+1

'int array2 [] = array1 + 95;' là bất hợp pháp. –

+0

Phải là int array1 [] = {1,2,3, ... 99,100}; int * array2 = array1 + 95; Bạn không thể khởi tạo một mảng (dấu ngoặc vuông) bằng một con trỏ - nó có thể cho biết nó bắt đầu ở đâu nhưng không phải là kích thước của nó. – BenG

1

Trong C++ bạn có thể sử dụng con trỏ int làm mảng int, do giới hạn kích thước, vì vậy bạn có thể làm điều này

int array2 [] = & array1 [96];

hay này

int *array2 = &array1[96]; 

nhưng KHÔNG này

int array2[5] = &array1[96]; // this doesn't work. 

Mặt khác, C++ không thi hành giới hạn kích thước mảng anyway, do sự mất mát thật duy nhất là bạn có thể' t sử dụng sizeof để lấy số phần tử trong mảng2.

lưu ý: &array1[96] là điều tương tự như array+96

chỉnh sửa: chỉnh - int array[] = &array[96] là không hợp lệ, bạn chỉ có thể sử dụng [] như là một từ đồng nghĩa với * khi tuyên bố một danh sách tham số chức năng.

vì vậy đây được phép

extern int foo(int array2[]); 
foo (&array1[96]); 
+0

Tôi vẫn gặp lỗi khi cố gắng nhập: int array2 [] = & array1 [96].Lỗi mà tôi nhận được là: không thể chuyển đổi từ 'int *' sang 'int []' –

+0

@John: 'int array2 [] = & array1 [96];' là xấu. –

+0

Vâng, 'int foo []' và 'int * foo' chỉ có thể hoán đổi cho nhau như các tham số hàm. – jamesdlin

0
int array1[] = {1,2,3,...99,100}; 
int *array2 = &array1[96]; 
0
int arr[] = { 1, 2, 3, 4, 5}; 
int arr1[2]; 
copy(arr + 3, arr + 5, arr1); 
for(int i = 0; i < 2; i++) 
    cout << arr1[i] << endl; 

Mã này là không an toàn nếu ranh giới không được xử lý đúng cách.

8

Tham chiếu Hack từ một lập trình viên C sẵn sàng để lật đổ hệ thống kiểu để có được những gì hoạt động:

int (&array2)[5] = (int (&)[5])(*(array1 + 5)); 

Bây giờ array2 sẽ là một mảng cho tất cả các tính năng, và sẽ là một tiểu mảng của array1 và thậm chí sẽ có thể chuyển sang hàm mẫu C++ array_size nổi tiếng đó. Mặc dù cách tốt nhất để xử lý tin tặc này là giấu nó với nhiều tin tặc hơn!

#define make_sub_array(type, arr, off, len) (type (&)[len])(*(arr + off)); 

int (&array2)[5] = make_sub_array(int, array1, 5, 5); 

Tốt. Khủng khiếp bởi một số tiêu chuẩn, nhưng kết quả cuối cùng a) trông khá gọn gàng, b) thực hiện chính xác những gì bạn muốn, c) có chức năng giống với một mảng thực, và d) cũng sẽ có thêm tiền thưởng (hoặc tính năng sai) một tham chiếu giống hệt với bản gốc, do đó, cả hai thay đổi cùng nhau.

UPDATE: Nếu bạn thích, một phiên bản templated (loại):

template <typename T, size_t M> 
T (&_make_sub_array(T (&orig)[M], size_t o))[] 
{ 
    return (T (&)[])(*(orig + o)); 
} 
#define make_sub_array(type, array, n, o) (type (&)[n])_make_sub_array(array, o) 

int (&array2)[5] = make_sub_array(int, array1, 5, 5); 

Chúng ta vẫn phải vượt qua các loại. Vì một trong các đối số của chúng ta phải được sử dụng như một phần của diễn viên, chúng ta không thể xóa sạch (IMHO) tránh được macro. Chúng tôi có thể thực hiện việc này:

template <typename T, size_t M, size_t N> 
T (&make_sub_array(T (&orig)[M], size_t o))[N] 
{ 
    return (T (&)[N])(*(orig + o)); 
} 

int (&array2)[5] = make_sub_array<int, 15, 5>(array1, 5); 

Nhưng mục tiêu ở đây là làm cho mã gọi càng sạch càng tốt và cuộc gọi đó hơi khó khăn. Phiên bản tinh khiết-macro có thể có chi phí thấp nhất và có lẽ là phần mềm sạch nhất để triển khai trong trường hợp này.

+1

Thật tệ khi nó tốt :-). +1. –

+0

Cảm ơn. Tôi mất nhiều thời gian hơn vì tôi muốn làm cho nó hoạt động với việc truyền C++ thực tế, nhưng cuối cùng tôi đã từ bỏ và làm cho nó _work_. Cải tiến (đặc biệt là một phiên bản tiềm năng của 'make_sub_array' như là một chức năng mẫu - Tôi đã cố gắng trong một thời gian trước khi từ bỏ) chào mừng. –

+0

@ Chris: C++ của tôi - fu không phải là tuyệt vời, tôi nhiều hơn một người C, nhưng tôi sẽ cố gắng! –

3

Để có cách tiếp cận hoàn toàn khác, bạn có thể làm một việc gì đó tương tự.

vector<int> v0(array1 + 95, array1 + 100); 

hoặc

vector<int> v1(array1, array1 + 100); 
vector<int> v2(v1.begin() + 95, v1.end()); 

Điều này sẽ tạo một bản sao thực sự của các phần tử của vector của bạn.

+0

Nên là 'std :: vector 'cho mặt dây chuyền. Dù sao, +1 cho câu trả lời "C++" nhất. –

3

Bạn có thể sử dụng để đại diện cho boost::iterator_range "lát" của mảng/container:

#include <iostream> 
#include <boost/range.hpp> 

int main() 
{ 
    int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

    // Create a "proxy" of array[5..7] 
    // The range implements the concept of a random sequence containter 
    boost::iterator_range<int*> subarray(&array[5], &array[7]+1); 

    // Output: 3 elements: 5 6 7 
    std::cout << subarray.size() << " elements: " 
       << subarray[0] << " " 
       << subarray[1] << " " 
       << subarray[2] << "\n"; 
} 

Lưu ý rằng phạm vi iterator "biết" về kích thước của các tiểu mảng. Nó thậm chí sẽ làm giới hạn kiểm tra cho bạn. Bạn không thể nhận được chức năng đó từ một con trỏ đơn giản.

Tính hữu ích của Boost.Range sẽ trở nên rõ ràng hơn khi bạn tìm hiểu về các container STL và các trình vòng lặp.

Nếu bạn tham gia đại số tuyến tính, Boost.uBlas hỗ trợ các phạm vi và lát cho ma trận và vec-tơ của nó.

Các vấn đề liên quan