C++ odczyt z pliku

0

Mam problem z odczytem z pliku, który umieściłem w załączniku. Z pliku wycinam 3 współrzędne i umieszczam je w tablicy dwuwymiarowej. Kiedy umieszczam je zgodnie z nrlinii, tj. od indeksu nr 2 wszystko działa. Chcę jednak, aby dane z pliku były umieszczone w tablicy od indeksu nr 0. Program kompiluje się, ale po chwili automatycznie przestaje działać.

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <cstring>

using namespace std;

void readPDB(double r[][3]) 
{
 
    fstream plik;
    int nrlinii = 1, liczbaatomow;
 	string str, nazwapliku;
 
	cout << "Podaj nazwe pliku PDB z polozeniami atomow wraz z rozszerzeniem: " << endl;
	cin >> nazwapliku;
	cout << "Podaj liczbe atomow: " << endl;
 	cin >> liczbaatomow;
	 
	plik.open(nazwapliku.c_str(), ios::in);
	if(plik == NULL)
		perror ("NIE MOGE OTWORZYC PLIKU, BY POBRAC DANE!"); 
	 
 	while(getline(plik, str))
	{
		string x, y, z;
		if(nrlinii!=1 && nrlinii!=(liczbaatomow+2))
    	{
    		x=str.substr(31, 7);
    		y=str.substr(39, 7);
    		z=str.substr(47, 7);
    		
    		const char* tempX = x.c_str();
        	double xd = atof(tempX);
	 
	        const char* tempY = y.c_str();
	        double yd = atof(tempY);
 
	        const char* tempZ = z.c_str();
	        double zd = atof(tempZ);
 			
 			int nr=nrlinii-2;
 			
	        r[nr][0] = xd;
	        r[nr][1] = yd;
	        r[nr][2] = zd;
		}	
    		
        nrlinii++;
    }
 	
    plik.close();
}

int main()
{
	double r[][3]={};

	readPDB(r); //wczytanie pliku pdb
	
	for(int i=0;i<10;i++)
		cout << r[i][0] << " " << r[i][1] << " " << r[i][2] << endl;
	
	return 0;
}
0

Źle inicjalizujesz tablicę dwuwymiarową. Jeśli chcesz ją mieć na stosie, to dla tablicy 3x2 robisz to tak:

double foo[3][2] = {{0, 0}, {0, 0}, {0, 0}};

Analogicznie musisz zrobić dla swojej 10x3. Dodatkowo deklaracja funkcji do której ją przekazujesz powinna wyglądać tak:

// void read_1(double r[][]); edit niepoprawny sposób, mój błąd
// albo
void read_2(double **r);
// albo
void read_3(double *r[]);
0

Program ma działać dla pliku z 10 lub 100 atomami (nie wrzucam, bo wygląda analogicznie do pliku z 10). Zmieniłem deklarację funkcji na sposób nr 1 z Twojego postu i program przestał się kompilować - "expected primary expression before ']' token" (linie 68, 86). Oczywiście nawiasu nigdzie nie brakuje. Jak pozostanę przy pierwotnym sposobie deklaracji to po kompilacji w konsoli wyświetla się wyjątek: "terminate called after throwing an instance of std out_of_range".

int main()
{
	int N;
	
	cout << "Podaj liczbe atomow: " << endl;
 	cin >> N;
 	
 	if(N==10)
 	{
 		double r[10][3]={{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}};
 		
 		readPDB(r[][]);
 		
 		for(int i=0;i<10;i++)
			cout << r[i][0] << " " << r[i][1] << " " << r[i][2] << endl;
	}		
	else if(N==100)
	{
		double r[100][3]={{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, 
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, 
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0},
						{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}};
						
		readPDB(r[][]); //wczytanie pliku pdb		
		
		for(int i=0;i<10;i++)
			cout << r[i][0] << " " << r[i][1] << " " << r[i][2] << endl;
	}	
	
	return 0;
}
several napisał(a):

Źle inicjalizujesz tablicę dwuwymiarową. Jeśli chcesz ją mieć na stosie, to dla tablicy 3x2 robisz to tak:

double foo[3][2] = {{0, 0}, {0, 0}, {0, 0}};

Analogicznie musisz zrobić dla swojej 10x3. Dodatkowo deklaracja funkcji do której ją przekazujesz powinna wyglądać tak:

void read_1(double r[][]);
// albo
void read_2(double **r);
// albo
void read_3(double *r[]);
0

Pierwszy błąd tutaj:

double r[][3]={}; // Jaki rozmiar ma ta tablica?

Kolejny tutaj:

if(nrlinii!=1 && nrlinii != (liczbaatomow+2))
  1. W drugim przypadku chyba powinno być <, bo tak jak jest teraz, to będzie czytał do końca pliku.
  2. Zdecyduj się w jakim języku piszesz. W C++ nie zaleca się używać słowa NULL.
  3. Do sprawdzenia stanu pliku można użyć: good(), is_open()
  4. Zamiast atof(), użyj stod().
  5. Te zmienne const char *temp, są tam zupełnie zbędne, zresztą podobnie zmienne xd, yd, zd.
  6. Po co wprowadzasz komplikacje z numerami linii itd? Otwórz plik, przeczytaj pierwszą z linii (Możesz sprawdzić, co zawiera), i potem już w pętli odczytujesz tyle linii, ile Ci potrzeba.
  7. Zamiast dwuwymiarowej tablicy, użyj std::vector<T>, który przechowywać będzie np. struktury (x, y, z).
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <vector>

using namespace std;

struct Data {
  double x;
  double y;
  double z;
};

void readPDB(std::vector<Data> &results) {
    fstream plik;
    int liczbaatomow = 0;
    string line, nazwapliku;

    cout << "Podaj nazwe pliku PDB z polozeniami atomow wraz z rozszerzeniem: " << endl;
    cin >> nazwapliku;
    cout << "Podaj liczbe atomow: " << endl;
    cin >> liczbaatomow;

    Data data;
    plik.open(nazwapliku.c_str(), ios::in);
    if(plik.is_open()) {
      getline(plik, line);
      while (getline(plik, line) && liczbaatomow--) {
        data.x = stod(line.substr(31, 7));
        data.y = stod(line.substr(39, 7));
        data.z = stod(line.substr(47, 7));

        results.push_back(data);
      }
      plik.close();
    } else {
      cerr << "NIE MOGE OTWORZYC PLIKU, BY POBRAC DANE!";
    }
}

int main() {
    std::vector<Data> results;

    readPDB(results); //wczytanie pliku pdb

    for (const Data& res : results) {
      cout << res.x << " " << res.y << " " << res.z << std::endl;
    }

    return 0;
}
0

Tak jak napisał Sparrow-hawk był błędny warunek w if-ie. Po zmienieniu go program kompiluje się i działa, ale zapisywane są nieprawidłowe wartości do tablicy.

int main()
{
	int N;
	
	cout << "Podaj liczbe atomow: " << endl;
 	cin >> N;
 	
 	double r[N][3];
 		
 	readPDB(r);
 		
 	for(int i=0;i<N;i++)
		cout << r[i][0] << " " << r[i][1] << " " << r[i][2] << endl;

	return 0;
}
0

Język C++ nie obsługuje tablic VLA. Jeśli chcesz stworzyć dynamicznie tablicę (I zapewne nie możesz korzystać z inteligentnych pointerów), to zrób to tak:

#include <iostream>

using namespace std;

int main()
{
    size_t N;

    cout << "Podaj liczbe atomow: " << endl;
    cin >> N;
    
    double** r = new double*[N];
	for(size_t i = 0; i < N; ++i)
    	r[i] = new double[3];

    for(int i=0;i<N;i++)
        cout << r[i][0] << " " << r[i][1] << " " << r[i][2] << endl;
        
    for (size_t i = 0; i < N; ++i)
    	delete [] r[i];
    delete[] r;

    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1