2016-06-14 27 views
7

Próbuję napisać i odczytać połączoną listę z pliku binarnego w C. Moim celem jest zapisanie i załadowanie danych rezydentnych dla Domu Pomocy Społecznej (w rzeczywistości, Jestem pielęgniarką), aby sklasyfikować każdego mieszkańca za pośrednictwem Grup Używania Zasobów. Zrobiłem to już dla stałej liczby mieszkańców (32, to jest pojemność obiektu) przy użyciu szeregu struktur, ale teraz muszę to zrobić dla zmiennej grupy mieszkańców, w celu przeprowadzenia badania statystycznego . Oczywiście dla tej pierwszej próby uprościłem strukturę do minimum, ponieważ rzeczywista struktura zawiera 109 danych.zapisywanie i ładowanie połączonej listy do pliku binarnego (C)

Jestem bardzo blisko rozwiązania, ale coś nie działa, to znaczy, że każdy element zapisanej listy jest na przemian z pustym. Ten kod powinien odczytać listę z pliku binarnego, pokazać go na terminal, dodaj nowy element, zapisz listę. Oczywiście każdą procedurę należy umieścić w funkcji.

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

struct pat 
{ 
    char surn [16]; 
    char name [16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 

struct pat *make_structure (void); 

int main() 
{ 
    initscr(); 
    raw(); 
    keypad (stdscr, TRUE); 
    noecho(); 

    clear(); 

    osp=make_structure(); 
    first=osp; 

    h=fopen ("archivio","r"); 

    if (h==NULL) 
     printw ("Archivio inesistente\n"); 
    else 
    { 
     while (!feof(h)) 
     { 
      printw ("Lungh. nome = %d\n",sizeof osp->name); 
      fread (osp->surn,sizeof osp->surn,1,h); 
      fread (osp->name,sizeof osp->name,1,h); 
      printw ("Cognome: %s\tNome: %s\n",osp->surn,osp->name); 
      osp->next=make_structure(); 
      osp=osp->next; 
     } 
    } 

    getch(); 

    echo(); 
    printw ("Surname: "); 
    scanw ("%s",osp->surn); 
    printw ("\nName: "); 
    scanw ("%s",osp->name); 

    noecho(); 

    osp=first; 

    h=fopen ("archivio","w"); 

    while (osp != NULL) 
    { 
     fwrite (osp->surn,sizeof osp->surn,1,h); 
     fwrite (osp->name,sizeof osp->name,1,h); 
     osp=osp->next; 
    } 

    return 0; 
} 

struct pat *make_structure(void) 
{ 
    struct pat *a; 
    a = (struct pat *)malloc(sizeof(struct pat)); 
    return (a); 
} 
+2

Powinieneś zamknąć pliki, szczególnie przed ich ponownym otwarciem. (To nie powinno naprawiać twojego problemu, tylko napiwek.) – Jashaszun

+1

'scanw ("% s ", osp-> name);' potrzebuje limitu, aby uniknąć czytania zbyt wielu znaków. Z 'name [16]', może coś takiego jak 'scanw ("% 15s ", osp-> name);' – chux

+2

BTW: imiona i nazwiska mają jakieś spacje, czyniąc '"% s "' niewystarczającym. – chux

Odpowiedz

2

Byłaś tak blisko, nie jestem nawet pewien, co było prawdziwą przyczyną awarii, gdyż z pierwszego cięcia, po prostu zastosować [większość] rozwiązywanych je przez innych i dostał program roboczy .

Mimo że zadziałało, odkryłem, że sposób, w jaki robiłeś "jedno z wyprzedzeniem" make_structure, jest mniej elastyczny, gdy rozszerzasz program, by robić inne rzeczy.

Na przykład, masz zawieszony rekord "widmowy", jeśli zamiast dodawać nowy rekord, zdecydujesz się na , a nie dodać nowy rekord, ale zrób statystyki lub manipuluj nimi.

Stworzyłem więc drugą wersję programu, który ma więcej izolacji i ogólności.


Oto minimalnie zmieniona wersja [proszę wybaczyć oczyszczanie stylu nieodpłatne]:

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

struct pat { 
    char surn[16]; 
    char name[16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 

struct pat *make_structure(void); 

int 
main() 
{ 
    int rlen; 

    initscr(); 
    raw(); 
    keypad(stdscr, TRUE); 
    noecho(); 

    clear(); 

    osp = make_structure(); 
    first = osp; 

    h = fopen("archivio", "r"); 

    if (h == NULL) 
     printw("Archivio inesistente\n"); 
    else { 
     while (1) { 
      printw("Lungh. nome = %d\n", sizeof osp->name); 

      // leave early on EOF or badly formed entry 
      rlen = fread(osp->surn, sizeof osp->surn, 1, h); 
      if (rlen != 1) 
       break; 

      // leave early on EOF or badly formed entry 
      fread(osp->name, sizeof osp->name, 1, h); 
      if (rlen != 1) 
       break; 

      printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name); 

      osp->next = make_structure(); 
      osp = osp->next; 
     } 
     fclose(h); 
    } 

    // NOTE: this just chews the first character (debug, I suppose?) 
#if 0 
    getch(); 
#endif 

    // add new element 
    echo(); 
    printw("Surname: "); 
    scanw("%15s", osp->surn); 
    printw("Name: "); 
    scanw("%15s", osp->name); 

    noecho(); 

    h = fopen("archivio", "w"); 

    osp = first; 
    while (osp != NULL) { 
     fwrite(osp->surn, sizeof osp->surn, 1, h); 
     fwrite(osp->name, sizeof osp->name, 1, h); 
     osp = osp->next; 
    } 

    fclose(h); 

    return 0; 
} 

struct pat * 
make_structure(void) 
{ 
    struct pat *a; 

    a = malloc(sizeof(struct pat)); 

    // NOTE: do this for good measure 
    a->next = NULL; 

    return (a); 
} 

Oto bardziej uogólniona wersja, która może dać Ci kilka pomysłów, kiedy rozszerzyć możliwości programu :

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

struct pat { 
    char surn[16]; 
    char name[16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 
static struct pat *prev; 

void read_archive(const char *file); 
void add_new_elements(void); 
void write_archive(const char *file); 
struct pat *make_structure(void); 
void add_to_list(struct pat *pat); 

int 
main() 
{ 

    initscr(); 
    raw(); 
    keypad(stdscr, TRUE); 
    noecho(); 

    clear(); 

    read_archive("archivio"); 

    // NOTE: this just chews the first character (debug, I suppose?) 
#if 0 
    getch(); 
#endif 

    // NOTE: instead of just automatically adding new elements, this might 
    // be replaced with a menu, such as: 
    // Enter Operation: 
    //  (1) Add new names 
    //  (2) Calculate statistics 
    //  (3) Backup database 
    add_new_elements(); 

    write_archive("archivio"); 

    return 0; 
} 

// read_archive -- read in archive 
void 
read_archive(const char *file) 
{ 
    int rlen; 

    h = fopen(file, "r"); 

    if (h == NULL) 
     printw("Archivio inesistente\n"); 

    else { 
     while (1) { 
      osp = make_structure(); 

      // leave early on EOF or badly formed entry 
      rlen = fread(osp->surn, sizeof osp->surn, 1, h); 
      if (rlen != 1) 
       break; 

      // leave early on EOF or badly formed entry 
      fread(osp->name, sizeof osp->name, 1, h); 
      if (rlen != 1) 
       break; 

      printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name); 

      add_to_list(osp); 
     } 

     // NOTE: this is _always_ for EOF or bad entry, so free it 
     free(osp); 

     fclose(h); 
    } 
} 

// add_new_elements -- prompt for new elements 
void 
add_new_elements(void) 
{ 

    echo(); 
    while (1) { 
     osp = make_structure(); 

     printw("Surname: "); 
     osp->surn[0] = 0; 
     scanw("%15s", osp->surn); 
     if (osp->surn[0] == 0) 
      break; 

     printw("Name: "); 
     osp->name[0] = 0; 
     scanw("%15s", osp->name); 
     if (osp->name[0] == 0) 
      break; 

     add_to_list(osp); 
    } 
    noecho(); 

    free(osp); 
} 

// write_archive -- write out archive 
void 
write_archive(const char *file) 
{ 

    h = fopen(file, "w"); 

    for (osp = first; osp != NULL; osp = osp->next) { 
     fwrite(osp->surn, sizeof osp->surn, 1, h); 
     fwrite(osp->name, sizeof osp->name, 1, h); 
    } 

    fclose(h); 
} 

struct pat * 
make_structure(void) 
{ 
    struct pat *a; 

    a = malloc(sizeof(struct pat)); 

    // NOTE: do this for good measure 
    a->next = NULL; 

    return (a); 
} 

void 
add_to_list(struct pat *pat) 
{ 

    if (first == NULL) 
     first = pat; 
    else 
     prev->next = pat; 

    prev = pat; 
} 

UPDATE:

ja wciąż próbuje dowiedzieć się powód mojego niepowodzenia

ja nie debug/jednoetapowy oryginalnego kodu, bo myślałem, że połączone lista logika wymagałoby naprawy i chciałem do tego szybko dojść. Jednak po jego przejrzeniu logika była w porządku. Opierając się na mojej najlepszej analizie domyślnej, prawdopodobną porażką był feof, który już zmieniłem na sprawdzanie długości na fread.

Oczywiście miałem zamiar zorganizować lepszy program wykorzystujący funkcje

Przypuszczałem, że tak. Podział w drugim programie był raczej narzędziem dydaktycznym do wyjaśnienia i zilustrowania zasady i był krytyką modułowości.

W swoim oryginalnym kodzie użytkownik miał, aby dodać nowy rekord, ponieważ osp był pusty, ale został już połączony z listą. Luźno, rekord "zombie", jeśli chcesz.

Oznacza to, że na liście był wpis związany przed został wypełniony i zatwierdzony. Innymi słowy, po pętli odczytu, ale zanim użytkownik zostanie poproszony o wprowadzenie nowego wpisu, lista może zostać uznana za zniekształconą (tj. [Małe] naruszenie zasad "programowania kontraktowego" lub "zasady projektowania po zawarciu umowy") .

Funkcja podziału w drugim programie miała właśnie to podkreślić. W szczególności, przesuwając pętlę odczytu do oddzielnej funkcji, zilustrowano/wzmocniono projekt po kontrakcie.

Oznacza to, że po wejściu lista jest pełna i dobrze sformułowana [aczkolwiek pusta]. Po powrocie jest puste (jeśli plik wejściowy ma wartość , a nie) lub zawiera tylko dobrze utworzone/kompletne rekordy.

W drugim programie wpis częściowy/zniekształcony to nigdy nie jest powiązany z. add_to_list jest zawsze wykonywany jako ostatni [tylko dla całego/kompletnego rekordu].

Tak, zarówno dla read_archive, jak i add_new_entries, gdy są wywoływane, otrzymują one pełną/kompletną listę z poprawnymi, w pełni uformowanymi rekordami. To jest "kontrakt" z im.

I aby wypełnić swoją część "umowy", funkcje te muszą pozostawiać rzeczy w ten sam sposób, zachowując integralność listy po wyjściu. Że jest "umowa" funkcji do świata zewnętrznego


Aktualizacja # 2:

wybaczcie za OT, ale można zasugerować mi dobre IDE dla C - C++ który działa dobrze z systemem Debian/GNU Linux?

Mogę nie być najlepszą osobą, która doradziłaby ci w tej sprawie, ponieważ ja jej nie używam. Pisałem C na długo przed ich istnieniem, więc opracowałem własny zestaw narzędzi, który jest o wiele potężniejszy niż jakikolwiek IDE jaki widziałem. Ponadto, gdy na nie spojrzałem, nigdy nie mogłem znaleźć sposobu na połączenie tych dwóch elementów.

jestem w domu z Code :: Blocks, ale niestety tzw nightly zbudować ma błędy i awarie bardzo często

Jeśli jesteś w domu z CodeBlocks, ale nightly build jest buggy, być może prostym rozwiązaniem jest zamiana aktualizacji na "stabilne" drzewo, jeśli to możliwe. To może być najlepsza "krótka odpowiedź".

(narzędzie do uzupełniania kodu jest bardzo przydatne, ale nie wolno mi wpisywać str ..., w przeciwnym razie zawiesza się), a to bardzo frustrujące!

Być może możesz sprawdzić bazę danych błędów i sprawdzić, czy napotkane problemy nie zawierają znanych błędów. Jeśli nie, możesz/powinieneś złożyć jeden.


Zainstalowałem codeblocks. Wygląda na to, że jest czysty i wystarczająco prosty. Zainstalowałem także eclipse i przyjrzałem się kdevelop. Z kilku stron internetowych, eclipse dostaje wysokie oceny, z netbeans o blisko sekundę

Próbowałem użyć ich na pliku źródłowym, który leżałem wokół, który został zbudowany z pliku Makefile. blockblocks był na tyle intuicyjny, że mogłem go szybko uruchomić. Miałem więcej kłopotów z innymi. Zaćmienie zostało pierwotnie zaprojektowane przez IBM do użytku wewnętrznego, a następnie wydane jako usługa publiczna. Jest dobrze wspierany i dojrzały.

I został uruchomiony zaćmienie bez CDT, ale raz dodać, że eclipse dostaje mój głos, ponieważ wydaje się mieć wystarczająco dużo możliwości kontrolowania wszystkich co zamierzam narzekać o poniżej ;-)

IDE to nieco osobisty wybór [chyba że firma go wymaga], więc powinieneś używać tego, co lubisz. Innymi słowy, spróbuj i sprawdź, jakie funkcje mają i jak działają. Oto strona, która zawiera listę niektórych: https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments

Wybierając IDE, musisz spojrzeć na "najczęściej używane" funkcje. Najczęstszą rzeczą, którą robisz, jest przewijanie w pliku źródłowym. Tak więc edytor powinien obsługiwać aliasy hjkl klawiszy strzałek, na przykład vi. Konieczność przesunięcia prawej ręki na klawisze strzałek i spowolnienie powoduje spowolnienie pracy tak, że nie można jej uruchomić.

eclipse używa gvim [graficzna vim], więc to jest plus.

Nie jestem nie fanem edycji z prostym edytorem WYSIWYG, który ma tylko proste funkcje wyszukiwania/zamiany. Podobnie vim umożliwia przeszukiwanie regex prostu wpisując /, więc ponownie, najczęstsze operacje są „na wyciągnięcie ręki”

nie używam [ani chcą] funkcje autouzupełniania. Kiedy ich wypróbowałem, często popełniają błędy, a cofnięcie się do tego, co zrobili, zajmuje więcej czasu. Jestem bardzo szybką maszynistką.

Wyłączyłem także podświetlanie składni i kolorowanie źródła. Gdy wprowadzasz kod źródłowy, kolory zmieniają się prawie z każdym wprowadzonym znakiem, ponieważ myślisz, że redaktor pisze (np. Piszę komentarz, ale myśli, że to kod, itp.). Stwierdziłem, że rozpraszać.

Ponadto, patrząc na końcowy wynik, stwierdzam, że kolorowany wynik jest "zbyt zajęty" (tj. Więcej informacji muszę filtrować), a nie coś, co pomaga mi zobaczyć, co muszę zobaczyć.

Jestem dość uporczywy wobec wcięć, dzielenia długich bloków kodu z pustymi liniami, aby poprawić czytelność. I, oczywiście, dobre komentarze. Dla mnie są one o wiele ważniejsze niż kolorystyka. Mam własne narzędzie do wcięcia [Jak możesz sobie przypomnieć, kiedy opublikowałem powyższy kod, został on ponownie uruchomiony, ponieważ przeprowadziłem go przez moje narzędzie przed opublikowaniem.

Kolejną funkcją jest graficzny debugger. Czy jest w pełni funkcjonalny? Na przykład: ddd jest graficznym opakowaniem wokół [bardzo potężnego] gdb.ddd zapewnia graficzne opakowanie i okna dla zwykłych rzeczy, ale nadal pozwala na bezpośrednie okno tekstowe dla zapytania gdb, dzięki czemu można ręcznie wpisać bardziej zaawansowane polecenia (np. watch symbol).

Czy IDE można rozszerzyć? Czy możesz dodać wtyczki? Czy możesz łatwo dodać/stworzyć swój własny?

Z jakiego systemu kontroli kodu źródłowego korzysta IDE? Przez wiele lat używałem wielu i teraz jestem całkowicie sprzedany pod numerem git. Tak więc, jeśli IDE nie obsługuje git, to nie jest uruchamianie.

Należy zauważyć, że git ma więc wiele funkcji niż mogą nieznajdować się w GUI. Tak więc naprawdę potężne rzeczy używają narzędzia wiersza poleceń w oknie terminala.

Moje IDE? Kilka okien: xterm Windows, vi, git i mój pakiet narzędzi (obecnie 250 000 wierszy skryptów perl ;-)] Czy IDE zmusza Cię do robienia rzeczy po swojemu? Jak łatwo jest importować/eksportować konfigurację itp. Do innych zewnętrznych narzędzi i IDE?

Mam bardzo potężny skrypt budujący mój własny projekt. Tak, chciałbym IDE, aby po kliknięciu przycisku "kompilacji" na nie zrobić, co normalnie zrobić, ale przełączyć kontrolę na mój skrypt budowania. Podobnie jak w przypadku innejinnej operacji, którą IDE ma do zaoferowania.

Czy IDE jest przenośny i dostępny na wszystkich głównych platformach: Linux, OSX i Windows? W przeszłości był to kolejny powód, dla którego uciekałem przed IDE. Będą dostępne tylko na jednej platformie. Lub, od kiedy robiłem konsultacje, chodziłem do środowiska, które nie pozwoliłoby zainstalować/używać IDE z powodu zasad [sysadmin].

+0

Bardzo dziękuję! Byłeś taki miły. Nie spodziewałem się tak szybko. Oczywiście zamierzałem lepiej zorganizować program za pomocą funkcji, ale wciąż próbowałem zrozumieć przyczynę mojej porażki: w końcu to była moja pierwsza próba, ale nie wiem, czy odniosę sukces bez Wsparcie. Przepraszamy za włoskie słowa w kodzie. Jeśli chodzi o getch(), tak, jego celem było tylko debugowanie. – user241968

+0

Nie ma za co! Jednym z moich najlepszych przyjaciół jest pielęgniarka, która przeprowadza podobną analizę zapisów pacjentów, aby móc wczuć się w tę sytuację. Mój przyjaciel nie jest programistą i używa tylko arkuszy kalkulacyjnych itp., Więc dla ciebie, jako pielęgniarki, napisanie własnego programu [w C, nie mniej] jest godne pochwały. Zrobiłem cięcie i wklejałem język ["obcy" :-)] do Tłumacza Google, więc byłem w stanie przeczytać wystarczająco dużo języka włoskiego, aby zrozumieć, co się dzieje. Dodałem aktualizację do mojej odpowiedzi, aby wyjaśnić nieco więcej. Tak trzymaj! –

+0

Druga wersja w 'read_archive', masz' h = fopen (file, "w"); '(' "w" '??) –

Powiązane problemy