C-Programm Banksystem mit Hashtabelle (Hashtabelle mit Überlaufliste)
-
Hallo ,
ich studiere zZ Wirtschaftsinformatik und habe die Aufgabe ein interaktives Banksystem zu programmieren. Dieses muss verschiedene Funktionen besitzen, wie zb. anmelden, abmelden, Kunden erstellen (mit 10 stelliger Kontonr. und 4 stelligem Pin) usw.. Dies war alles kein Problem. Ich gehe von max. 100 Kunden aus. In der Aufgabenstellung steht desweiteren :
Es muss eine Hashtabelle mit Überlaufliste zur Verwaltung der Kunden implementiert werden.
Leider hatten wir das Thema sowohl in der Vorlesung als auch in der Übung/im Praktikum nur wenig bis garnicht behandelt.
Kann mir vllt. jemand weiterhelfen und mir sagen, wie ich vorzugehen habe, da ich im Internet zwar einiges über Hashing gefunden habe, es jedoch leider einfach nicht wirklich verstehe.
Vielen Dank im Voraus.
MfG Marcel
-
Dann präsentiere erstmal das was du schon hast und die Stellen, an der du die Hashtabelle jeweils einsetzen willst.
-
Für mein Beispiel habe ich ein Struct erstellt das wie folgt aussieht :
struct Kundendaten {
int Kontonummer;
int Pin;
float Guthaben;
int Eingabe;
int deleted;
};Diese Daten werden dann mittels struct Kundendaten Kontodaten[100] = { 0, 0, 0, 0, 0 }; in einem Array angelegt.
Um auf die einzelnen Kunden zugreifen zu können , würde ich jetzt an eine Hashtabelle bzgl. der Kontonummer denken. Jedoch kann ich mir nicht erklären wie das funktionieren soll. Finde im Netz zwar viele Seiten die es erklären, jedoch kaum ähnlich beispiele, die ich bräuchte um es zu verstehen.
Mfg
-
Namen haben deine Kunden nicht?
Die (für ein Bankprogramm) sowieso schon eindeutige Kontonummer als Schlüssel zu nehmen, macht keinen Spaß.
Definiere wenigstens mal, welche Aktionen du für deine Anwendung bzgl. der Hashtable brauchst.
-
Als Aktionen soll das Programm :
1. Erstelen einer 10stellg. Kontonr. + 4stllg. Pin
2. An und Abmelden
3. Konto sperren bei 3*maliger falschen Pineingabe
4. Geld ein,auszahlen sowie auf anderes Konto überweißen
5. Konto löschen
6. Pin ändern
enthalten.Mein Programm ist bereits fertig und man kann alle diese Aktionen ausführen, jedoch halt ohne Verwendung einer Hashfunktion/tabelle.
-
Eine ganz einfache Implementierung,
das ganze Hash-Zeugs gehört in ein eigenes Modul, und die Schnittstelle dazu habe ich mal selbst vergeben, da du ja nicht dazu in der Lage warst.
Funktionen wie Löschen einzelner Elemente, Dubletten-Handling, Ändern von Elementen, Speicher-Errorhandling usw. kannst du nach dem Muster ergänzen, die Hashfunktion verbessern usw.
Der Hashkey ist die Kontonummer als String, die Hashtablegröße ist anpassbar.
Normalerweise passt eine Kontonummer nicht in int, und die neue IBAN auch nicht in unsigned long long.#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { long long Kontonummer; int Pin; float Guthaben; int Eingabe; int deleted; } Kundendaten; /*************************************************************************/ /* hash.c */ enum { HTS = 200 }; /* 100 Datensätze, d.h. möglichst mehr Einträge vorsehen */ typedef struct { int s; char (*knr)[99]; Kundendaten *kl; } Hte; typedef struct { Hte liste[HTS]; } Ht; static unsigned long hash(const char *k) { /* einfache Hashfunktion für Kontonummer als String */ unsigned long c, r = 5381; while (c = *k++) { r = ((r << 5) + r) + c; } return r; } void *ht_get(void *t,const char*key) { Ht *ht = t; Hte e = ht->liste[hash(key) % HTS]; /* wichtig zum Verständnis von Hashtables */ { int i; for (i = 0; i < e.s; ++i) if (!strcmp(key, e.knr[i])) return &e.kl[i]; } return 0; } void ht_put(void *t, const char *key, Kundendaten k) { Ht *ht = t; Hte *e = &ht->liste[hash(key) % HTS]; e->kl = realloc(e->kl, (e->s + 1)*sizeof*e->kl); e->knr = realloc(e->knr, ++e->s*sizeof*e->knr); strcpy(e->knr[e->s - 1], key); memcpy(&e->kl[e->s - 1], &k, sizeof k); } void ht_free(void*t) { Ht *h = t; int i; for (i = 0; i < HTS; ++i) { Hte e = h->liste[i]; free(e.knr); free(e.kl); } free(t); } void *ht_new(void) { return calloc(HTS, sizeof(Ht)); } void ht_printall(void *t, FILE*f, void (*pr)(Kundendaten, FILE *)) { Ht *h = t; int i; for (i = 0; i < HTS; ++i) { Hte e = h->liste[i]; while (e.s--) pr(e.kl[e.s],f); } } /* hash.c Ende */ /*************************************************************************/ const char *kontostr(Kundendaten k) { static char s[99]; sprintf(s, "%lld", k.Kontonummer); return s; } void k_out(Kundendaten k, FILE *f) { /* Callback zur Ausgabe 1x Kunde */ fprintf(f, "\n%lld : %d : %f : %d : %d", k.Kontonummer, k.Pin, k.Guthaben, k.Eingabe, k.deleted); } int main() { void *ht = ht_new(); /* anonymer void Zeiger für Hashtable-Objekt, der Aufrufer braucht die Interna nicht wissen */ Kundendaten k1 = { 12345678900, 4711, 1000., 100, 1 }; Kundendaten k2 = { 12345678902, 4713, 1002., 888, 0 }; Kundendaten k3 = { 12345678904, 4715, 1004., 0, 0 }; ht_printall(ht, stdout, k_out); ht_put(ht, kontostr(k1), k1); ht_printall(ht, stdout, k_out); ht_put(ht, kontostr(k2), k2); ht_printall(ht, stdout, k_out); ht_put(ht, kontostr(k3), k3); ht_printall(ht, stdout, k_out); ht_put(ht, kontostr(k2), k2); ht_printall(ht, stdout, k_out); { Kundendaten *k = ht_get(ht, kontostr(k2)); puts("\nKunde k2"); k_out(*k, stdout); } ht_free(ht); return 0; }
-
Noch eine kleine Sache:
Ich weiß nicht, ob das mit dem
float
hier so die richtige Sache ist. Je größer die Beträge werden, desto mehr Genauigkeit büßt du ein. Eindouble
oderlong double
wäre angebrachter.Aber bei einer richtigen Bankensoftware würde ich das so auch nicht implementieren wollen und stattdessen auf BCDs ausweichen. Ja, das ist erheblich mehr Aufwand. Ja, in deiner Übrungsaufgabe wird das nicht verlangt werden. Und ja, eventuell wird man in der Realität auch darauf verzichten. Ich haben noch keine solche Software geschrieben, die derart genau sein musste.
Aber wenn ich jemals sowas schreiben würde, vermutlich würde ich es so machen (aber ich hebe auch meine Musik in lossless auf :D). Meint auch die Wikipedia übrigens:
Wikipedia schrieb:
BCD-Arithmetik wird heutzutage nur noch selten angewendet, da sie den Speicher verschwenderisch nutzt und gegenüber den 32-bit-Gleitkommazahlen nur wenige Vorteile bzgl. Genauigkeit liefert. Allerdings benötigen Großbanken immer noch eine Genauigkeit, welche über die Gleitkommadarstellung hinausgeht. Daher verwenden Großrechner das Densely Packed Decimal Encoding.
Quelle. Vielleicht kannste damit auch den Prof beeindrucken, und selbst wenn nicht, hast du heute wenigstens davon mal gehört.
-
Vielen Dank für den Quellcode.
Dann werde ich mich da mal reinfuchsen.Lg