2016-06-14 6 views
7

Ich versuche eine verknüpfte Liste aus einer Binärdatei in C zu schreiben und zu lesen. Mein Ziel ist das Speichern und Laden von residenten Daten für ein Pflegeheim (eigentlich Ich bin eine Krankenschwester), um jeden Bewohner über die Ressourcennutzungsgruppen zu klassifizieren. Ich habe es bereits für eine festgelegte Anzahl von Bewohnern (32, das ist die Kapazität der Einrichtung) mit einer Reihe von Strukturen getan, aber jetzt muss ich dies für eine variable Gruppe von Bewohnern tun, um eine statistische Studie zu machen . Offensichtlich für diesen ersten Versuch habe ich die Struktur auf das Minimum vereinfacht, da die tatsächliche Struktur 109 Daten enthält.Speichern und Laden einer verketteten Liste in eine Binärdatei (C)

Ich bin sehr nah an der Lösung, aber etwas funktioniert nicht, das heißt, jedes Element der gespeicherten Liste wird mit einer void eins abgewechselt.Dieser Code sollte die Liste aus der Binärdatei lesen, zeigen Sie es auf der Terminal, fügen Sie ein neues Element hinzu, speichern Sie die Liste. Natürlich sollte jede Prozedur in eine Funktion gestellt werden.

#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

Sie sollten Dateien schließen, besonders bevor Sie sie wieder öffnen. (Dies sollte Ihr Problem nicht beheben, nur ein Tipp.) – Jashaszun

+1

'scanw ("% s ", osp-> name);' benötigt ein Limit, um zu vermeiden, zu viele Zeichen zu lesen. Mit 'name [16]', vielleicht etwas wie 'scanw ("% 15s ", osp-> name);' – chux

+2

Übrigens: Vornamen und Nachnamen haben etwas in ihnen, was "% s" unangemessen macht. – chux

Antwort

2

Sie waren so nah, ich bin nicht einmal sicher, was die wahre Ursache des Scheiterns war, weil, für den ersten Schnitt, ich habe gerade angewandt [meisten] die von anderen vorgeschlagenen Behebungen und bekam ein Arbeitsprogramm .

Obwohl es funktionierte, fand ich, dass die Art, wie Sie die "one ahead" make_structure Aufruf weniger flexibel zu sein, wenn Sie das Programm zu anderen Dingen zu erweitern.

Zum Beispiel hätten Sie einen hängenden "Ghost" -Datensatz, wenn Sie anstatt einen neuen Datensatz hinzuzufügen, nicht einen neuen Datensatz hinzufügen, aber einige Statistiken oder Manipulation der vorhandenen.

Also habe ich eine zweite Version des Programms erstellt, die mehr Isolation und Allgemeingültigkeit hat.


Hier ist die minimal verändert Version [bitte unentgeltlichen Stil Bereinigungs verzeihen]:

#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); 
} 

Hier ist die verallgemeinerte Version, die Ihnen ein paar Ideen, wenn Sie die Funktionen des Programms erweitern :

#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:

Ich war immer noch der Grund meines Versagens

Ich habe nicht debug/um herauszufinden, Ihre Original-Code einstufiges, weil ich dachte, dass verknüpften Liste Logik würde repariert werden müssen und ich wollte schnell dazu kommen. Nachdem ich es überprüft habe, war die Logik in Ordnung. Basierend auf meiner Analyse der besten Schätzung war der wahrscheinliche Fehler der feof, den ich bereits auf fread zur Längenüberprüfung geändert hatte.

Natürlich, ich würde besser organisieren, um die Programmfunktionen mit

ich davon aus, dass Sie würden. Die Aufteilung in das zweite Programm war eher ein Lehrmittel zur Verdeutlichung und Veranschaulichung eines Prinzips und war eine Kritik der Modularität.

In Ihrem ursprünglichen Code, Sie hatten, um einen neuen Datensatz hinzuzufügen, weil osp leer war, aber bereits in der Liste verknüpft. Lose, eine "Zombie" Platte, wenn du willst.

Das heißt, die Liste hatte einen Eintrag verknüpft in vor es wurde ausgefüllt und validiert. Mit anderen Worten, nach der Leseschleife, aber bevor der Benutzer nach dem neuen Eintrag gefragt wird, könnte die Liste als fehlerhaft angesehen werden (dh eine [kleine] Verletzung der Prinzipien "Vertragsprogrammierung" oder "Design-by-Contract") .

Die Funktionsaufteilung im zweiten Programm war nur um dies zu betonen. Insbesondere, indem die Leseschleife in eine separate Funktion verschoben wurde, veranschaulichte/erzwang er Entwurf für Vertrag.

Das heißt, bei der Eingabe ist die Liste ganz und gut gebildet [wenn auch leer]. Bei der Rückgabe ist es entweder leer (wenn die Eingabedatei nicht ist) oder hat nur wohlgeformte/vollständige Datensätze darin.

Im zweiten Programm ist ein partieller/fehlerhafter Eintrag nie verknüpft. Die add_to_list wird immer zuletzt [nur für eine ganze/vollständige Aufzeichnung] durchgeführt.

Also, für beide read_archive und add_new_entries, wenn sie aufgerufen werden, sind sie beide eine vollständige/vollständige Liste mit nur gültige, vollständig ausgeformte Datensätze gegeben. Das ist der "Vertrag" zu sie.

Und um ihren Teil des "Vertrages" zu erfüllen, müssen diese Funktionen die Dinge auf die gleiche Weise verlassen und die Listenintegrität beim Beenden beibehalten. Das ist die Funktion "Vertrag" mit der Außenwelt


UPDATE # 2:

mich entschuldigen für das OT, aber könnten Sie schlagen eine gute IDE für C mir - C++ das funktioniert gut mit Debian/GNU Linux?

Ich bin vielleicht nicht die beste Person, um Sie auf diesem zu beraten, da ich keinen benutze. Ich schrieb C schon lange bevor sie existierten, also habe ich meine eigene Tools-Suite entwickelt, die viel mächtiger ist als jede IDE, die ich gesehen habe. Auch wenn ich sie angeschaut habe, konnte ich niemals einen Weg finden, die beiden miteinander zu verbinden.

Ich bin zu Hause mit Code :: Blocks, aber leider ist die so genannte nächtlichen bauen ist Buggy und stürzt sehr oft

Wenn Sie mit Codeblöcke zu Hause sind, aber die Nightly-Build ist Buggy, vielleicht ist die einfache Lösung, wenn Sie Ihr Update auf den "stabilen" Baum umstellen, wenn das möglich ist. Das ist vielleicht die beste "kurze Antwort".

(das Programm Code-Vervollständigung ist sehr nützlich, aber ich darf nicht str schreiben ..., sonst friert es ein), und das ist sehr frustrierend!

Vielleicht könnten Sie die Fehlerdatenbank überprüfen und sehen, ob die Probleme, die Sie erleben, bekannte Fehlerberichte haben. Wenn nicht, könnten/sollten Sie eine Datei erstellen.


Ich installierte codeblocks. Es sieht sauber und einfach genug aus. Ich habe auch eclipse installiert und einen Blick auf kdevelop geworfen. Von mehreren Webseiten bekommt Eclipse gute Noten, mit netbeans eine enge Sekunde

Ich versuchte, sie auf Quelldatei zu verwenden, die ich herumliegen hatte, das mit einem Makefile aufgebaut wurde. Codeblocks war intuitiv genug, dass ich es schnell umsetzen konnte. Ich hatte mehr Ärger mit den anderen. Eclipse wurde ursprünglich von IBM für den internen Gebrauch entwickelt und dann als öffentlicher Dienst veröffentlicht. Es ist gut unterstützt und ausgereift.

Ich hatte Eclipse läuft ohne CDT, aber sobald ich, dass hinzugefügt, eclipse bekommt meine Stimme, denn es scheint, alle genug Funktionen zu haben, zu kontrollieren, was ich unten ;-) meckern über

Eine IDE ist eine etwas persönliche Wahl [es sei denn, Ihre Firma beauftragt], also sollten Sie verwenden, was Sie möchten. Mit anderen Worten, versuchen Sie einige und sehen Sie, welche Funktionen sie haben und wie sie funktionieren. Hier ist eine Seite, die einige auflistet: https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments

Bei der Auswahl einer IDE müssen Sie sich die "am häufigsten verwendeten" Funktionen ansehen. Am häufigsten wird in der Quelldatei geblättert. Also sollte ein Editor die hjkl Aliasnamen für die Pfeiltasten unterstützen, wie vi tut. Wenn du deine rechte Hand auf die Pfeiltasten und zurück bewegst, verlangsamt sich alles so sehr, dass es kein Ansporn ist.

Eclipse verwendet gvim [grafische vim], das ist also ein Plus.

Ich bin nicht ein Fan der Bearbeitung mit einigen einfachen WYSIWYG-Editor-Bereich, der nur grobe Suche/Ersetzen Funktionen hat. Ebenso ermöglicht Suche regex vim einfach durch / eingeben, also wieder, die häufigsten Operationen „auf Knopfdruck“ sind

Ich benutze keine [noch wollen] Auto-Vervollständigung Funktionen. Wenn ich sie ausprobiert habe, machen sie oft Fehler und es dauert länger, wenn sie das, was sie getan haben, rückgängig machen. Ich bin eine sehr schnelle Schreibkraft.

Ich deaktiviere auch Syntax-Hervorhebung und Einfärbung der Quelle. Beim Eingeben des Quellcodes ändern sich die Farben fast mit jedem eingegebenen Zeichen, was der Editor denkt Ich tippe (zB schreibe ich einen Kommentar, aber es denkt, es ist Code, etc.) Ich habe das gefunden ablenken. Wenn ich auf das Endergebnis schaue, finde ich, dass das eingefärbte Ergebnis "zu beschäftigt" ist (d. H. Mehr Informationen, die ich filtern muss) als etwas, das mir hilft zu sehen, was ich sehen muss.

Ich bin ziemlich hartnäckig über Einrücken, aufbrechen lange Codeblöcke mit leeren Zeilen, um die Lesbarkeit zu verbessern. Und natürlich gute Kommentare. Für mich sind diese viel wichtiger als die Färbung. Ich habe ein benutzerdefiniertes Werkzeug für den Einzug [Wie Sie sich vielleicht erinnern, wurde der Code, als ich ihn oben gepostet hatte, neu eingeordnet, weil ich ihn vor dem Posten durch mein Tool laufen ließ.

Ein weiteres Feature ist der grafische Debugger. Ist es voll ausgestattet? Zum Beispiel ist ddd ein grafischer Wrapper um [das sehr mächtige] gdb.ddd stellt einen grafischen Wrapper und Fenster für allgemeine Dinge zur Verfügung, erlaubt aber immer noch ein direktes Textfenster für die Eingabeaufforderung gdb, so dass Sie die fortgeschritteneren Befehle manuell eingeben können (z. B. watch symbol).

Ist die IDE erweiterbar? Können Sie Plugins hinzufügen? Können Sie einfach Ihre eigenen hinzufügen/erstellen?

Welches Quellcode-Steuerungssystem wird von der IDE verwendet? Ich habe viele über die Jahre verwendet und jetzt bin ich komplett auf git verkauft. Also, wenn die IDE git nicht unterstützt, ist es ein Nicht-Starter.

Es sollte beachtet werden, dass gitso viele Funktionen hat, als sie können nicht in einer GUI enthalten sein. Also, das wirklich mächtige Zeug verwendet ein Befehlszeilentool in einem Terminalfenster.

Meine IDE? Mehrere xterm Fenster, vi, git, und meine Tools-Suite [die derzeit 250.000 Zeilen von perl Skripten enthält ;-)] Erzwingt die IDE, Dinge auf ihre Art zu tun? Wie einfach ist es, Konfigurationen usw. in andere externe Tools und IDEs zu importieren/exportieren?

Ich habe ein sehr leistungsfähiges Build-Skript von meinem eigenen Design. Also, ich würde die IDE wollen, wenn ich auf die Schaltfläche "Build" auf nicht tun, was auch immer es normalerweise tun würde, aber die Kontrolle auf mein Build-Skript umdrehen. Ebenso für beliebige andere Operation die IDE zu bieten hat.

Ist die IDE portabel und auf allen wichtigen Plattformen verfügbar: Linux, OSX und Windows? In der Vergangenheit war das ein weiterer Grund, warum ich mich vor IDEs scheute. Sie wären nur auf einer Plattform verfügbar. Oder, da ich beratend tätig war, ging ich in eine Umgebung, in der die IDE aufgrund der [sysadmin] -Richtlinie nicht installiert/verwendet werden konnte.

+0

Vielen Dank! Du warst so nett. Ich habe nicht so bald ein asnwer erwartet. Natürlich wollte ich das Programm besser mit Funktionen organisieren, aber ich versuchte immer noch, den Grund meines Versagens herauszufinden: Schließlich war das mein erster Versuch, aber ich weiß nicht, ob ich ohne deinen Erfolg Erfolg haben würde Hilfe. Entschuldigung für die italienischen Wörter im Code. Soweit die getch() betrifft, ja, war ihr Zweck nur Debugging. – user241968

+0

Gern geschehen! Eine meiner besten Freunde ist eine Krankenschwester und sie macht eine ähnliche Analyse von Patientenakten, damit ich mich einfühlen kann. Mein Freund ist kein Programmierer und benutzt nur Tabellenkalkulationen usw., also ist es für Sie, als Krankenschwester, Ihr eigenes Programm [in C, nicht weniger] zu schreiben, zu empfehlen. Ich hatte eine Ausschneide-und-Einfügen-Funktion für die Sprache ["Alien" :-)] in Google Translate eingegeben, sodass ich genügend Italienisch lesen konnte, um zu verstehen, was vor sich ging. Ich habe meiner Antwort ein Update hinzugefügt, um die Dinge ein wenig genauer zu erklären. Mach weiter so! –

+0

Zweite Version in 'read_archive', Sie haben' h = fopen (Datei, "w"); '(' "w" '??) –