调整通过引用传递的动态分配数组的大小

Resizing a dynamically allocated array passed by reference

本文关键字:动态分配 数组 引用 调整      更新时间:2023-10-16

我被困在这个问题:如何调整大小,在一个函数中,一个动态分配的数组,它已经通过引用传递给函数。我尝试了这个方法,以及无数的这种方法的变化。当然,这只是一个例子,它应该打印"john"10次,扩展一个数组,最初只有大小为1(即只有一个名字)的引用传递。

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
int NumLast=-1;

int Surname(string *MyData)
{
          for (int i=0; i<10 ; i++)
          {
            NumLast++;
            string *Temp = new string[NumLast+1];   // temporary array 
            for (int jjj=0; jjj<NumLast; jjj++)
                Temp[jjj]=MyData[jjj];
            delete[] MyData;
            MyData=Temp;
            MyData[NumLast]="John";
          }
          return 0;
}

void main()
{ 
     string *Data = new string[1]; // inizializza l'array 
     Surname(&*Data);
     for (int iii=0; iii<10; iii++)
              cout << Data[iii] << endl; 
     system("pause");
} 

您必须通过引用传递。你在传递价值。你得到

&*Data                                              = Data
The value of the address of what is pointed to Data = Data

然后按值传递给姓。Surname对它的任何影响都不会影响main中的Data

int Surname(string *MyData)  // This will take a copy of whatever you passed in to MyData

应该是(引用操作符应该在函数定义上)

int Surname(string*& MyData)
                  ^^

调用将是

void main()
{ 
     string *Data = new string[1];
     Surname(Data);  // The function will take a reference of data.

我可以问一下你为什么在循环中分配吗?

  1. 看起来std::vector是您的最佳解决方案。
  2. 如果你真的需要手动重新分配,考虑一下老派的malloc(), free(), realloc()接口。要记住的主要事情是不要将它与c++的new/delete接口混在一起,尽管new/delete通常是使用malloc()/free()实现的。如果你需要数组,你不应该传递数组,而是传递指针(或引用)到数组(双指针)。在std::vector的情况下,向它传递引用就足够了。
  3. 另一个使用std::vector引用的参数——在指针指向数组调用者的情况下,应该以某种方式通知新的数组大小。

我决定尝试逐行检查您的代码,并指出一些问题并强调正在发生的事情。我将从您的main函数开始:

void main()
{ 
    string *Data = new string[1]; // inizializza l'array 
    Surname(&*Data);
    for (int iii=0; iii<10; iii++)
        cout << Data[iii] << endl;
}

好的,这段代码所做的是分配一个字符串,并将指针保存在一个名为Data的变量中。

然后它解引用 Data,因此,返回一个string,然后获得该字符串的地址(即返回与Data相同的东西)。

换句话说,这段代码:

    Surname(&*Data);

的作用与下面的代码完全相同:

    Surname(Data);

那么,现在我们来看看Surname:

int Surname(string *MyData)
{
    for (int i=0; i<10 ; i++)
    {
        NumLast++;
        string *Temp = new string[NumLast+1];   // temporary array 
        for (int jjj=0; jjj<NumLast; jjj++)
            Temp[jjj]=MyData[jjj];
        delete[] MyData;
        MyData=Temp;
        MyData[NumLast]="John";
    }
    return 0;
}

这个奇怪的函数接受一个指向字符串的指针,并循环10次执行操作。让我们看看在循环的第一次迭代中发生了什么…

首先增加NumLast(从-1增加到0)。然后分配一个字符串数组,长度为NumLast + 1(即长度为1)。到目前为止一切顺利。

现在你可能认为函数会进入for循环。但它不会:记住,在这一点上,NumLastjjj都是0,因此,jjj < NumLast是假的。

代码将delete[] MyData(也就是说,它将删除MyData指向的任何内容),设置MyData指向在循环中早些时候分配的临时数组,然后设置第一个元素(索引0)为字符串"John"

在循环的第二次迭代中,该函数再次增加NumLast(现在为1),它将再次分配一个字符串数组,这次的长度为2

这次将进入循环。它将把MyData的第一个条目复制到Temp的第一个条目。它会退出

同样,MyData将被删除,指针将指向新分配的数组。

冲洗。泡沫。重复。

最后,函数将退出。我们返回到main,它现在将执行这段代码:

for (int iii=0; iii<10; iii++)
    cout << Data[iii] << endl;

请稍等。Data指向哪里?嗯…它指向很久以前就已经删除的数据。为什么?

好,Surname收到了Data指针的拷贝。当它调用delete[] MyData时,它删除了MyData所指向的数组(即Data所指向的数组)。当Surname之后执行MyData=Temp时,所有改变的都是MyData(指针local指向函数Surname的副本)和Data(指针在main中)不受影响,继续指向现在已删除的内存。

其他人已经解释了如何得到你想要的效果,我不会重复他们写的。但是我建议你坐下来想想Surname是做什么的,代码是如何不清楚和令人困惑的,以及如何重写它,以便更容易理解,更不容易出错。

对于那些将来需要解决同样问题的人来说,这里是修改后的代码:

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
int NumLast=-1;
int Surname(string *&MyData)
{       
     for (int i=0; i<10 ; i++)
     {
           NumLast++;
           string *Temp = new string[NumLast+1];   
           for (int jjj=0; jjj<NumLast; jjj++)
                Temp[jjj]=MyData[jjj];
           delete[] MyData;
           MyData=Temp;
           MyData[NumLast]="franci";
      }
      return 0;
}

void main()
{ 
      string *Data = new string[1]; // inizializza l'array 
      Surname(Data);  
      for (int iii=0; iii<10; iii++)
           cout << Data[iii] << endl;    
      system("pause");
}