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

Zapis double do pliku (Unie)

Object Storage Arubacloud
0 głosów
346 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ź 278 wizyt
pytanie zadane 15 maja 2017 w C i C++ przez pako217 Nowicjusz (120 p.)
+1 głos
1 odpowiedź 1,285 wizyt
0 głosów
4 odpowiedzi 311 wizyt

92,550 zapytań

141,394 odpowiedzi

319,522 komentarzy

61,935 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...