2012-01-02 2 views
1

Я привык писать программы в Fortran (это f90), но мне нужно написать программу на C++. Я очень смущен тем, как передать многомерный массив из C++-функции. Чтобы привести пример, я хочу прочитать список атомных координат в формате XYZ в подпрограмме, а затем передать координаты основной программе.передать многомерный массив в C++ для fortran-программиста

Здесь в Fortran:

program findcenterofmass 
character*2 atm(1000) 
integer ttl 
real*8 crd(1000,3) 

call getxyz(atm,ttl,crd) 
call centerofmass(ttl,crd) 
end 

subroutine getxyz(element,atomcount,coord) 
character*2 element(1000) 
integer atomcount 
real*8 coord(1000,3) 
open(file='test.xyz',unit=1) 
read(1,*) atomcount 
read(1,*) 
do i=1,atomcount 
    read(1,*) element(i),(coord(i,j),j=1,3) 
enddo 
close(unit=1) 
end 

subroutine centerofmass(atomcount,coord) 
integer atomcount 
real*8 coord(1000,3) 
real*8 x,y,z 
do i=1,atomcount 
    x=x+coord(i,1)/atomcount 
    y=y+coord(i,2)/atomcount 
    z=z+coord(i,3)/atomcount 
enddo 
write(*,*) 'Center of mass is x: ',x,' y:',y,' z:',z 
end 

Файл теста читайте здесь очень простая молекула CO2:

3 

C 0.0 0.0 0.0 
O -1.4 0.0 0.0 
O 1.4 0.0 0.0 

Так что мне нужно сделать такую ​​же процедуру в C++ и часть, кажется Наиболее запутанным является чтение координат в многомерный массив , а затем передача массива обратно в основную программу.

Это C++ (у этого есть ошибки) - Любая помощь будет принята с благодарностью!

#include <stdio.h> 
#include <iostream> 
#include <string> 
#include <sstream> 

void readxyz(double& x); 

int main() { 

double x[100][3]; 
readxyz(double& x); 
std::cout << " x " << x[0][0] << "\n"; 
return 0; 
} 

void readxyz(double& coord[][3]) 
{ 
    int i,j,k; 
    int ttl; 
    int MAXATOM=1000; 
    int MAXLINE=72; 
    char atoms[MAXATOM][2]; 
    long double coord[MAXATOM][3]; 
    char s[MAXLINE]; 
    const char* filename="test.xyz"; 

    using namespace std; 
    cout.precision(12); 

    FILE *fp = fopen(filename,"r"); 

    fgets(s,MAXLINE,fp); 
    std::stringstream stream(s); 
    stream >> ttl; 

    fgets(s,MAXLINE,fp); 

    for (i = 0; i < ttl; i++) { 
    fgets(s,MAXLINE,fp); 
    std::stringstream stream(s); 
    stream >> atoms[i] >> coord[i][0] >> coord[i][1] >> coord[i][2]; 
    } 
} 
+0

@ Anicorn: not _really_ Соответствующий, поскольку Fortran в этом случае является программой, которую пользователь11255566 хочет переписать на C++ ... – sarnold

+0

my плохой думал, что он хочет передать массив между c и f90 – Anycorn

+0

[FAQ] (http: // stackoverflow.com/questions/4810664 /) – fredoverflow

ответ

0

Обратите внимание, что char atoms[MAXATOM][2]; но вы не даете достаточно индексов при записи в atoms в цикле: stream >> atoms[i] //...

0

double& coord[][3] является двумерный массив ссылок, с одной фиксированной размерности и одной неопределенной размерности, если он даже компилируется. Не может быть того, чего вы хотите. Вызываемая функция будет не сможет определить размер неизвестного размера во время выполнения.

Когда вы передаете многомерный массив в C++, под капотом все, что передается, является указателем на первый элемент. Так, везде работать с произвольными размерами, необходимо передать указатель, и любые размеры как дополнительные параметры:

void readxyz(double* coord, size_t numCoords, size_t numAxes) 
{ // ... access array data with: 
    coord[coordIndex * numAxes + axisIndex] 

    // ... or somewhat optimized in loops: 
    for(int coordIndex = 0; coordIndex < numCoords; ++coordIndex) { 
     double* thisCoord = coord + coordIndex * numAxes; 
     cout << "("; 
     for(int axisIndex = 0; axisIndex < numAxes; ++axisIndex) { 
      if(axisIndex) 
       cout << ", "; 
      cout << thisCoord[axisIndex]; 
     } 
     cout << ")" << endl; 
    } 
} 

Вы не пошли в подробности относительно того, что вы будете делать с информацией после того как вы «Я прочитал его, поэтому я не знаю, должны ли данные храниться в виде многомерного массива для дальнейшей обработки. Лично я хотел бы сохранить это как вектор Atom объектов, и просто использовать C++ I/O вместо смешивания C (функции, начиная с f) и C++ (классы заканчивая stream):

#include <iostream> 
#include <iomanip> 
#include <fstream> 
#include <vector> 

struct Atom 
// Defined as a `struct` to keep it as a simple "plain old data" (POD) type. 
// It doesn't have to be this way. 
{ // Store atom names as C strings; they can have up to 3 characters. 
    // Possible optimization: store the atomic number (one byte) instead 
    // and use a lookup table (or std::map) to get names. 
    char name[4]; 
    double x, y, z; 
}; 

typedef std::vector<Atom> Atoms; 

std::istream& operator >>(std::istream& is, Atom& a) 
{ // Always use setw() with char* to avoid buffer overflow. 
    is >> std::setw(4) >> a.name >> a.x >> a.y >> a.z; 
    return is; 
} 

void ReadAtoms(const char* filename, Atoms& atoms) 
{ std::ifstream ifs(filename); 
    size_t numAtoms; 
    ifs >> numAtoms; 

    for(size_t i = 0; i < numAtoms; i++) 
    { Atom atom; 
     ifs >> atom; 
     atoms.push_back(atom); 
    } 
} 

int main(int argc, char* argv[]) 
{ if(argc != 2) 
    { std::cerr << "Usage: " << argv[0] << " <filename>" << '\n'; 
     return 1; 
    } 

    Atoms atoms; 
    ReadAtoms(argv[1], atoms); 
    std::cout << " x " << atoms[0].x << '\n'; 
    return 0; 
} 

Это Безразлично» t обрабатывает поврежденные данные во входном файле, но это отправная точка.

+0

В C++ нет массивов ссылок. – fredoverflow

0

Является ли намерение прочитать фактическую длину массива из файла? Я предполагаю, что из Fortran:

read(1,*) atomcount 
do i=1,atomcount 
    read(1,*) element(i),(coord(i,j),j=1,3) 
enddo 

Если это так, было бы лучше, чтобы сделать переменную длину массива, вместо того, чтобы гадать максимальную длину (1000). Что произойдет, если ваша догадка слишком мала? Это легко сделать в Fortran> = 90 или C++. В Fortran сделать массивы «allocatable» и выделить их после чтения размером atomcount из файла. Также нет необходимости явно передавать размеры массива между различными процедурами ...

+0

Вы правы, он читает длину из файла. Пока размер атома меньше максимального размера, программа работает нормально. Вам просто нужно вручную изменить размер памяти для более крупных систем и перекомпилировать (старый стиль F77!). Я не хотел пытаться сделать массив переменных размера, пока не понял, как передавать массивы в C++. Мне просто нелегко обернуть голову вокруг передачи многомерных массивов в C++ и fortran. – user1125566

Смежные вопросы