仅使用数组的一部分

17
我有一个动态分配的浮点数数组,我需要将该数组作为参数传递给三个不同的函数,但每个函数需要获取数组的不同范围。是否有一种方法可以将元素0到23的数组发送到一个函数,将元素24到38的数组发送到另一个函数,并将元素39到64的数组发送到第三个函数。
在某些语言中(如Python),您可以执行以下操作:
somefunction(my_array[0:23]);
somefunction(my_array[24:38]);
somefunction(my_array[39:64]);

然而我正在使用C++,并且不知道如何在C++中实现这一点。

有人知道怎么做吗?

somefunction(); 是来自API的一个函数,所以我不能修改它所接受的参数。


somefunction 如何知道数组的大小? - GManNickG
somefunction(); 是来自OpenGL的glTexCoordPointer();。 - PgrAm
еҰӮжһңжӮЁжӯЈеңЁдҪҝз”ЁglTexCoordPointer()пјҢеҸӘйңҖдј йҖ’my_array + nгҖӮ - sverre
@PgrAm:在看到你现在提到的glTexCoordPointer()后,我刚刚编辑了我的答案。如果你有任何其他绘制纹理后的代码,请将其添加到你的问题中。 - AusCBloke
7个回答

14

如果你编写的函数是操作一对前向迭代器而不是数组,那么你可以这样传递它:

somefunction1(my_array, my_array + 24);
somefunciton2(my_array + 24, my_array + 39);
somefunction3(my_array + 39, my_array + 65);

指针是前向迭代器,这使得函数能够在向量、队列或其他STL容器的部分上使用。


2
如果第二个参数表示传统的 end() 迭代器,那么你不是多了一个吗? - Robᵩ
@Rob:这种函数将第二个参数解释为“最后一个元素之后的位置”。这就是STL处理迭代器的方式。 - xtofl
2
@xtofl:是的,他的意思是偏移量为24、39、65,而不是23、38、64。 - AusCBloke
1
我不能这样做,因为我无法修改somefunction(); - PgrAm

8

这个Python示例正在进行拷贝。如果这符合您的使用情况,您可以像这样做(我将您的原始数组替换为std :: vector):

#include <iostream>
#include <vector>

void somefunction(std::vector<int> v) {
    std::cout << "vector has " << v.size() << " elements,"
        << " first value is " << *v.begin() << ","
        << " last value is " << *(v.end()-1) << std::endl;
}

int main() {
    std::vector<int> a;
    for (int i=0; i<65; i++) {
        a.push_back(i);
    }
    somefunction(std::vector<int>(a.begin(),a.begin()+23));
    somefunction(std::vector<int>(a.begin()+24,a.begin()+38));
    somefunction(std::vector<int>(a.begin()+39,a.begin()+65));
}

输出如下:

vector has 23 elements, first value is 0, last value is 22
vector has 15 elements, first value is 23, last value is 37
vector has 27 elements, first value is 38, last value is 64

但是看起来你不能使用std::vector,因为somefunction()的签名是不能改变的。幸运的是,你可以手动复制数组的部分内容来完成类似的操作,如下所示:

#include <iostream>
#include <string.h>

void somefunction(int v[], int len) {
    std::cout << "vector has " << len << " elements,"
        << " first value is " << v[0] << ","
        << " last value is " << v[len-1] << std::endl;
}

int main() {
    int a[65];
    for (int i=0; i<65; i++) {
        a[i] = i;
    }
    int b[23];
    memcpy(b, a, 23*sizeof(int));
    somefunction(b, 23);
    int c[15];
    memcpy(c, a+23, 15*sizeof(int));
    somefunction(c, 15);
    int d[27];
    memcpy(d, a+38, 27*sizeof(int));
    somefunction(d, 27);
}

再次输出如下:
vector has 23 elements, first value is 0, last value is 22
vector has 15 elements, first value is 23, last value is 37
vector has 27 elements, first value is 38, last value is 64

我认为Python示例并没有创建副本,而是返回了一个视图。你能提供一个参考吗? - Mayou36

7
您的函数无论如何都需要确定数组的大小。我建议您让函数采用类似标准库算法的begin和end迭代器的方式,像这样:
template<typename I>
void somefunction(I begin, I end);

然后,您可以像这样使用您的数组调用它:
somefunction(my_array, my_array + 24);
somefunction(my_array + 24, my_array + 39);
somefunction(my_array + 39, my_array + 65);

我不能这样做,因为我无法修改somefunction(); - PgrAm
@PgrAm:那么回答一下GMan在你的问题下面的评论,因为当你将一个数组传递给一个函数时,它会衰减为一个指针,并且大小会丢失。 - Benjamin Lindley
glTexCoordPointer(); 是来自OpenGL的somefunction();。 - PgrAm

5
有两种方法可以做到这一点:
void useArray(int array[], size_t len) { ... }
...
useArray(myArray, 24);
useArray(&myArray[24], 15);
useArray(&myArray[39], 26);

或者

void useArray(int *start, int *end) { ... }
...
useArray(myArray, myArray + 24);
useArray(myArray + 24, myArray + 39);
useArray(myArray + 39, myArray + 65);

第一个方法更像是C语言的写法,第二个方法更像是C++语言的写法。请注意,使用第二种方法时,范围为[start, end) - 就像你在很多C++代码中看到的一样,end不包括在范围内。
编辑:您编辑了您的帖子以提及您正在使用glTexCoordPointer()。在这种情况下,将数组的起始位置传递给glTexCoordPointer(),该位置将是myArraymyArray + 24myArray + 39
然而,数组的大小仍然需要知道,并且被传递到函数glDrawArraysglDrawElements()中,然后开始从数组中读取。如果您正在使用glDrawArrays(),则数组的长度作为第二个参数传递。因此,您的代码可能如下所示:
glTexCoordPointer(..., ..., ..., my_array);
...
glDrawArrays(..., 0, 24);

glTexCoordPointer(..., ..., ..., my_array + 24);
...
glDrawArrays(..., 0, 15);

glTexCoordPointer(..., ..., ..., my_array + 39);
...
glDrawArrays(..., 0, 26);

强调一下“更加符合C ++的方式”的+1。个人而言,我喜欢让第一个案例与后续案例保持一致:use(myarray + 0,myarray + 23) - xtofl
我不能这样做,因为我无法修改somefunction(); - PgrAm
@AusCBloke glTexCoordPointer(..., ..., ..., my_array + 24); 看起来只是旋转纹理,没有其他作用。 - PgrAm
@PgrAm:我对OpenGL的东西不太确定,但是传递my_array + 24会让它看起来像是数组的开头。 - AusCBloke

0

没有上限范围检查,所以你必须自己注意。但是你可以将&my_array[0]传递给一个函数,将&my_array[24]传递给另一个函数。也许在你的函数中添加一个len参数来处理上限范围。


0
我会返回或者做类似于std::pair<pointer_type, pointer_type>的东西,其中包含{Begin_Pointer, End_Pointer}。因此,如果我们需要在特定部分/块中切割原始数组(在C/C++领域中只是一个指针),我会返回类似于这样的东西。
pointer_type element_begin = raw_array+begin;
pointer_type element_end = raw_array+end;
std::pair<pointer_type, pointer_type> = std::make_pair(element_begin, element_end);

我将拥有一个方便的函数,我可以给它传入那些非负的beginend值,它将返回一个std::pair


0
你可以重构你的函数,使用“迭代器”来指向你感兴趣的数组范围的开头和结尾:
 void somefunction( int* begin, int* end ) {
    for( int* i=begin; i != end; ++i ) {
       //stuff with *i
    }
 }


 // usage:
 somefunction( my_array+0, my_array+23 );
 somefunction( my_array+24, my_array+38 );
 somefunction( my_array+39, my_array+64 );

加分项:如果你将函数设为模板,你就可以将它用于其他迭代器:

 template<typename T>
 void somefunction( T begin, T end ) {
    for( T i=begin; i != end; ++i ) {
       //stuff with *i
    }
 }

 vector<int> values(100);
 somefunction( values.begin(), values.end() );
 somefunction( values.rbegin(), values.rend() );

...


1
我不能这样做,因为我无法修改somefunction();。 - PgrAm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接