C++ - problem` z zapisem do pliku funkcją write()

0

Witam.
Mój program jest bardzo prosty. Służy ćwiczeniu, więc niektóre rzeczy można by napisać dużo prościej, ale nie o to tu chodzi. Dla jasności wkleję polecenie:

Napisz program, który jest 200 elementowa tablica obiektów typu double. Poszczególne elementy tej tablicy są wielokrotnością liczby 0,01. Tzn.: 0,01, 0,02, 0,03. Następnie niech program zapisze do pliku binarnego (funkcją write) wartości z tej 200 elementowej tablicy, a tablicę wyzeruje. Następnie niech program zapyta użytkownika o numer elementu tablicy, który chciałby poznać. jeśli użytkownik odpowie, że na przykład 173, pozycjonuj odpowiednio wskaźnik do czytania, przeczytaj tę liczbę, wstaw do tablicy we właściwe miejsce i pokaż tę liczbę na ekranie po to, by się przekonać, czy operacja Ci się udała. (Powinieneś wtedy zobaczyć wartość 1,73)

Jak już mówiłem, program krótki i raczej prosty. Oto mój kod:

 #include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main()
{
    const int rozmiar = 200;
    double liczby[rozmiar];
    for(int i = 0; i < rozmiar; i++) liczby[i] = (0.01 * i);

    ofstream plik("liczby.txt", ios::out | ios::binary);

    for(int i = 0; i < rozmiar; i++)
    {
        string tymczasowy;
        ostringstream strumien(tymczasowy);
        strumien << liczby[i];
        string wypis = strumien.str();
        //cout << wypis << endl; Dzięki tej instrukcji przekonałem się, że problem tkwi w funkcji write().
        plik.write(wypis.c_str(), sizeof(double));
        liczby[i] = 0; // ZEROWANIE
    }

    //////// ROZMOWA Z UŻYTKOWNIKIEM ////////
    while(1)
    {
        string nazwa = "liczby.txt";
        ifstream plik(nazwa.c_str(), ios::in | ios::binary);
        if(!plik) // Sprawdzamy poprawnoϾ
        {
            cout << "Blad przy probie otwarcia pliku: " << nazwa << '!';
            break;
        }

        int index;
        cout << "Podaj numer elementu tablicy (0-199): ";
        cin >> index;

        if(index > -1 && index < 200)
        {
            plik.seekg(sizeof(double) * index);
            plik >> liczby[index];
            cout << "Wartosc przechowywana w tym miejscu tablicy: " << liczby[index] << endl;
        }
        else cout << "Niepoprawny index! Wprowadz liczbe z przedzialu 0-199." << endl;
    }
}

Skompilujcie, jeśli możecie i wpiszcie liczbę większą niż 191 (i mniejszą niż 200). Jeśli wyświetli 0, to macie tak jak ja... Program działa prawidłowo, ale tylko dla liczb mniejszych niż 192... Czemu? Wiem przynajmniej gdzie się sypie. Po prostu te liczby (192, 193 itd.) nie są zapisywane do pliku. Dlaczego? Przecież według zasady, którą wyczytałem w książce Jerzego Grębosza obiekt double zawsze ma wielkość sizeof(double)...

0

A może spróbuj zapisać dane za pomocą strumienia http://strefakodera.pl/programowanie/c/obsluga-plikow-w-c-zapis-danych

1

Masz zapisać do pliku binarnego. Po co więc

        string tymczasowy;
        ostringstream strumien(tymczasowy);
        strumien << liczby[i];
        string wypis = strumien.str();
        //cout << wypis << endl; Dzięki tej instrukcji przekonałem się, że problem tkwi w funkcji write().
        plik.write(wypis.c_str(), sizeof(double));
        liczby[i] = 0; // ZEROWANIE

?

plik.write(reinterpret_cast<char const*>(liczby+i), sizeof(liczby[0]));

To, co robisz teraz, to jest UB i jest niezgodne z wymogiem (a przynajmniej intencją) zadania - zapisujesz tekst ze streamu, wywołując przy okazji UB, bo czytasz 8 znaków (tzn. sizeof(double)) z wyników funkcji c_str(), która ma ich zaalokowanych 4-5.

Odczyt tak samo:

plik.read(reinterpret_cast<char*>(liczby+index),sizeof(liczby[0]));

Dlaczego miałeś problem? Bo otworzyłeś sobie plik do zapisu, a potem nie raczyłeś go zamknąć. Wyobraź sobie, że system operacyjny sobie zapisy do pliku sobie cache'uje, bo są to operacje porównywalnie do innych bardzo powolne. Dlatego też po wielokrotności 512 bajtów czekał na kolejną transzę, którą by wysłał do pliku, ale Ty jej po prostu nie dostarczyłeś. Rozwiązaniem by było po prostu wywołanie flush lub close na pierwszym obiekcie plik (lub po prostu umieszczenie go we własnym zakresie), gdyby nie wyżej opisane UB.

2

Ok więc możesz zapisywać całą tablicę na raz, zamiast kolejne elementy:

plik.write((char*)&liczby, sizeof(float)*rozmiar);

Czytasz potem za pomocą funkcji read:

plik.read((char*)&liczby[index], sizeof(double));

Ogólna całość kodu po poprawce:

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
 
int main()
{
    const int rozmiar = 200;
    double liczby[rozmiar];
    for(int i = 0; i < rozmiar; i++) liczby[i] = (0.01 * i);
 
    ofstream plik("liczby.txt", ios::out | ios::binary);

    plik.write((char*)liczby, sizeof(double)*rozmiar);


    //////// ROZMOWA Z UŻYTKOWNIKIEM ////////
    while(1)
    {
        string nazwa = "liczby.txt";
        ifstream plik(nazwa.c_str(), ios::in | ios::binary);
        if(!plik) // Sprawdzamy poprawnoϾ
        {
            cout << "Blad przy probie otwarcia pliku: " << nazwa << '!';
            break;
        }
 
        int index;
        cout << "Podaj numer elementu tablicy (0-199): ";
        cin >> index;
 
        if(index > -1 && index < 200)
        {
            plik.seekg(sizeof(double) * index);
            plik.read((char*)&liczby[index], sizeof(double));
            cout << "Wartosc przechowywana w tym miejscu tablicy: " << liczby[index] << endl;
        }
        else cout << "Niepoprawny index! Wprowadz liczbe z przedzialu 0-199." << endl;
    }

	system("pause");
} 
0

Fakt, a zrób tak, że daj plik.write(&wypis[0], sizeof(wypis));

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