如何处理变化的数组大小作为函数的参数?

时间:2019-04-28 06:14:53

标签: c++ fortran

我设法将5000多个Fortran 77程序的行代码手动转换为C ++,但是转换没有按计划进行。因此,我尝试使用我的Fortran 77程序调试C ++程序。在fortran中,我开发了一个子例程,该例程接受一个数组,并将数组索引及其值打印到以逗号分隔的文件中。我正在尝试在C ++中做类似的事情。但会违反“ double temp1 [tempi]”声明。在对函数的所有调用中,数组的大小不必相同。因此,我无法将其编码为“ double temp1 [21]”,因为下一次是25。Fortran通过引用传递数组。你建议我做什么。

我设法实现了Fortran程序。这样做的目的是从c ++程序中获取变量内存转储,并使用vba比较Excel中的值,以查看哪个变化最大,然后从C ++程序中着眼于该变量,这是调试的起点。

c ++代码逻辑:

 void singlearrayd(double temp1[tempi], int tempi, string str1){
   for (int md_i = 1; md_i <= tempi; md_i++){
   cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
   }
 }

 int main(){
   double askin[22];
   double fm[26];
   singlearrayd(askin,22,"askin");
   singlearrayd(fm,26,"fm");
   return 0;
 }

Fortran 77代码逻辑:

 PROGRAM PRINT_MEMORY
 real*8 :: ASKIN(21)
 real*8 :: FM(25)
 CALL SINGLEARRAYD(ASKIN,21,"ASKIN")
 CALL SINGLEARRAYD(FM,25,"FM")
 END PRINT_MEMORY

 SUBROUTINE SINGLEARRAYD(TEMP1,TEMPI,STR1)
 IMPLICIT NONE
 CHARACTER(LEN=*) :: STR1
 INTEGER*4 MD_I,TEMPI
 REAL*8, DIMENSION(1:TEMPI) :: TEMP1
 DO MD_I = 1, TEMPI
 WRITE(51,'(ES25.16E3,A1,A25,A1,I5,A1)') TEMP1(MD_I),',',STR1,'(',
1 MD_I,')'
 ENDDO
 ENDSUBROUTINE SINGLEARRAYD

3 个答案:

答案 0 :(得分:4)

您的代码中存在多个问题。

在C ++中,本机数组(如askin中的main())在传递给函数时会转换为指针。因此,无需在参数列表中的数组上声明维,但仍然需要传递第二个参数,因为您要指定大小。

这意味着C ++函数应具有以下形式

void singlearrayd(double temp1[], int tempi, std::string str1)

或(等效)

void singlearrayd(double *temp1, int tempi, std::string str1)

在上面请注意,我已将第三个参数的类型全名指定为std::string。在很多情况下,最好避免使用using namespace std

第二个问题是您假设Fortran数组索引和C ++数组索引相同。实际上,Fortran数组索引是基于1的(默认情况下,数组的第一个元素的索引为1),而C ++数组索引是基于0的(数组的第一个元素的索引为零)。在C ++中使用Fortran数组索引会导致不确定的行为,因为它将访问有效范围之外的元素。

第三个(潜在)问题是您的函数定义了两个名为md_i的变量(一个在函数中,一个在循环内)。最好避免这样做。

解决以上所有问题将使您的功能变为(完整)

void singlearrayd(double temp1[], int tempi, std::string str1)
{
    for (int md_i = 0; md_i < tempi; ++md_i)    // note the differences here carefully
    {
        cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
    }
 }

第四个问题是C ++中的main()返回int,而不是void

第五个问题是main()singlearrayd()打印它们之前没有初始化数组。在Fortran中,函数本地的数组(通常)是零初始化的。在C ++中,默认情况下未对它们进行初始化,因此访问它们的值(例如打印它们)会产生不确定的行为。

int main()
{
   double askin[21] = {0.0};   // initialise the first element.  Other elements are initialised to zero
   double fm[21] = {0.0};
   singlearrayd(askin,21,"askin");
   singlearrayd(fm,25,"fm");
}

这将使您的代码正常工作。但是实际上,有可能进行改进。第一个改进是使用标准容器而不是数组。标准容器知道它们的大小,因此可以简化您的功能。其次,通过引用传递非平凡的参数(例如容器或字符串)-如果对参数不做任何更改,最好使用const引用。与Fortran不同,在Fortran中,函数参数通常通过引用按DEFAULT传递,因此有必要在C ++中有意地引入引用。

#include <vector>

void singlearrayd(const std::vector<double> &temp1, const std::string &str1)
{
    for (std::size_t md_i = 0; md_i < temp1.size(); ++md_i)
   {
        cout << temp1[md_i] << "," << str1 << "(" << md_i << ")";
   }
}

int main()
{
   std::vector<double> askin(21);   // askin has 21 elements, initialised to zero
   std::vector<double> fm(21);
   singlearrayd(askin, "askin");
   singlearrayd(fm, "fm");
}

C ++容器还支持迭代器-与使用数组索引相比,迭代器在实践中更安全,而且通常效率更高。我将其作为练习来学习如何使用它们。

但是要注意的一个关键信息是:不要认为从Fortran到C ++的简单机械翻译就行。您已经证明了这种假设的陷阱。在尝试将太多代码从Fortran转换为C ++之前,请花一些时间学习C ++。这对于使C ++代码正确运行以及使其高效运行都是必需的。

答案 1 :(得分:2)

一个更现代的实现是

 #include <string>
 #include <array>
 #include <iostream>

 template <std::size_t size, class U>
 void singlearrayd(const std::array<U, size>& temp1, const std::string& str1){
   int i = 0;
   for (const auto& x : temp1)
      std::cout << x << "," << str1 << "(" << (i++) << ")";
   }

 int main(){
   std::array<double, 21> askin;
   std::array<double, 21> fm; 
   singlearrayd(askin, "askin");
   singlearrayd(fm, "fm");

   return 0;
 }

请注意,在上面的代码中,两个数组askinfm未初始化。大概在实际代码中,您将在调用singlarrayd之前已经对其进行了初始化。 另外,请记住main必须返回int

答案 2 :(得分:0)

感谢您的宝贵见解和评论。我认为最好的方法是使用

    void singlearrayd(double *temp1, int tempi, std::string str1)

扩展了这个想法并使用Google进行了更多研究,我能够将这个想法扩展到处理2D和3D数组。

    void doublearrayd(double *temp1, int tempi, int tempj, std::string str1){
        for (int md_j = 1; md_j<tempj; md_j++){
            for (int md_i = 1; md_i<tempi; md_i++){
                std::cout << *(temp1 + md_i*tempj + md_j) << "," << str1 << "(" << md_i << ";" << md_j << ")" << std::endl;
            }
        }
    }

    void triplearrayd(double *temp1, int tempi, int tempj, int tempk, std::string str1){
        for (int md_k = 1; md_k < tempk; md_k++){
            for (int md_j = 1; md_j<tempj; md_j++){
                for (int md_i = 1; md_i<tempi; md_i++){
                    std::cout << *(temp1 + md_i*tempj*tempk + md_j*tempk + md_k) << "," << str1 << "(" << md_i << ";" << md_j << ";" << md_k << ")" << std::endl;
                }
            }
        }
    }

https://en.wikipedia.org/wiki/Row-_and_column-major_order

How can I pass a dynamic multidimensional array to a function?