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

Zapis do pliku binarnego C ANSI PEDANTIC WALL

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
866 wizyt
pytanie zadane 18 maja 2020 w C i C++ przez Daim123 Użytkownik (530 p.)

Polecenie:

program otwiera plik tekstowy, którego każda linijka zawiera pewną, z góry nieokreśloną liczbę liczb 
zmiennoprzecinkowych typu float (pełne rozwiązanie nie powinno zakładać żadnego ograniczenia na długość linijki),
odczytuje kolejne linijki i ich zawartość zapisuje do pliku binarnego jako rekordy o zmiennej długości:
każdy rekord składa się z liczby typu integer, która określa liczbę danych (liczb float) w linijce, 
za którą następują same dane (liczby). Plik nie powinien zawierać żadnych dodatkowych zapisów (separatorów, znaczników itp).

Mam problem, ponieważ do pliku zapisuje się jedynie liczba liczb w linii i nie wiem jak to naprawić. 

#include <stdio.h>
#include <stdlib.h>
#define IN 1
#define OUT 0

struct rec
{
    size_t num;
    char *arr;
};

int number_of_numbers(char * buffer)
{
    int counter, state;
    int i;
   i=counter = state = OUT;
    
    while((buffer[i]!='\n')&&(buffer[i]!=EOF))
    {
        if(buffer[i]==' '||buffer[i]=='\t') state = OUT;
        else if(state==OUT)
        {
            state = IN;
            counter++;
        }
        i++;
    }
    
    return counter;
}




int main()
{
    FILE *f,*f_2;
   
    long lSize;
    char *buffer;
    struct rec r;


   
    f = fopen("plik.txt", "r");
    f_2=fopen("nowyplik.txt", "wb");
    if(!f) return 1;
    
    fseek(f, 0, SEEK_END);
    lSize = ftell(f);
    rewind (f);
    
    r.arr = (char*)malloc(sizeof(char)*lSize);
   
    while(fgets(r.arr,lSize,f)!=NULL)
   {
       r.num = number_of_numbers(r.arr);
       fwrite(&r, sizeof(struct rec), sizeof(r.arr), f_2);
   }
  
 
    fclose(f);
    free(r.arr);
    fclose(f_2);
    return 0;
}

 

1 odpowiedź

0 głosów
odpowiedź 19 maja 2020 przez j23 Mędrzec (195,220 p.)

Zapis pojedynczej linii tak powinien wyglądać:

float* p = /* tablica floatów */;
size_t n = /* ilość liczb w 'p' */;

fwrite(&n, sizeof(size_t), 1, f_2);
fwrite(p, sizeof(float), n, f_2);

 

komentarz 19 maja 2020 przez Daim123 Użytkownik (530 p.)
zapisywać to w mojej pętli?
komentarz 19 maja 2020 przez j23 Mędrzec (195,220 p.)

Najpierw napisz funkcję, która pędzie zwracać odpowiednio ustawione p i n dla każdej linii (możesz użyć tak jak teraz struktury, tylko zamiast wskaźnika char* daj float*).

Użyj funkcji strtof i realloc.

komentarz 19 maja 2020 przez Daim123 Użytkownik (530 p.)
Masz na myśli strtof, w c jako atof?
komentarz 19 maja 2020 przez j23 Mędrzec (195,220 p.)

Mam na myśli to, co napisałem. strtof zwraca wskaźnik na miejsce, w którym skończył parsować liczbę. Dzięki temu możesz w łatwy sposób napisać pętlę wyciągającą liczby z linii tekstu. W połączeniu z realloc to parę linii kodu.

 

Funkcja ta jest w standardzie C99.

komentarz 19 maja 2020 przez Daim123 Użytkownik (530 p.)
trochę nie wiem jak to zrobić, pierw i tak pobierać linię z pliku i do tego to zastosować?
komentarz 19 maja 2020 przez j23 Mędrzec (195,220 p.)
No tak. Jak inaczej chciałeś to zrobić?
komentarz 19 maja 2020 przez Daim123 Użytkownik (530 p.)
Próbuję sobie ułożyć to w algorytm.

1) Głowna pętla w której wczytuję linię

2) pod pętla która jest zależna od strtof jeżeli zwróci NULL to kończę

-w tej pętli wczytuje liczby do tablicy i zwiększam pamięć tej tablicy i tworzę licznik który ustala ile jest liczb w linii

3) Zapisuje do pliku wracam do punktu 1, tak to ma wyglądać?
komentarz 19 maja 2020 przez j23 Mędrzec (195,220 p.)

Tak.

strtof jeżeli zwróci NULL to kończę

strtof nie zwraca NULL. Kończysz, kiedy zwrócony wskaźnik będzie równy wskaźnikowi początkowemu lub kiedy nastąpi błąd konwersji.

komentarz 20 maja 2020 przez Daim123 Użytkownik (530 p.)
Czyli jak ten warunek w while zapisać?
komentarz 20 maja 2020 przez j23 Mędrzec (195,220 p.)
const char* line = " 1.2 2.3 3.4";
char *end;
float v;

while (v = strtof(line, &end), line != end) {
    /* tu dodajesz 'v' do tablicy */
    line = end;
}
    

 

komentarz 20 maja 2020 przez Daim123 Użytkownik (530 p.)
#include <stdio.h>
#include <stdlib.h>

struct rec
{
    size_t num;
    float *arr;
};


int main()
{
    FILE *f,*f_2;
   
    long lSize;
    char *buffer, *end;
    struct rec r;
    float v;
    int counter;
    
    f = fopen("rosol.txt", "r");
    f_2=fopen("nowyplik.txt", "wb");
    if(!f) return 1;
    

    fseek(f, 0, SEEK_END);
    lSize = ftell(f);
    rewind (f);
    
    r.arr = (float*)malloc(sizeof(float)*lSize);
    buffer = (char*)malloc(sizeof(char)*lSize);
   
    while(fgets(buffer,lSize,f)!=NULL)
   {
      counter=0;
       while (v = strtof(buffer, &end),buffer != end)
       {
           r.arr[counter] = v;
           counter++;
           buffer = end;
       }
       r.num = counter;
       fwrite(&r.num, sizeof(size_t), 1, f_2);
       fwrite(r.arr, sizeof(char), r.num, f_2);
       printf("%d",r.num);
   }
  
 
    fclose(f);
    free(r.arr);
    fclose(f_2);
    return 0;
}

Czy tak to ma wyglądać? 

komentarz 20 maja 2020 przez j23 Mędrzec (195,220 p.)

rec::arr jest wskaźnikiem na wartości typu float, dlaczego zatem w wywołaniu fwrite masz sizeof(char)?

Po co ten counter? Nie wystarczy rec::num, skoro już używasz struktury?

 

komentarz 20 maja 2020 przez Daim123 Użytkownik (530 p.)
 while(fgets(buffer,lSize,f)!=NULL)
   {
       r.num=0;
       while (v = strtof(buffer, &end),buffer != end)
       {
           r.arr[r.num] = v;
           r.num++;
           buffer = end;
       }
     
       fwrite(&r.num, sizeof(size_t), 1, f_2);
       fwrite(r.arr, sizeof(float), r.num, f_2);
    
   }

Tak? I mam pytanie, czy teraz jak np mam w pliku liczbę 1 to nie zapiszę mi się to do binarnego jako 1.0000? 

komentarz 20 maja 2020 przez j23 Mędrzec (195,220 p.)

Nie. Zapisujesz binarnie, więc liczba będzie zapisana w kodowaniu zmiennoprzecinkowym (IEEE-754).

komentarz 20 maja 2020 przez Daim123 Użytkownik (530 p.)
A gdybym chciał zrobić to w drugą stronę, teraz ten plik co zapisałem jakbym chciał go otworzyć i zapisać do normalnego?
komentarz 20 maja 2020 przez j23 Mędrzec (195,220 p.)

Robisz odwrotnie. Użyj funkcji fread i fprintf.

komentarz 20 maja 2020 przez Daim123 Użytkownik (530 p.)
w sensie, że zamiast fwrite, fread?
komentarz 21 maja 2020 przez Daim123 Użytkownik (530 p.)

       fread(&r.num, sizeof(size_t), 1, f);
       fread(r.arr, sizeof(float), r.num, f);
       
    for(i=0; i<r.num; i++) fprintf(f_2,"%f ", r.arr[i]);

Tylko nie wiem w w jakiej pętli to zamknąć, z jakim warunkiem i jak poradzić sobie  z zapisem np 3.00000

komentarz 21 maja 2020 przez j23 Mędrzec (195,220 p.)
edycja 21 maja 2020 przez j23
struct rec r = { 0, NULL };

while (fread(&r.num, sizeof(size_t), 1, f) == 1) {
	r.arr = realloc(r.arr, sizeof(float) * r.num);
	r.num = fread(r.arr, sizeof(float), r.num, f);
	for(i = 0; i < r.num; i++) 
		fprintf(f_2, "%g ", r.arr[i]);
}

free(r.arr);

 

Podobne pytania

0 głosów
1 odpowiedź 398 wizyt
pytanie zadane 16 marca 2020 w C i C++ przez Quanti994 Początkujący (340 p.)
0 głosów
1 odpowiedź 570 wizyt
pytanie zadane 2 grudnia 2018 w C i C++ przez MAXIM7 Obywatel (1,990 p.)
0 głosów
1 odpowiedź 1,790 wizyt
pytanie zadane 6 lutego 2019 w C i C++ przez kamasazi98 Początkujący (410 p.)

93,103 zapytań

142,077 odpowiedzi

321,571 komentarzy

62,445 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

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...