Problem z programem zapisującym i odczytującym dane z pliku.

0

O to fragment programu. Zapisywanie działa póki co bez problemu. Wczytywanie uprościłem na razie do minimum (wyrzuciłem pętlę), a i tak nie działa jak powinno.

struct wezel{
  char nazwisko[20];
  int wiek;
  struct wezel *nast, *pop;
};

void wstawP(struct wezel *nowy){
 
  nowy->nast = wykaz;
  if (wykaz!=NULL) wykaz->pop = nowy;
  nowy->pop = NULL;
  wykaz = nowy;

}

void odczytaj(){
 FILE * pFile;
  pFile = fopen ("myfile.txt","r");
   struct wezel *w;
 
   fscanf(pFile, "%s %d", w->nazwisko,&w->wiek);

   fclose (pFile);
  printf ("\n Dane z pliku zostały wczytane. \n");
wstawP(w);
}

Mam plik myfile.txt o treści:

ddd 22

Po załadowaniu pliku i użyciu drukowania wychodzi mi coś takiego:

d
spacja 22

Jakieś rady?;)
Dlaczego omija tekst przed liczbą? %s jest chyba w porządku.

0

jakiego drukowania - nigdzie nie pokazujesz wypisywania zawartości pliku.

0

Przepraszam. Mój błąd. Oto cały program:

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

 struct wezel{ 
 char nazwisko[20]; 
 int wiek; 
 struct wezel *nast, *pop; 
 }; 

 int ilosc; 
 int rozmWezla = sizeof(struct wezel); 
 struct wezel *wykaz=NULL; 

 void czekaj(){ 
 printf("wcisnij ENTER"); getchar(); 
 } 

 void wstawP(struct wezel *nowy){ 

 nowy->nast = wykaz; 
 if (wykaz!=NULL) wykaz->pop = nowy; 
 nowy->pop = NULL; 
 wykaz = nowy; 

 } 


 void wstaw(){ 
 struct wezel *w = (struct wezel *)malloc(rozmWezla); 
 printf("nazwisko, wiek: "); 
 scanf("%s%d",w->nazwisko,&w->wiek); 
 wstawP(w); 
 } 

 void drukuj(){ 
 struct wezel *w; 
 for (w=wykaz;w!=NULL;w=w->nast) 
 printf("%s %d \n", w->nazwisko,w->wiek); 
 czekaj(); 
 } 

void odczytaj(){
  FILE * pFile;
   pFile = fopen ("myfile.txt","r");
    struct wezel *w;
  
    fscanf(pFile, "%s %d", w->nazwisko,&w->wiek);

    fclose (pFile);
   printf ("\n Dane z pliku zostały wczytane. \n");
 wstawP(w);
 }

 void zapisz(){ 
 FILE * pFile; 
 pFile = fopen ("myfile.txt","a"); 
 struct wezel *w; 
 for (w=wykaz;w!=NULL;w=w->nast) 
 { 
 fprintf(pFile, "%s %d \n", w->nazwisko,w->wiek); 
 } 
 fclose (pFile); 
 }


 main(){ 
 char z[100]; 
 do { 
 printf("\n\n w - wstaw"); 
 printf("\n d - drukuj"); 
 printf("\n z - zapisz"); 
 printf("\n k - koniec"); 
 printf("\n wybor: "); 
 fgets(z,100,stdin); 
 switch(z[0]){ 
 case 'w' : wstaw(); break; 
 case 'd' : drukuj(); break; 
 case 'z' : zapisz(); break; 
 } 
 }while(z[0]!='k'); 

 } 

Mój obecny problem dotyczy void odczytaj, która nie odczytuje danych z pliku tak jak powinna.

0

to to przyjrzyj się dokładnie linijce:
fscanf(pFile, "%s %d",
w->nazwisko,
&w->wiek);

widzisz ten znak **& **

przy wieku jest a przy nazwisko go nie ma?

0

alex - fscanf jest dobry.

Ja nie widzę tutaj alokowania pamięci na węzeł.

0

Alokowania pamięci na węzeł?
struct wezel *w; nie wystarczy? Wystarcza przy zapisz void.

0

Przy zapisie ustawiasz wskaźnik na wcześniej zaalokowane stryktury, przy odczycie nie. Tak poza tym, to u mnie działa.

0

Nie do końca rozumiem. Czyli co muszę zmienić?

1

Shalom ma rację: mamy wiszący wskaźnik "wezel* w" i brakuje czegoś co jest w funkcji wstaw():
struct wezel *w = (struct wezel *)malloc(rozmWezla);

Dopiero wtedy można przypisywac cokolwiek do w->nazwisko i w->wiek.

0

Tego brakowało. Teraz działa bez zarzutów. A więc czas dodać pętle, żeby wczytywało więcej danych z jednego pliku.
I tu kolejny problem. Pętla użyta do zapisywania do pliku nie działa już przy odczytywanie.
Wyskakuje błąd: Naruszenie ochrony pamięci.

 void odczytaj(){
 FILE * pFile;
  pFile = fopen ("myfile.txt","r");
   struct wezel *w = (struct wezel *)malloc(rozmWezla); 
 for  (w=wykaz;w!=NULL;w=w->nast)
{
   fscanf(pFile, "%s%d \n", w->nazwisko,&w->wiek);
}
   fclose (pFile);
  printf ("\n Dane z pliku zostały wczytane. \n");
wstawP(w);
}

Gdy zrobię taką zmianę, to nie wyrzuca błędu, ale i tak wczytuje tylko pierwszą linijkę z pliku txt :/

void odczytaj(){
 FILE * pFile;
  pFile = fopen ("myfile.txt","r");

   struct wezel *w = (struct wezel *)malloc(rozmWezla); 
wstawP(w);
 for  (w=wykaz;w!=NULL;w=w->nast)
{
   fscanf(pFile, "%s%d \n", w->nazwisko,&w->wiek);
}
   fclose (pFile);
  printf ("\n Dane z pliku zostały wczytane. \n");

} 
0

malloc alokuje pamięć, ale jej nie inicjuje - są tam śmieci. To znaczy, że po zaalokowaniu pamięci dla "wezel* w", pole w->next wskazuje na dowolny obszar pamięci do którego chcesz przypisać dane w drugim obiegu pętli. Czyli zmiana powinna polegać na tym, że:

  1. najpierw alokujesz pamięć dla w->next
  2. dopiero potem czytasz z pliku i zapisujesz odczytane dane do w->next->nazwisko i w->next->wiek

Jeszcze jedno: cała pętla for jest bez sensu. Powinieneś w pętli czytać dane w pliku - czyli koniec pliku byłby dla ciebie końcem pętli i przy każdym jej obiegu inicjujesz pamięć dla w->next i zapisujesz do w->next->nazwisko i w->next->wiek.

0

Nie mam pojęcia jak to zrobić :/
Mógłbyś bardziej "łopatologicznie"?

0

FILE* f = fopen(...)

wezel* w = (wezel*)malloc(sizeof(wezel));
wezel* root = w; //co by mieć wskaźnik do pierwszego elementu

while(EOF != fscanf(f, "%s %d", w->nazwisko, &w->imie))
{
w->next = (wezel*)malloc(sizeof(wezel));
w = w->next;
}

fclose(f);

Pisane z głowy, więc może zawierać błędy, ale chodzi o ideę. Dodatkowo przy tym rozwiązaniu alokujemy o jeden węzeł za dużo, więc po wyjściu z pętli musimy go zwolnić

free(w);
a w poprzednim węźle ustawiamy w->next na zero.

Dodatkową alokację możemy pominąć używając dodatkowych zmiennych:
char szName[20]
int wiek

do których czytamy w fscanf() i dopiero potem alokujemy kolejny węzeł.

0

Na razie mam coś takiego;

 void odczytaj(){
 FILE * pFile;
  pFile = fopen ("myfile.txt","r");

   struct wezel *w = (struct wezel *)malloc(rozmWezla); 
   struct wezel *root = w;  //wskaźnik ustawiony na pierwszy element
wstawP(w);
 while(EOF!=fscanf(pFile, "%s%d \n", w->nazwisko,&w->wiek))
{
   w->nast = (struct wezel *)malloc(rozmWezla);
   w=w->nast;
}
free(w);
   fclose (pFile);
  printf ("\n Dane z pliku zostały wczytane. \n");

}

Wczytuje wszystkie dane, ale dodatkowo dodaje "0" na końcu listy. Dodatkowym problemem jest fakt, że po wczytaniu i kolejnym zapisaniu program zapisuje znowu te same dane. Nie wiem jak tego uniknąć.
Po kilku odczytach i zapisać treść pliku txt wygląda tak:

ccc 33 
bbb 22 
aaa 11 
ccc 33 
bbb 22 
aaa 11 
 0 
ccc 33 
bbb 22 
aaa 11 
 0 
ccc 33 
bbb 22 
aaa 11 
ccc 33 
bbb 22 
aaa 11 
0 0 
ccc 33 
bbb 22 
aaa 11 
0 0 
 0  

No i największy problem. Gdy do wczytanego pliku wstawię powiedzmy dwie dodatkowe pozycje, a następnie próbuję zapisać plik, program zapisuje w kółko te same dane. Trwa to aż nie przerwę działania programu ctrl+z.

0

W funkcji odczytaj() po wyjściu z pętli usuwasz ostatni węzeł - free(w) - ale nie ustawiasz w poprzednim węźle w->next na zero. Czyli znów masz wiszący wskaźnik. Być może to jest przyczyną. Przypuszczam, że wtedy funkcja zapisz() próbuje zapisać o jeden element za dużo sprawdzając czy "w->next != NULL". Proponuję dokładnie sprawdzić program pod debuggerem.

A po chwili szukania znalazłbyś kiedy fscanf() może doprowadzić do nieskończonej pętli i jak temu zaradzić:
http://www.cs.bu.edu/teaching/c/file-io/intro/

0
 oid odczytaj(){
 FILE * pFile;
  pFile = fopen ("myfile.txt","r");

   struct wezel *w = (struct wezel *)malloc(rozmWezla); 
   struct wezel *root = w;  //wskaźnik ustawiony na pierwszy element
wstawP(w);
 while(EOF!=fscanf(pFile, "%s%d \n", w->nazwisko,&w->wiek))
{
   w->nast = (struct wezel *)malloc(rozmWezla);
   w=w->nast;
}
w->nast = NULL;
free(w);
   fclose (pFile);
  printf ("\n Dane z pliku zostały wczytane. \n");

}

Jak myślisz, w którym momencie przy odczycie z pliku zostaje dodane to "0" na końcu? Chociaż to pewnie w niczym nie pomorze, bo jeśli odczytam, a potem zapiszę, znowu odczytam, to po drukowaniu mam dwa razy dłuższy plik i już trzy zera na końcu.

Nieskończona pętla powstaje, gdy program napotka nieoczekiwany format pliku. Np. tekst tam gdzie miał być INT. Nie widzę czegoś takiego w moim programie:/

0

Tego nie wiem. Ale jak przy zapisie każdego węzła dodasz fflush(), puścić krok po kroku pod debugerem i będziesz patrzył kiedy to to się zapisuje do pliku, to zapewne znajdziesz.

0

Zainstalowałem jakiś Nemiver Debugger i nie ma w nim chyba podglądu na to co się w danym momencie dzieje w kodzie programu.
Chyba zaczynam pomału nienawidzić linuksa:/
Tak to jest jak chce się ogarnąć w 3 dni coś czego powinno się uczyć 3 miesiące:/

0

Ja akurat jestem "Windows-oriented", więc w linuksie za dużo nie pomogę :)
Nie ma jakiegoś IDE pod linuksa? Nawet NetBeans ma wsparcie dla C++, więc powinien dać radę. Może Eclipse CDT.

0

Instaluje NetBeans pod windowsem. Da rade wrzucić do niego jeszcze nieskompilowany program? Tekst to tekst, więc mogę go sobie przenieść do windowsa.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
podkreśla jak błędy:/

0

Nie jestem masochistą i używam Visual Studio 2010 Express :)

Pod linuksem Netbeans potrafi wykryć zainstalowane gcc. Pod windowsem trzeba ściągnąć mingw, bo Netbeans to tylko IDE. Skoro możesz pracować na windzie, to proponuję zainstalować Visuala. Od razu będziesz mial gotowe całe środowsko do pracy.

0

Cały system mi się posypał, więc jeśli ktoś miałby jakąś radę co do odczytaj void, to piszcie. Na razie ciężko będzie mi cokolwiek zainstalować na komputerze, a to zadanie muszę dzisiaj skończyć:/

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