2017-05-23 113 views
0

這裏是我的代碼:Ç - 哈希表不能正常工作

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



    } 

  • 我的代碼工作正常的循環,它的認證 成功,但隨後有時死機,或者我給出相同的 詳細信息(用戶名和密碼),並以某種方式認證失敗的代碼
  • 一部分,我相信它的越野車:

    //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'); 
    

    ,如果我把這意味着運行循環while choice=='y'do..while(choice=='y')停止if choice=='y'這是有點兒奇怪

問題:身份驗證器無法正常工作後第一次嘗試

謝謝很多你的時間!

,在我跳出
+1

建議您使用調試器來跟蹤程序的執行情況並檢查其狀態。這是調試此類問題的最佳方法(不能總是轉向SO來爲您調試)。 – kaylum

+0

我已經嘗試了數週,沒有找到解決方案...我如何使用調試器? – Phill

+0

嘗試使用fgets()而不是scanf()。在最後一個scanf()中,很可能會有一個不需要的換行符被結轉。在最後一個scanf()後面插入這行'fgets(stdin,garbage,sizeof(garbage))'。並聲明'char garbage [50];'。 –

回答

2

幾個問題:

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

你打算爲T是的struct node序列(在這種情況下的T類型是錯誤的),或指針的序列struct node(在這種情況下,參數爲sizeof是錯誤的)?

這將是一個很大清潔劑(和更容易出錯)如果你寫

T = malloc(m * sizeof *T); 

那麼它只是一個決定性的T類型的問題。就個人而言,我希望你可以分配的struct node序列,從而使可能會被宣佈

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

然而,你的代碼的其餘部分似乎真的認爲T是指針的序列struct node,所以在這種情況下,這將是

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

那這個成語的美 - 你需要改變的唯一的事情就是T類型。調用本身不需要改變。如果T的類型是struct node *,則sizeof *T相當於sizeof (struct node)。如果Tstruct node **,則sizeof *T相當於sizeof (struct node *)

然後是這樣的:

initializeHashTable(&(*T)); 

應該真的只是

intializeHashTable(T); 

此外,

while(!feof(fp)) 

永遠是錯的 - feof不會後直到返回true你試圖閱讀過去的結尾該文件,所以你會經常循環一次。您應該檢查與輸入操作,而不是結果:

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

再次,論證&(*T)應該只是T

至於你輸入:

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

fflush調用是不必要在這裏 - 如果有緊隨其後的輸出操作的輸入操作,沖洗是隱含的。

編輯

我不會讓人說我誤解是fflush電話 - 由於某種原因,我讀了爲fflush(stdout),這意味着你要確保在你的輸出被寫入到控制檯呼籲scanf

在輸入流上調用fflush是錯誤的,並且這樣做的行爲是undefined。它不會清除任何未讀輸入的輸入流(MSVC中除外,這是因爲微軟決定編寫現有的不良行爲)。請撥打fflush

結束編輯

scanf呼叫應該是

scanf("%s", name); 

&是不必要此處 - name將隱含地從型轉換 「的char 30個元素的數組」 到「指針char 」。相同的pass

編輯

書面,這些scanf電話是不安全的 - 如果你在一個字符串比目標緩衝時間越長,scanf會很樂意寫這些額外的字符內存緊接的下該緩衝區,導致輸入任何從損壞的數據到seg故障。你需要確保你不會讀太多的字符。你可以做,要麼與字段寬度說明,如

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

或使用fgets

fgets(name, sizeof name, stdin); 

fgets通話將讀取並尾隨換行符,保存到緩衝區,如果有空間,這樣你「會需要做一些額外的工作:

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

如果有緩衝區沒有換行,那麼你將要在下一次讀之前清除輸入流:

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

編輯完

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

您使用了錯誤的格式說明閱讀choice - 你告訴scanf期待一個十進制整數輸入,而不是一個字符。 'y'與格式不匹配,所以scanf實際上沒有從輸入流中讀取它,並且choice未更新。你應該改變它

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

還有很多其他問題,但從這些開始。

+0

'fflush'調用確實*不必要*因爲[**它是錯誤的**](https://stackoverflow.com/questions/9122550/fflushstdin-function -does - 不工作)!人們經常(*錯誤地*)使用'fflush(stdin)'將'stdin'的光標移到下一個換行符(即放棄它,否則'name'將被讀作空白字段)。他們應該使用'scanf(「%* [^ \ n]」); getchar();'代替。 – Sebivor

+0

@Seb:derp。出於某種原因,我正在讀'fflush(stdout);' - 我會解決我的答案的一部分。 –

+0

好。我特別喜歡你使用樂觀循環(期望返回值爲2,而不是像我經常看到的那樣錯誤地期待它不等於'EOF')。我仍然有一些小問題。首先,'scanf(「%29s」,name);'和'fgets(name,sizeof name,stdin)有細微的差別;'因爲它們使用了不同的分隔符集合。你可以用'strcspn'建議(不會)來替換後面的'strchr'建議(當沒有找到新行時,將'NULL'解除引用)。 – Sebivor