在C ++中返回带有正常函数和void函数的动态分配数组的指针

时间:2014-04-05 21:12:34

标签: c++ arrays pointers memory-management

我是C ++的新手,来自Fortran 90+和MATLAB背景。我一直在玩C ++中的指针,我偶然发现了一些我无法解释的内容。对谷歌和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函数。在那种情况下可以/应该做什么?

3 个答案:

答案 0 :(得分:4)

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

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

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

#include <vector>

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

答案 1 :(得分:0)

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

或者作为更好的答案建议:使用参考。这不是c!

答案 2 :(得分:0)

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

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