在C ++中从现有数组创建子数组的最佳方法是什么?

时间:2010-01-26 03:25:41

标签: c++ pointers arrays

好的,我正在尝试从现有阵列中获取子阵列,我只是不确定如何做到这一点。在我的例子中,我有一个非常大的数组,但我想从数组的最后5个元素创建一个数组。

我所谈论的一个例子是:

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

我知道这是不正确的,但我在纠正它时遇到了一些麻烦。我想在array1中获取元素96到100并将它们放入array2但我不想复制数组。我只想让array2从96元素开始,这样array1 [96]和array2 [0]将指向同一个位置。

8 个答案:

答案 0 :(得分:18)

为此:

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

你可以这样做:

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

答案 1 :(得分:9)

来自C程序员的参考黑客,他们愿意破坏类型系统以使其起作用:

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

现在array2将是一个用于所有意图和目的的数组,并且将是array1的子数组,甚至可以传递给那个着名的C ++ array_size模板函数。虽然处理这个hackery的最好方法是隐藏它更多的hackery!

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

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

尼斯。一些标准可怕,但最终结果a)看起来非常整洁,b)完全符合你的要求,c)在功能上与实际数组完全相同,并且d)还将具有额外的奖励(或错误特征)与原作相同的参考,所以两者一起改变。

更新:如果您愿意,可以使用模板化版本(等等):

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

我们仍然要传递这种类型。由于我们的一个参数必须用作演员的一部分,我们不能干净地(恕我直言)避免宏。我们可以这样做:

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

但是这里的目标是使调用代码尽可能干净,并且调用有点毛茸茸。纯宏版本可能具有最小的开销,在这种情况下可能是最干净的。

答案 2 :(得分:3)

对于完全不同的方法,你可以做类似的事情。

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

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

这将成为载体元素的真实副本。

答案 3 :(得分:3)

您可以使用boost::iterator_range来表示数组/容器的“切片”:

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

请注意,迭代器范围“知道”子数组的大小。它甚至会为你检查边界。您无法通过简单的指针获得该功能。

一旦了解了STL容器和迭代器,Boost.Range的用处就会变得更加明显。

如果你是线性代数,Boost.uBlas支持其矩阵和向量的范围和切片。

答案 4 :(得分:1)

在C ++中你可以使用int指针作为int数组,所以让array2从array1中的item 96开始很容易,但是没有办法给array2一个大小限制,所以你可以这样做< / p>

<击>     int array2 [] =&amp; array1 [96];

或者这个

int *array2 = &array1[96];

但不是这个

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

另一方面,C ++不会强制执行数组大小限制,因此唯一真正的损失是你不能使用sizeof来获取array2中的元素数。

注意:&array1[96]array+96

相同

编辑:更正 - int array[] = &array[96]无效,在声明功能参数列表时,只能使用[]作为*的同义词。

所以这是允许的

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

答案 5 :(得分:0)

你说你不想复制数组,但得到一个指向最后五个元素的指针。你几乎拥有它:

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

答案 6 :(得分:0)

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

答案 7 :(得分: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;

如果边界处理不当,代码就不安全。