返回指向动态分配数组的指针,该数组具有 normal 函数和 void C++函数

Returning a pointer to dynamically allocated array with normal function and void function in C++

本文关键字:数组 函数 normal C++ void 动态分配 返回 指针      更新时间:2023-10-16

我对C++很陌生,来自Fortran 90+和MATLAB背景。我一直在玩C++指针,我偶然发现了一些我无法完全解释的东西。在Google和Stack Overflow上搜索并没有真正产生解释。

这是我想出的一个任意例子,只是从乱七八糟,试图理解C++是如何工作的。

本质上,我试图做的是在函数中分配一个动态数组,填充数组,并在调用函数中返回指向数组的指针。如果我使用 void 函数返回指向数组的指针,它不起作用。如果我将其作为带有返回的正常函数来执行,它就可以正常工作。让我们分别称这些情况 1 和案例 2。

举了一个例子来说明我的意思:

#include <iostream>
using namespace std;
// Prototypes
void populate(int rows, int cols, double* ptr_to_mat);
double* populate_return(const int rows, const int cols);
// Main function
int main()
{
  int rows, cols;
  cout << "Number of rows:    ";
  cin >> rows;
  cout << "Number of columns: ";
  cin >> cols;
  cout << endl;
  double* ptr_to_mat;
  populate(rows, cols, ptr_to_mat);
  cout << endl << "OUTPUT IN main FROM populate" << endl;
  for (int r = 0; r <= rows-1; r++)
    for (int c = 0; c <= cols-1; c++)
      cout << "mat(" << r << "," << c << ") = " << ptr_to_mat[c+cols*r] << endl;
  cout << endl << endl;
  ptr_to_mat = populate_return(rows, cols);
  cout << endl << "OUTPUT IN main FROM populate_return" << endl;
  for (int r = 0; r <= rows-1; r++)
    for (int c = 0; c <= cols-1; c++)
      cout << "mat(" << r << "," << c << ") = " << ptr_to_mat[c+cols*r] << endl;

  delete [] ptr_to_mat;
  return 0;
}
// Other functions
// Return pointer by modifying argument -- CASE 1
void populate(const int rows, const int cols, double* ptr_to_mat)
{
  double* internal_mat = new double[rows*cols];
  cout << "INPUT IN populate" << endl;
  for (int r = 0; r <= rows - 1; r++)
    for (int c = 0; c <= cols - 1; c++)
      {
        cout << "mat(" << r << "," << c << ") = "; 
        cin >> internal_mat[c+cols*r];
      }
  ptr_to_mat = internal_mat;
  cout << endl << "OUTPUT IN populate" << endl;
  for (int r = 0; r <= rows-1; r++)
    for (int c = 0; c <= cols-1; c++)
      cout << "mat(" << r << "," << c << ") = " << ptr_to_mat[c+cols*r] << endl;
}
// Return pointer using "return" -- CASE 2
double* populate_return(const int rows, const int cols)
{
  double* internal_mat = new double[rows*cols];
  cout << "INPUT IN populate_return" << endl;
  for (int r = 0; r <= rows - 1; r++)
    for (int c = 0; c <= cols - 1; c++)
      {
        cout << "mat(" << r << "," << c << ") = "; 
        cin >> internal_mat[c+cols*r];
      }
  cout << endl << "OUTPUT IN populate_return" << endl;
  for (int r = 0; r <= rows-1; r++)
    for (int c = 0; c <= cols-1; c++)
      cout << "mat(" << r << "," << c << ") = " << internal_mat[c+cols*r] << endl;
  return internal_mat;
}

运行上述代码的结果如下:

Number of rows:    3
Number of columns: 2
CASE 1
INPUT IN populate
mat(0,0) = 1
mat(0,1) = 2
mat(1,0) = 3
mat(1,1) = 4
mat(2,0) = 5
mat(2,1) = 6
OUTPUT IN populate
mat(0,0) = 1
mat(0,1) = 2
mat(1,0) = 3
mat(1,1) = 4
mat(2,0) = 5
mat(2,1) = 6
OUTPUT IN main FROM populate
mat(0,0) = -1.72952e-41
mat(0,1) = -2.77962e-42
mat(1,0) = -2.77966e-42
mat(1,1) = -2.7797e-42
mat(2,0) = -6.02988e-42
mat(2,1) = -2.77979e-42

CASE 2
INPUT IN populate_return
mat(0,0) = 1
mat(0,1) = 2
mat(1,0) = 3
mat(1,1) = 4
mat(2,0) = 5
mat(2,1) = 6
OUTPUT IN populate_return
mat(0,0) = 1
mat(0,1) = 2
mat(1,0) = 3
mat(1,1) = 4
mat(2,0) = 5
mat(2,1) = 6
OUTPUT IN main FROM populate_return
mat(0,0) = 1
mat(0,1) = 2
mat(1,0) = 3
mat(1,1) = 4
mat(2,0) = 5
mat(2,1) = 6

我的假设是,这与在调用函数中分配指针的时间有关。因此,在情况 2 中,在从内存中释放函数中的信息之前,它被分配给左侧,而在情况 1 中,该内存在调用函数中分配指针之前被释放,因为分配发生在右侧。

这听起来有道理吗?如果不是,案例 2 有效但案例 1 无效的原因是什么?

如果我想在一个函数中分配多个动态数组并返回指向这些数组的指针,我必须使用 void 函数。在这种情况下可以/应该做什么?

void版本不起作用的原因是指针参数是按值传递的,因此该函数有自己的副本。要使其"工作",您必须传递对指针的引用:

void populate(int rows, int cols, double*& ptr_to_mat);
//                                       ^

请注意,在实际代码中,您倾向于使用 std::vector 或某种其他类型的方法来管理自己的资源,而不是将资源管理留给调用方。例如

#include <vector>
std::vector<double> populate(int rows, int cols);

在 c++ 中,参数是按值传递的,因此在第一个实例中,您正在修改结果指针的副本。使用指向指针的指针,并通过引用它来设置结果。

或者正如更好的答案所建议的那样:使用参考。这不是c!

要在void函数中正确设置指针,您需要通过引用传递它:

void populate(const int rows, const int cols, double*& ptr_to_mat) { // ...