Cześć
Mam problem z pewnym zadaniem.
Oto jego treść:
Napisz program do zapisywania oraz odczytywania danych ze struktury do oraz z pliku, w postaci tekstowej oraz binarnej.
W tym celu wykorzystaj strukturę point_t oraz funkcje showi set z zadania 4.1 W punkt.
Ponadto przygotuj dodatkowe funkcje do zapisu oraz do odczytu danych struktury point_t, obsługujących format binarny oraz tekstowy przechowywania danych. Funkcje te mają mieć następujące prototypy:
int save_point_b(const char *filename, const struct point_t* p);
int load_point_b(const char *filename, struct point_t* p);
int save_point_t(const char *filename, const struct point_t* p);
int load_point_t(const char *filename, struct point_t* p);
Przyrostki _t oraz _b oznaczają, że pliki mają być zapisywane (save)/odczytywane (load) w trybie/formacie tekstowym oraz binarnym.
Parametry:
filename - nazwa pliku, do którego dana funkcja ma dane zapisać bądź z którego ma dane odczytać,
p (const) - wskaźnik na strukturę point_t, z której funkcja ma pobrać dane do zapisu,
p (non-const) - wskaźnik na strukturę point_t do której funkcja ma zapisać dane po ich odczycie z dysku.
Wartość zwracana:
1 - w przypadku podania błędnych danych podczas wywołąnia funkcji,
2 - w przypadku niemożliwości otworzenia filename,
3 - w przypadku kiedy nie uda się zapisać danych do pliku lub okażą się one uszkodzone,
0 - w przypadku gdy operacja wejścia/wyjścia zakończy się sukcesem.
Format plików
W pliku tekstowym współrzędne powinny być zapisane jako dwie liczby oddzielone od siebie znakiem białym (ang. whitespace).
W pliku binarnym strukturę należy zapisać jako blok pamięci o wielkości zapisywanej struktury.
Napisz program, który przypisze do struktury point_t losowe wartości, a następnie wyświetli je. Nastepnie powinien zapytać użytkownika o nazwę pliku (nie dłuższa niż 30 znaków), do którego zapisana ma zostać utworzona struktura. W zależności od rozszerzenia pliku w podanej nazwie program powinien zapisać strukturę do pliku binarnego (rozszerzenie .bin) lub tekstowego (rozszerzenie .txt).
Jeżeli rozszerzenie będzie błędne to program powinien wyświetlić komunikat Unsupported file format i zwrócić kod błędu 7.
W przypadku niemożliwości utworzenia pliku program powinien wyświetlić komunikat Couldn't create file i zwrócić wartość 5.
Jeżeli udało się zapisać dane do pliku, program powinien wyświetlić komunikat File saved i zapytać użytkownika, czy chce odczytać dane z tego samego pliku. Dopuszczalna odpowiedź to duże lub małe litery y (tak) oraz n (nie).
Odpowiedź TAK: Program powinien odczytać dane i wyświetlić je na ekranie.
Jeżeli nie uda się odczytać danych to program powinien wyświetlić komunikat File corrupted i zwrócić wartość 6.
W przypadku niemożliwości otworzenia pliku program powinien wyświetlić komunikat Couldn't open file i zwrócić wartość 4.
Odpowiedź NIE: Program kończy swoje działanie z kodem błędu 0.
Podanie innego znaku odpowiedzi powinno spowodować wyświetlenie komunikatu Incorrect input i zakończenie programu z kodem błędu 1.
Przykład interkacji z programem -- sukces:
x = 8; y = 7⏎
Podaj sciezke do pliku:⏎
band.txt⏎
File saved⏎
Do you want to read the file (Y/N)? n⏎
x = 4; y = 2⏎
Podaj sciezke do pliku:⏎
room.txt⏎
File saved⏎
Do you want to read the file (Y/N)? y⏎
x = 4; y = 2⏎
x = 9; y = -4⏎
Podaj sciezke do pliku:⏎
second.bin⏎
File saved⏎
Do you want to read the file (Y/N)? y⏎
x = 240; y = -353⏎
Przykładowa interkacja z programem -- błąd danych wejściowych:
x = 8; y = 10⏎
Podaj sciezke do pliku:⏎
self.tx⏎
Unsupported file format
Przykład interakcji z programem -- błąd wejścia/wyjścia:
x = -7; y = -4⏎
Podaj sciezke do pliku:⏎
vary.bin⏎
Couldn't create file⏎
x = -3; y = 4⏎
Podaj sciezke do pliku:⏎
wave.txt⏎
File saved⏎
Do you want to read the file (Y/N)? y⏎
Couldn't open file
Przykładowa interakcja z programem -- plik został uszkodzony między zapisem a odczytem:
x = 7; y = -10⏎
Podaj sciezke do pliku:⏎
mind.txt⏎
File saved⏎
Do you want to read the file (Y/N)? Y⏎
File corrupted
Uwaga
W programie nie wolno używać operatora [], poza deklaracją tablicy na nazwę pliku na 31 elementów (deklaracja tablicy musi wyglądać następująco: nazwa_zmiennej [31]).
W programie nie wolno używać funkcji alokujących pamięć.
A oto i mój kod:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct point_t
{
int x;
int y;
};
struct point_t* set(struct point_t* p, int x, int y);
void show(const struct point_t* p);
int save_point_b(const char *filename, const struct point_t* p);
int load_point_b(const char *filename, struct point_t* p);
int save_point_t(const char *filename, const struct point_t* p);
int load_point_t(const char *filename, struct point_t* p);
int main()
{
struct point_t p;
srand(time(NULL));
int x=rand()%100,y=rand()%100;
if(set(&p,x,y)==NULL)
{
printf("Incorrect input");
return 1;
}
show(&p);
printf("\n");
char tab[31]={0};
char input[31]={0};
char *tab_i=&(*(tab+0)), *input_i=&(*(input+0));
int i;
printf("Podaj sciezke do pliku:\n");
scanf(" %31[^\n]", input_i);
int licznik_on_binary=0;
int licznik_on_text=0;
for(i=0; i<30; i++)
{
*(tab_i+i)=*(input_i+i);
}
for(i=0; i<26; i++)
{
if( *(tab_i + i)=='.' && *(tab_i + i + 1)=='b' && *(tab_i + i + 2)=='i' && *(tab_i + i + 3)=='n' && *(tab_i + i + 4)=='\0')
{
licznik_on_binary++;
//printf("\n%d\n",licznik_on_binary);
break;
}
if( *(tab_i + i)=='.' && *(tab_i + i + 1)=='t' && *(tab_i + i + 2)=='x' && *(tab_i + i + 3)=='t' && *(tab_i + i + 4)=='\0')
{
licznik_on_text++;
//printf("\n%d\n",licznik_on_text);
break;
}
}
if( licznik_on_binary == 0 && licznik_on_text == 0)
{
printf("Unsupported file format");
return 7;
}
if( licznik_on_text == 1)
{
int result;
result=save_point_t((const char *) tab,&p);
if(result==2 || result==3)
{
printf("Couldn't create file");
return 5;
}
if(result==0)
{
printf("File saved");
}
printf("\n");
char wybor='y';
printf("Do you want to read the file (Y/N)? ");
getchar();
scanf("%c",&wybor);
if(wybor=='y' || wybor=='Y')
{
load_point_t((const char *) tab,&p);
}
else if(wybor=='n' || wybor=='N')
{
}
else
{
printf("Incorrect input");
return 1;
}
}
if(licznik_on_binary==1)
{
int result;
result=save_point_b((const char *) tab,&p);
if(result==2 || result==3)
{
printf("Couldn't create file");
return 5;
}
if(result==0)
{
printf("File saved");
}
printf("\n");
char wybor='y';
printf("Do you want to read the file (Y/N)? ");
getchar();
scanf("%c",&wybor);
if(wybor=='y' || wybor=='Y')
{
load_point_b((const char *) tab,&p);
}
else if(wybor=='n' || wybor=='N')
{
}
else
{
printf("Incorrect input");
return 1;
}
}
return 0;
}
struct point_t* set(struct point_t* p, int x, int y)
{
if(p==NULL)
{
return NULL;
}
p->x=x;
p->y=y;
return p;
}
void show(const struct point_t* p)
{
if(p==NULL)
{
return ;
}
printf("x = %d; y = %d",p->x,p->y);
}
int save_point_b(const char *filename, const struct point_t* p)
{
if(p==NULL || filename==NULL)
{
return 1;
}
FILE * f=fopen(filename,"wb");
if(f==NULL)
{
return 2;
}
//char znak=' ';
fwrite(&(p->x),sizeof(p),1,f);
//fwrite(&znak,sizeof(p),1,f);
fwrite(&(p->y),sizeof(p),1,f);
fseek(f,0,SEEK_CUR);
fclose(f);
return 0;
}
int load_point_b(const char *filename, struct point_t* p)
{
if(filename==NULL || p==NULL)
{
return 1;
}
FILE * f=fopen(filename,"rb");
if(f==NULL)
{
return 2;
}
int i=1;
long long int number_form_fread;
while(fread(&p,sizeof(p),1,f)==1)
{
number_form_fread=(long long int)p;
if(i==1)
{
printf("x = %lli; ",number_form_fread);
}
if(i==2)
{
printf("y = %lli; ",number_form_fread);
}
i++;
}
fclose(f);
return 0;
}
int save_point_t(const char *filename, const struct point_t* p)
{
if(p==NULL || filename==NULL)
{
return 1;
}
FILE * f=fopen(filename,"w");
if(f==NULL)
{
return 2;
}
fprintf(f,"%d %d",p->x,p->y);
fseek(f,0,SEEK_SET);
fclose(f);
return 0;
}
int load_point_t(const char *filename, struct point_t* p)
{
if(filename==NULL || p==NULL)
{
return 1;
}
FILE * f=fopen(filename,"r");
if(f==NULL)
{
return 2;
}
int znak;
while(fscanf(f,"%d",&znak)==1)
{
if(znak == p->x)
{
printf("x = %d; ",znak);
}
if(znak == p->y)
{
printf("y = %d",znak);
}
}
fclose(f);
return 0;
}
Zadanie wysłałem do sprawdzenia i przechodzi mi przez mniej więcej 2/3 testów. Mam jednak pytania do was odnośnie treści zadania, której mam wrażenie do końca nie rozumiem jak i samego rozpisanego przeze mnie kodu.
1)
Tak więc pojawia mi się między innymi na testach komunikat, że "funkcje nie powinny nic wyświetlać". Na pewno nie chodzi więc o funkcję "show". Czyżbym więc coś niepoprawnie zrozumiał w funkcjach load_... i tam nie powinienem nic printfować?
2)
Na anlizie statycznej pojawiają mi się komunikaty co do niepoprawności poniższego kodu:
sizeof(p)
z opisem: "The code calls sizeof() on a pointer type. This can produce an unexpected result".
Tak więc jak powinienem zapisać to w poprawny sposób, aby uniknąć wszelkich potencjalnych "niebezpieczeństw"?
3)
Nie rozumiem tego momentu w treści zadania dotyczącego opisu co mają zwracać funkcje w tym zadaniu:
3 - w przypadku kiedy nie uda się zapisać danych do pliku lub okażą się one uszkodzone,
To jest właśnie to, przed czym mój program na obecnym etapie nie jest wcale zabezpieczony (głównie dlatego, że nie do końca wiem jakie to mogłyby być przypadki).
4) No i teraz to co mnie najbardziej nurtuje. Testy wywalające się dotyczą funkcji load_point_b i load_point_t. Nie uwzględniając przypadków z return-em 3, dla niektórych w wynikach końcowych wychodzą niepoprawne wartości.
Ot choćby dla load_point_b:
struct point_t p = { .x = 5, .y = -2};
struct point_t p1;
printf("#####START#####");
int err_code = load_point_b("hundred.bin", &p1);
printf("#####END#####\n");
test_error(err_code == 0, "Funkcja load_point_b powinna zwrócić 0, a zwróciła %d", err_code );
if (!0)
{
test_error(p.x == p1.x, "Funkcja load_point_b odczytała błędne dane, współrzędna x powinna mieć wartość 5, a ma 0", p.x, p1.x );
test_error(p.y == p1.y, "Funkcja load_point_b odczytała błędne dane, współrzędna y powinna mieć wartość -2, a ma -227688824", p.y, p1.y );
}
I jeszcze test dla funkcji load_point_t:
Sprawdzanie poprawności działania funkcji load_point_t⏎
#####START##########END#####⏎
Wynik: PORAŻKA: Funkcja load_point_t odczytała błędne dane, współrzędna x powinna mieć wartość 4, a ma 0⏎
Sprawdź funkcję testującą TEST27(void) z pliku unit_test_v2.c, w linii 1012⏎
Wynik: PORAŻKA: Funkcja load_point_t odczytała błędne dane, współrzędna y powinna mieć wartość -5, a ma -227688824⏎
struct point_t p = { .x = 4, .y = -5};
struct point_t p1;
printf("#####START#####");
int err_code = load_point_t("govern.bin", &p1);
printf("#####END#####\n");
test_error(err_code == 0, "Funkcja load_point_t powinna zwrócić 0, a zwróciła %d", err_code );
if (!0)
{
test_error(p.x == p1.x, "Funkcja load_point_t odczytała błędne dane, współrzędna x powinna mieć wartość %d, a ma %d", p.x, p1.x );
test_error(p.y == p1.y, "Funkcja load_point_t odczytała błędne dane, współrzędna y powinna mieć wartość %d, a ma %d", p.y, p1.y );
}
Chyba wyszczególniłem wszystkie problemy, z którymi borykam się w tym zadaniu. Z góry dziękuję za wszelkie odpowiedzi, dzięki którym będę w stanie polepszyć swój kod.