提问人:asimes 提问时间:10/21/2012 最后编辑:NathanOliverasimes 更新时间:10/25/2022 访问量:179577
从函数返回数组指针的 C++ 正确方法
C++ correct way to return pointer to array from function
问:
我对 C++ 相当陌生,并且一直在避免指针。从我在网上读到的内容来看,我无法返回数组,但我可以返回指向它的指针。我制作了一个小代码来测试它,并想知道这是否是正常/正确的方法:
#include <iostream>
using namespace std;
int* test (int in[5]) {
int* out = in;
return out;
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int* pArr = test(arr);
for (int i = 0; i < 5; i++) cout<<pArr[i]<<endl;
cout<<endl;
return 0;
}
编辑:这似乎不好。我应该如何重写它?
int* test (int a[5], int b[5]) {
int c[5];
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
int* out = c;
return out;
}
答:
您的代码是正确的,但我很难弄清楚它如何在现实世界中使用。话虽如此,在从函数返回指针时,请注意一些注意事项:
- 当您使用 语法 创建数组时,它会分配在堆栈上,并且是函数的本地数组。
int arr[5];
- C++ 允许您返回指向此数组的指针,但使用此指针指向的内存在其本地范围之外是未定义的行为。使用现实世界的类比阅读这个伟大的答案,以获得比我所能解释的更清晰的理解。
- 如果可以保证数组的内存未被清除,则仍然可以在作用域之外使用数组。在您的情况下,当您传递到 .
arr
test()
- 如果要传递指向动态分配数组的指针而不必担心内存泄漏,则应对 / 进行一些读取。
std::unique_ptr
std::shared_ptr<>
编辑 - 回答矩阵乘法的用例
您有两种选择。幼稚的方法是使用 /。现代 C++ 的方法是有一个重载的类,如果你想避免复制乘法的结果以将其从函数中取出,你绝对必须使用 new。除了有你的 、 和 之外,你还需要有 和 。通过此搜索的问题和答案,以更深入地了解如何实现这一目标。std::unique_ptr
std::shared_ptr<>
Matrix
operator *
rvalue references
copy constructor
operator =
destructor
move constructor
move assignment operator
编辑 2 - 对附加问题的回答
int* test (int a[5], int b[5]) {
int *c = new int[5];
for (int i = 0; i < 5; i++)
c[i] = a[i]+b[i];
return c;
}
如果您将此用作 ,则在代码的稍后某个时间,您应该调用以释放函数中分配的内存。您现在看到的问题是,手动跟踪何时调用 .因此,答案中概述了如何处理它的方法。int *res = test(a,b);
delete []res
test()
delete
评论
static int arr[5];
static int arr[5]
static
strtok
static char*
你的代码没问题。但请注意,如果返回指向数组的指针,并且该数组超出范围,则不应再使用该指针。例:
int* test (void)
{
int out[5];
return out;
}
以上方法永远不会起作用,因为返回时不再存在。返回的指针不能再使用。如果你确实使用它,你将读取/写入你不应该的内存。out
test()
在原始代码中,数组在返回时超出范围。显然这没问题,因为返回也意味着您的程序正在终止。arr
main()
main()
If you want something that will stick around and cannot go out of scope, you should allocate it with :new
int* test (void)
{
int* out = new int[5];
return out;
}
The returned pointer will always be valid. Remember do delete it again when you're done with it though, using :delete[]
int* array = test();
// ...
// Done with the array.
delete[] array;
Deleting it is the only way to reclaim the memory it uses.
评论
boolean matMult(int* A, int* B, int* C, size_t m, size_t n, size_t p);
A
m x n
B
m x p
C
n x p
new
在实际应用中,返回数组的方式是使用 out 参数调用的。当然,您实际上不必返回指向数组的指针,因为调用方已经拥有它,您只需要填充数组即可。传递另一个参数指定数组的大小也很常见,以免它溢出。
使用 out 参数的缺点是调用方可能不知道数组需要多大才能存储结果。在这种情况下,您可以返回 std::vector 或类似的数组类实例。
新问题的新答案:
不能从函数返回指向自动变量 () 的指针。自动变量以返回封闭块(在本例中为函数)结束其生存期 - 因此您将返回指向不存在的数组的指针。int c[5]
要么使变量动态化:
int* test (int a[5], int b[5]) {
int* c = new int[5];
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
return c;
}
或者将您的实现更改为使用:std::array
std::array<int,5> test (const std::array<int,5>& a, const std::array<int,5>& b)
{
std::array<int,5> c;
for (int i = 0; i < 5; i++) c[i] = a[i]+b[i];
return c;
}
如果你的编译器没有提供,你可以用包含数组的简单结构体来替换它:std::array
struct array_int_5 {
int data[5];
int& operator [](int i) { return data[i]; }
int operator const [](int i) { return data[i]; }
};
老问题的老答案:
您的代码是正确的,并且......嗯,嗯,......无用。由于数组可以在没有额外函数的情况下分配给指针(请注意,您已经在函数中使用它):
int arr[5] = {1, 2, 3, 4, 5};
//int* pArr = test(arr);
int* pArr = arr;
函数的 Morever 签名:
int* test (int in[5])
相当于:
int* test (int* in)
所以你看这没有意义。
但是,此签名采用数组,而不是指针:
int* test (int (&in)[5])
评论
int* arr3 = test(arr1, arr2)
delete[]
delete
引用数组的变量基本上是指向其第一个元素的指针,所以是的,您可以合法地返回指向数组的指针,因为 thery 本质上是一回事。自己检查一下:
#include <assert.h>
int main() {
int a[] = {1, 2, 3, 4, 5};
int* pArr = a;
int* pFirstElem = &(a[0]);
assert(a == pArr);
assert(a == pFirstElem);
return 0;
}
这也意味着将数组传递给函数应该通过指针(而不是通过)完成,并且可能与数组的长度一起完成:int in[5]
int* test(int* in, int len) {
int* out = in;
return out;
}
也就是说,你是对的,使用指针(没有完全理解它们)是非常危险的。例如,引用在堆栈上分配并超出范围的数组会产生未定义的行为:
#include <iostream>
using namespace std;
int main() {
int* pArr = 0;
{
int a[] = {1, 2, 3, 4, 5};
pArr = a; // or test(a) if you wish
}
// a[] went out of scope here, but pArr holds a pointer to it
// all bets are off, this can output "1", output 1st chapter
// of "Romeo and Juliet", crash the program or destroy the
// universe
cout << pArr[0] << endl; // WRONG!
return 0;
}
So if you don't feel competent enough, just use .std::vector
[answer to the updated question]
The correct way to write your function is either this:test
void test(int* a, int* b, int* c, int len) {
for (int i = 0; i < len; ++i) c[i] = a[i] + b[i];
}
...
int main() {
int a[5] = {...}, b[5] = {...}, c[5] = {};
test(a, b, c, 5);
// c now holds the result
}
Or this (using ):std::vector
#include <vector>
vector<int> test(const vector<int>& a, const vector<int>& b) {
vector<int> result(a.size());
for (int i = 0; i < a.size(); ++i) {
result[i] = a[i] + b[i];
}
return result; // copy will be elided
}
评论
new int
delete[] p
main
test
Your code (which looks ok) doesn't return a pointer to an array. It returns a pointer to the first element of an array.
In fact that's usually what you want to do. Most manipulation of arrays are done via pointers to individual elements, not via pointers to the array as a whole.
You can define a pointer to an array, for example this:
double (*p)[42];
defines as a pointer to a 42-element array of s. A big problem with that is that you have to specify the number of elements in the array as part of the type -- and that number has to be a compile-time constant. Most programs that deal with arrays need to deal with arrays of varying sizes; a given array's size won't vary after it's been created, but its initial size isn't necessarily known at compile time, and different array objects can have different sizes.p
double
A pointer to the first element of an array lets you use either pointer arithmetic or the indexing operator to traverse the elements of the array. But the pointer doesn't tell you how many elements the array has; you generally have to keep track of that yourself.[]
If a function needs to create an array and return a pointer to its first element, you have to manage the storage for that array yourself, in one of several ways. You can have the caller pass in a pointer to (the first element of) an array object, probably along with another argument specifying its size -- which means the caller has to know how big the array needs to be. Or the function can return a pointer to (the first element of) a static array defined inside the function -- which means the size of the array is fixed, and the same array will be clobbered by a second call to the function. Or the function can allocate the array on the heap -- which makes the caller responsible for deallocating it later.
Everything I've written so far is common to C and C++, and in fact it's much more in the style of C than C++. Section 6 of the comp.lang.c FAQ discusses the behavior of arrays and pointers in C.
But if you're writing in C++, you're probably better off using C++ idioms. For example, the C++ standard library provides a number of headers defining container classes such as and , which will take care of most of this stuff for you. Unless you have a particular reason to use raw arrays and pointers, you're probably better off just using C++ containers instead.<vector>
<array>
EDIT : I think you edited your question as I was typing this answer. The new code at the end of your question is, as you observer, no good; it returns a pointer to an object that ceases to exist as soon as the function returns. I think I've covered the alternatives.
you can (sort of) return an array
instead of
int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
int* m3 = test(m1, m2);
write
struct mystruct
{
int arr[5];
};
int m1[5] = {1, 2, 3, 4, 5};
int m2[5] = {6, 7, 8, 9, 10};
mystruct m3 = test(m1,m2);
where test looks like
struct mystruct test(int m1[5], int m2[5])
{
struct mystruct s;
for (int i = 0; i < 5; ++i ) s.arr[i]=m1[i]+m2[i];
return s;
}
not very efficient since one is copying it delivers a copy of the array
上一个:删除 C++ 中向量的常量限定符
下一个:光线追踪器的材质属性列表
评论
std::array
int* funct() { int arr[5]; return arr; }