2017-05-23 8 views
0

Hier ist mein Code:C - Hashtable funktioniert nicht richtig

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#define m 9 



int flag1=1; 
//Creating memory for username and password 
struct node // The list that is being used to store username and password 
{ 
    char username[30]; 
    char password[30]; 
    struct node *next; 
}; 

int getkey(char[30]); //a method to get "randomly" a key 
int hash(int); // a method to create the hashcode 
void insert(struct node **,char[30],char[30]); //adding a node struct to a specific possition in hashtable 
void initializeHashTable(struct node **); 
void search(struct node **,char[30]);//check if password exists 
void searchuser(struct node **,char[30]); //check if username exists 
void print(struct node**);//printing the hashtable 

void print(struct node **T) 
{ 
    struct node *tmp; 
    int i,flag=0; 
    printf("-------Data Base-------\n"); 
    for(i=0;i<m;i++) 
    { 
     tmp=*(T+i); 
     while(tmp!=NULL) 
     { 
      printf("Username: %s Password: %s\n",tmp->username,tmp->password); 
      tmp=tmp->next; 
     } 

    } 
} 
void search(struct node **T,char password[30]) 
{ 
    struct node *tmp; 
    int i,flag=0; 
    for(i=0; i<m; i++) 
    { 
     tmp=*(T+i); 
     while(tmp!=NULL) 
     { 
      if(strcmp(tmp->password,password)==0) 
      { 
       flag=1; 
       break; 
      } 
      tmp=tmp->next; 

     } 
     if(flag==1) 
      break; 

    } 
    if(flag==1) 
     printf("Authentication Successfull\n"); 
    else 
     printf("Authentication Failed\n"); 

} 

void searchuser(struct node **T,char user[30]) 
{ 
    struct node *tmp; 
    int i,flag=0; 
    for(i=0; i<m; i++) 
    { 
     tmp=*(T+i); 
     while(tmp!=NULL) 
     { 
      if(strcmp(tmp->username,user)==0) 
      { 
       flag=1; 
       break; 
      } 
      tmp=tmp->next; 

     } 
     if(flag==1) 
      break; 

    } 
    if(flag==0) 
     { 
      printf("Username NOT Found\n"); 
      flag1=0; 

     } 
} 

void initializeHashTable(struct node **T) 
{ 
    int i; 
    for (i=0; i<m; i++) 
     *(T+i)=NULL; 

} 
int getkey(char name[30]) 
{ 


    int i=0; 
    int key=0; 
    for (i=0; i<15; i++) 
    { 
     key+=name[i]; 

    } 
    return key; 

} 

int hash(int key) 
{ 
    return key%m; 
} 

void insert (struct node **T,char name[30],char password[30]) 
{ 

    struct node *newnode; 
    newnode=(struct node*)malloc(sizeof(struct node)); 
    strcpy(newnode->username,name); 
    strcpy(newnode->password,password); 
    int key; 
    key=getkey(name); 
    int hashcode; 
    hashcode=hash(key); 
    //printf("Key:%d\n",key); 
    // printf("Hashcode:%d\n",hashcode); 

    if(*T+hashcode==NULL) 
    { 
     (*(T+hashcode))->next=newnode; 
     newnode->next=NULL; 
    } 
    else 
    { 

     newnode->next=(*(T+hashcode)); 
     (*(T+hashcode))=newnode; 
    } 



} 



int main() 
{//possible content of file: phill 1234 
    char choice; 
    struct node **T; 
    struct node **head; 
    head==NULL; 
    T=(struct node**)malloc(m*sizeof(struct node));//creating the hashmap 
    FILE *fp; 
    char name[30]; 
    char pass[30]; 

    fp=fopen("passwords.txt","r"); 

    if (fp==NULL) 
    { 
     printf("File Not Found"); 
     return 0; 
    } 
    else 
    { 
     initializeHashTable(&(*T)); 
     while(!feof(fp)) // end of file 
     { 
      fscanf(fp,"%s %s",name,pass); //reads until first wild space, 
      //one each loop, you get 1 username and 1 password from the file 
      //adding them on hashmap 
      insert(&(*T),name,pass); 


     } 
    } 

    //user authentication 
    do{ 

     printf("Enter Username:\n"); 
     fflush(stdin); 
     scanf("%s",&name); 
     searchuser(&(*T),name); 
     if(flag1==1) 
     { 
     printf("Enter Password:\n"); 
     scanf("%s",&pass); 
     search(&(*T),pass); 

     } 
     printf("Try Again? (y/n)\n"); 
     fflush(stdin); 
     scanf("%d",&choice); 
    }while(choice!='y'); 

    free(T); 
    free(fp); 
    free(head); 



    } 

  • Mein Code funktioniert auf der Schleife in Ordnung, es funktioniert die Authentifizierung erfolgreich, aber dann manchmal stürzt, oder i gibt den gleichen Details (Benutzername und Passwort) und irgendwie die Authentifizierung fehl
  • Teil des Codes, die ich seinen Buggy glauben:

    //user authentication 
        do{ 
        printf("Enter Username:\n"); 
        fflush(stdin); 
        scanf("%s",&name); 
        searchuser(&(*T),name); 
        if(flag1==1) 
        { 
        printf("Enter Password:\n"); 
        scanf("%s",&pass); 
        search(&(*T),pass); 
    
        } 
        printf("Try Again? (y/n)\n"); 
        fflush(stdin); 
        scanf("%d",&choice); 
    }while(choice!='y'); 
    

    wenn ich do..while(choice=='y') setzen die while choice=='y' die Schleife laufen Mittel stoppt es if choice=='y' die

Ausgabe ein bisschen seltsam ist: Authenticator nach dem 1. nicht richtig funktioniert versuchen

Thanks A Los für deine Zeit!

+1

Schlagen Sie vor, dass Sie einen Debugger verwenden, um die Ausführung Ihres Programms zu verfolgen und seinen Status zu überprüfen. Das ist der beste Weg, um solche Probleme zu debuggen (man kann sich nicht immer an SO wenden, um für Sie zu debuggen). – kaylum

+0

Ich habe seit Wochen versucht, habe keine Lösung gefunden ... wie kann ich einen Debugger verwenden? – Phill

+0

Versuchen Sie, fgets() anstelle von scanf() zu verwenden. Auf der letzten scanf() gibt es eine gute Möglichkeit, dass ein unerwünschter Zeilenumbruch-Char, der übertragen wurde. Fügen Sie diese Zeile 'fgets (stdin, marble, sizeof (marble))' nach dem letzten scanf() ein. und deklariere 'char Müll [50];'. –

Antwort

2

Mehrere Probleme, die mich herausspringen:

struct node **T; 
... 
T=(struct node**)malloc(m*sizeof(struct node)); 

Haben Sie für T beabsichtigen, eine Folge von struct node zu sein (in diesem Fall die Art der T falsch ist), oder eine Folge von Zeiger zu struct node (in diesem Fall ist das Argument zu sizeof falsch)?

Es wäre viel sauberer (und viel weniger fehleranfällig), wenn Sie

T = malloc(m * sizeof *T); 

dann ist es nur eine Frage der Entscheidung, welche Art von T schrieben. Persönlich würde ich erwarten, dass Sie eine Folge von struct node werden Zuteilung, so dass wahrscheinlich

struct node *T = malloc( m * sizeof *T); 

jedoch erklärt werden würde, der Rest des Codes scheint wirklich davon ausgehen, dass T ist eine Folge von Zeigern auf struct node, so in daß Fall, dass

struct node **T = malloc(m * sizeof *T); 

das ist die Schönheit dieses Idiom sein würde - das einzige, was Sie ändern müssen die Art der T ist. Der Anruf malloc selbst muss nicht geändert werden. Wenn der Typ Tstruct node * ist, entspricht sizeof *Tsizeof (struct node). Wenn Tstruct node ** ist, entspricht sizeof *Tsizeof (struct node *).

Dann gibt es noch das:

initializeHashTable(&(*T)); 

die sollte wirklich nur

sein
intializeHashTable(T); 

Auch

while(!feof(fp)) 

ist immer falsch - feof wird nicht wahr zurück, bis nach Sie versuchen, über das Ende von zu lesen die Datei, so dass Sie einmal zu oft Loopings durchführen. Sie sollten prüfen, gegen das Ergebnis des Eingabevorganges statt:

while (fscanf(fp,"%s %s",name,pass) == 2) 
{ 
    insert(T,name,pass); 
} 

Auch das Argument &(*T) sollte nur T sein.

Wie für Ihre Eingabe:

printf("Enter Username:\n"); 
fflush(stdin); 
scanf("%s",&name); 

Der fflush Anruf ist hier nicht notwendig - wenn es ein Eingabevorgang sofort eine Ausgabeoperation folgt, ein Flush impliziert.

bearbeiten

ich embarrased bin zu sagen, dass ich falsch verstanden, dass fflush Anruf - aus irgendeinem Grund habe ich gelesen, dass als fflush(stdout), das heißt, Sie sicherstellen möchten, würde die Ausgabe an die Konsole geschrieben wurde, bevor Rufen scanf.

Aufruf fflush auf einem Eingangsstrom ist falsch, und das Verhalten so zu tun, ist undefined. Der Eingabestream von ungelesenen Eingaben wird nicht gelöscht (mit Ausnahme von MSVC, und das liegt daran, dass Microsoft entschieden hat, bestehendes schlechtes Verhalten zu kodifizieren).

Verlieren Sie den fflush Anruf insgesamt.

Ende bearbeiten

Der scanf Anruf

scanf("%s", name); 

Die & ist hier nicht notwendig sein sollte - name implizit vom Typ "Array 30-Element von char" umgewandelt werden zu „Zeiger auf char ". Das Gleiche gilt für pass.

bearbeiten

Wie geschrieben, diese scanf Anrufe sind unsicher - wenn Sie in einer Zeichenfolge eingeben, der länger ist als der Zielpuffer, wird scanf glücklich, diese zusätzlichen Zeichen in den Speicher schreiben sofort nach diesem Puffer, was zu alles von beschädigten Daten bis zu einem seg-Fehler. Sie müssen sicherstellen, dass Sie nicht zu viele Zeichen lesen.Sie können tun, dass entweder mit einem Feld Breitenbezeichner, wie

scanf("%29s", name); // leave at least one element for the 0 terminator 

oder verwenden fgets:

fgets(name, sizeof name, stdin); 

Der fgets Anruf wird an den Puffer der Newline lesen und speichern, wenn es Raum, so dass Sie ‚ll müssen einige zusätzliche Arbeit tun:

char *newline = strchr(name, '\n'); 
if (*newline) 
    *newline = 0; 

Wenn kein newline im Puffer ist, dann werden Sie den Eingangsstrom vor dem nächsten Lese löschen möchten:

while (getchar() != '\n') 
    ; // empty loop 

Ende bearbeiten

scanf("%d",&choice); 
}while(choice!='y'); 

Sie das falsche Formatbezeich mit choice zu lesen - Sie scanf erzählen eine ganze Dezimalzahl Eingang zu erwarten ist, ist kein Zeichen. 'y' stimmt nicht mit dem Format überein, so scanf liest es nicht tatsächlich aus dem Eingabestream und choice wird nicht aktualisiert. Sie sollten, dass

choice = getchar(); 
} while (choice != 'y'); 

ändern Es gibt viele andere Fragen sind, aber mit denen beginnen.

+0

Der 'fflush' Aufruf dort ist in der Tat * unnötig * weil [** es ist fehlerhaft **] (https://stackoverflow.com/questions/9122550/fflushstdin-function -funktioniert nicht)! Leute benutzen oft (* fälschlicherweise *) 'fflush (stdin)', um den Cursor für 'stdin' zum nächsten Newline zu bringen (d. H., Um ihn zu verwerfen, weil sonst 'name' als leeres Feld gelesen würde); Sie sollten etwas wie 'scanf ("% * [^ \ n] ") verwenden; getchar(); 'stattdessen. – Sebivor

+0

@Seb: derp. Aus irgendeinem Grund las ich das als 'fflush (stdout);' - Ich werde diesen Teil meiner Antwort fixieren. –

+0

Gut. Ich liebe besonders, dass Sie die optimistische Schleife verwenden (erwarten Sie, dass der Rückgabewert 2 ist, anstatt fälschlicherweise zu erwarten, dass sie ungleich "EOF" ist, wie ich so oft sehe). Ich habe noch ein paar kleine Probleme damit. Erstens, 'scanf ("% 29s ", name);" tut etwas, das sich subtil von 'fgets (name, sizeof name, stdin) unterscheidet;' da sie unterschiedliche Mengen von Begrenzern verwenden. Sie können den folgenden 'strchr'-Hinweis (der" NULL "dereferenziert, wenn kein Zeilenumbruch gefunden wird) durch' strcspn' ersetzen (was nicht der Fall wäre). – Sebivor