• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zapis double do pliku (Unie)

42 Warsaw Coding Academy
0 głosów
413 wizyt
pytanie zadane 16 kwietnia 2020 w C i C++ przez Hubertius Bywalec (2,970 p.)
edycja 16 kwietnia 2020 przez Hubertius

Hej :)

Rozwiązuje obecnie zadanie o takiej treści:

Napisz program do zapisu/odczytu liczby typu double poprzez tablice bajtów do pliku tekstowego.

Przygotuj unię do przechowywania liczby double oraz ośmiobajtowej tablicy znaków:

union double_to_char_t
{
    double d;
    char tab[8];
};
Napisz funkcje do: zapisywania liczby typu double na dysk po jednym znaku oraz do wczytywania danych z pliku i odtwarzania liczby double. Prototypy funkcji powinny wyglądać następująco:

int save_double(const union double_to_char_t *dtc, const char *filename);
Funkcja zapisuje zawartość unii dtc korzystając jedynie z pola tab. Operację zapisu należy zrealizować bajt po bajcie. Wielkość poprawnie zapisanego pliku to zawsze 8 bajtów.

Parametry:

filename - nazwa pliku, do którego ma zostać zapisana liczba,
dtc - wskaźnik na unię, której zawartość ma zostać zapisana do pliku,
Wartość zwracana:

0 - jeżeli zapis się powiódł,
1 - kiedy podane zostały błędne dane,
2 - w przypadku kiedy nie można otworzyć pliku filename,
3 - w przypadku kiedy nie uda się zapisać wszystkich danych do pliku filename.
int load_double(union double_to_char_t *dtc, const char *filename);
Funkcja wczytuje dane do unii dtc z pliku filename. Dane mogą być zapisywane pod wskaźnik dtc jedynie z wykorzystaniem tablicy tab.

Parametry:

filename - nazwa pliku, z którego ma zostać odczytana liczba,
dtc - wskaźnik na unię, do której mają zostać zapisane dane odczytane z pliku,
Wartość zwracana:

0 - jeżeli odczyt się powiódł,
1 - funkcję wywołano z błędnymi danymi,
2 - w przypadku kiedy nie można otworzyć pliku,
3 - w przypadku, kiedy plik jest uszkodzony.
Napisz program, który pobierze od użytkownika liczbę typu double i zapisze ją do unii, w przypadku wprowadzenia błędnych danych program powinien wyświetlić komunikat Incorrect input i zakończyć działanie z kodem błędu 1. Następnie program ma zapytać użytkownika o nazwę pliku (nie więcej niż 39 znaków) i zapisać do niego liczbę w trybie tekstowym.

W przypadku niepowodzenia program powinien wyświetlić komunikat Couldn’t create file i zakończyć się z kodem błędu 5. Jeżeli udało się zapisać liczbę do pliku to program powinien wyświetlić komunikat File saved i kontynuować pracę.

Następnie program powinien ponownie zapytać użytkownika o nazwę pliku (nie więcej niż 39 znaków) i wczytać z niego zawartość do unii.

Jeżeli operacja zakończy się sukcesem to program powinien wyświetlić na ekranie odczytaną liczbę. Jeżeli plik nie istnieje to program powinien wyświetlić komunikat Couldn’t open file i zakończyć się z kodem błedu 4 W przypadku uszkodzenia pliku wejściowego program ma wyświetlić File corrupted i zakończyć się z kodem błedu 6.

Przykład interakcji z programem -- sukces:

Podaj liczbę: 5860.514410⏎
Podaj nazwę pliku: pick.txt⏎
File saved⏎
Podaj nazwę pliku: die⏎
4820.069145
Pliki: pick.txt, die.

Przykład interakcji z programem -- błędy wejścia/wyjścia:

Podaj liczbę: -79.170020⏎
Podaj nazwę pliku: together⏎
Couldn't create file⏎
⏎
Podaj liczbę: 0.000000⏎
Podaj nazwę pliku: keptbin⏎
File saved⏎
Podaj nazwę pliku: strangebin⏎
Couldn't open file
Przykład interakcji z programem -- próba wczytania uszkodzonego pliku:

Podaj liczbę: 2759.583284⏎
Podaj nazwę pliku: heatbin⏎
File saved⏎
Podaj nazwę pliku: occurbin⏎
File corrupted
Przykład interakcji z programem -- błąd danych wejściowych:

Podaj liczbę: hhYmQwVhb⏎
Incorrect input
Uwaga

W programie nie wolno korzystać z operatora [], oprócz deklaracji tablicy.
Używanie operatorów bitowych jest niedozwolone.

Rozpisałem więc kod do zadania:

#include <stdio.h>
#include <stdlib.h>

union double_to_char_t
{
    double d;
    char tab[8];
};

int save_double(const union double_to_char_t *dtc, const char *filename);
int load_double(union double_to_char_t *dtc, const char *filename);

int main()
{
    union double_to_char_t unia;
    printf("Podaj liczbe: ");
    if(scanf("%f",&(unia.d))!=1)
    {
        printf("Incorrect input");
        return 1;
    }
    char tab[40]={0};
    char input[40]={0};
    char *tab_i=&(*(tab+0)), *input_i=&(*(input+0));
    printf("Podaj sciezke do pliku\n");
    scanf(" %39[^\n]", input_i);
    int i;
    for(i=0; i<39; i++)
    {
        *(tab_i+i)=*(input_i+i);
    }
    int wynik;
    wynik = save_double(&unia,tab);
    if( wynik > 0)
    {
        printf("Couldn’t create file");
        return 5;
    }
    else
    {
        printf("File saved\n");
    }
    char tab2[40]={0};
    char input2[40]={0};
    char *tab_i2=&(*(tab2+0)), *input_i2=&(*(input2+0));
    printf("Podaj sciezke do pliku: ");
    scanf(" 39[^\n]",input_i2);
    for(i=0; i<39; i++)
    {
        *(tab_i2+i)=*(input_i2+i);
    }
    wynik = load_double(&unia,tab2);
    if(wynik>0 && wynik<3)
    {
        printf("Couldn’t open file");
        return 4;
    }
    if(wynik == 3)
    {
        printf("File corrupted");
        return 6;
    }
    printf("%f",unia.d);

    return 0;
}

int save_double(const union double_to_char_t *dtc, const char *filename)
{
    if(dtc == NULL || filename == NULL)
    {
        return 1;
    }
    FILE * f=fopen(filename,"w");
    if(f == NULL)
    {
        return 2;
    }
    int i;
    int result;
    char znak;
    for( i = 0; i < 8; i++)
    {
        znak = dtc -> tab + i;
        result = fwrite( &znak ,sizeof(char),1,f);
        if( result != 1)
        {
            fclose(f);
            return 3;
        }
    }
    fclose(f);
    return 0;
}

int load_double(union double_to_char_t *dtc, const char *filename)
{
    if( dtc == NULL || filename == NULL)
    {
        return 1;
    }
    FILE * f = fopen(filename,"r");
    if( f == NULL )
    {
        return 2;
    }
    int i;
    int result;
    char znak;
    for(i = 0; i < 8; i++)
    {
        result = fread(&znak,sizeof(char),1,f);
        if( result != 1)
        {
            fclose(f);
            return 3;
        }
    }
    fclose(f);
    return 0;
}

Generalnie na chwilę obecną brakuje mi wiedzy na temat jednej rzeczy w celu ukończenia zadania.

Jak za pomocą wskaźnika dtc mogę się odwołać do *(tab + i)? Na ten czas w funkcji save_double nie wiem, czy zapis odbywa się poprawnie ( nie jestem pewien, czy poniższa linijka kodu jest prawidłowa):

znak = dtc -> tab + i;

Ponadto jak mogę zastosować podobny zapis przypisując wartość zmiennej znak pod *(tab + i)? w funkcji load_double?

Gdybym musiał się odwoływać za pomocą unii w funkcji main to pewnie wykorzystałbym zapis w stylu:

unia.tab + i

, ale tutaj mam już działanie na wskaźniku do unii w osobnej funkcji.

P.S Teraz zauważyłem w trakcie sprawdzania poprawności programu, że choćbym przy drugim pliku wpisywał nazwę tego pierwszego to cały czas dostaje komunikat o niemożliwości otwarcia pliku. O co może chodzić?

komentarz 16 kwietnia 2020 przez LuQ232 Mądrala (7,200 p.)

Nie jestem pewny czy w 100% rozumiem twój problem, ale jeżeli przesyłasz do funkcji wskaźnik na oryginał unii to do elementu tej tablicy możesz odwoływać się tak:

dtc->tab[i];

Czy o to Ci chodziło?

komentarz 16 kwietnia 2020 przez Hubertius Bywalec (2,970 p.)

Prawie. Chodzi o to, aby właśnie ten zapis

dtc->tab[i]

uzyskać bez operatorów []. Taki wymóg został mi narzucony w uwagach do zadania.

Czy w takim razie to byłoby coś w stylu 

dtc->*(tab+i)

1 odpowiedź

+1 głos
odpowiedź 16 kwietnia 2020 przez LuQ232 Mądrala (7,200 p.)
wybrane 17 kwietnia 2020 przez Hubertius
 
Najlepsza

Jak za pomocą wskaźnika dtc mogę się odwołać do *(tab + i)?

W funkcji load_duble możesz stworzyć wskaźnik na elementy typu char. Ustawić go na pierwszy  element tablicy. Potem możesz przesuwać wskaźnik jak Ci się tylko podoba i dostać się do każdego elementu tablicy. W taki sposób możesz odwolać się do elementu i tablicy    "*(pointer+i)". Poniżej program obrazujący to co chciałem przekazać ;)


#include <stdio.h>
#include <stdlib.h>

union double_to_char_t
{
    double d;
    char tab[8];
};

int print_original_element(union double_to_char_t *dtc);

int main()
{
    union double_to_char_t unia;
    unia.tab[0]='a';
    unia.tab[1]='b';
    unia.tab[2]='s';

    print_original_element(&unia);


    return 0;
}

int print_original_element(union double_to_char_t *dtc)
{
char *pointer ;
pointer = dtc->tab;

printf("%c ",*(pointer));


printf("%c ",*(pointer+1));


printf("%c ",*(pointer+2));
    return 0;
}



 

 

Ponadto jak mogę zastosować podobny zapis przypisując wartość zmiennej znak pod *(tab + i)? w funkcji load_double?

 

*(pointer+i) = 'd';

 

Przyklad obrazujący: 


#include <stdio.h>
#include <stdlib.h>

union double_to_char_t
{
    double d;
    char tab[8];
};

int change_element(union double_to_char_t *dtc);

int main()
{
    union double_to_char_t unia;
    unia.tab[0]='a';
    unia.tab[1]='b';
    unia.tab[2]='s';
    printf("BEFORE CHANGE: %c\n",unia.tab[2]);
    change_element(&unia);

    printf("AFTER CHANGE: %c",unia.tab[2]);
    return 0;
}

int change_element(union double_to_char_t *dtc)
{
char *pointer ;
pointer = dtc->tab;

*(pointer+2) = 'd';
    return 0;
}

 

Dodatkowo, pamiętaj że na początku ustawiasz wskaźnik na pierwszy element tablicy w przesłanej do funkcji uni. Jeżeli gdzieś w kodzie przykładowo dasz:

pointer++;

wtedy pointer będzie wskazywał na drugi element. Przesunie się on z pierwszego elementu na drugi. 

 

Poza tym rozumiem że to wymóg aby dostawać się do tablicy w sposób  *(tab+i). W praktyce powinno używać się:

dtc->tab[i];

 

Podobne pytania

0 głosów
1 odpowiedź 483 wizyt
pytanie zadane 15 maja 2017 w C i C++ przez pako217 Nowicjusz (120 p.)
+1 głos
1 odpowiedź 1,398 wizyt
0 głosów
4 odpowiedzi 670 wizyt

93,385 zapytań

142,384 odpowiedzi

322,540 komentarzy

62,745 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...