C - 哈希表不能正常工作
C - Hashtable Doesn't Work Properly
这是我的代码:
#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');
如果我输入 do..while(choice=='y')
这意味着 运行 循环 while choice=='y'
它停止 if choice=='y'
这有点奇怪
Issue: Authenticator doesn't work properly after 1st try
非常感谢您的宝贵时间!
我突然想到的几个问题:
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
的类型。 malloc
调用本身不需要更改。如果T
的类型是struct node *
,那么sizeof *T
就等同于sizeof (struct node)
。如果 T
是 struct node **
,那么 sizeof *T
就等同于 sizeof (struct node *)
。
然后是这个:
initializeHashTable(&(*T));
实际上应该是
intializeHashTable( T );
此外,
while(!feof(fp))
总是错误的 - feof
不会 return 为真,直到 之后 你试图读取文件末尾,所以你会结束循环一次太频繁了。您应该检查输入操作的结果:
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
是错误的,这样做的行为是 未定义。它不会清除任何未读输入的输入流(在 MSVC 中除外,这是因为 Microsoft 决定将现有的不良行为编纂成法典)。
完全失去 fflush
调用。
结束编辑
scanf
调用应该是
scanf( "%s", name );
此处不需要 &
- name
将从类型“char
的 30 元素数组”隐式转换为 "pointer to char
"。 pass
也一样。
编辑
正如所写,这些 scanf
调用是不安全的 - 如果您输入的字符串比目标缓冲区长,scanf
会很乐意将这些额外的字符写入紧跟该缓冲区的内存中,导致从损坏的数据到段错误的任何事情。你需要确保你没有读到太多的字符。您可以使用字段宽度说明符来做到这一点,例如
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' );
还有很多其他问题,但从这些开始。
这是我的代码:
#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');
如果我输入
do..while(choice=='y')
这意味着 运行 循环while choice=='y'
它停止if choice=='y'
这有点奇怪
Issue: Authenticator doesn't work properly after 1st try
非常感谢您的宝贵时间!
我突然想到的几个问题:
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
的类型。 malloc
调用本身不需要更改。如果T
的类型是struct node *
,那么sizeof *T
就等同于sizeof (struct node)
。如果 T
是 struct node **
,那么 sizeof *T
就等同于 sizeof (struct node *)
。
然后是这个:
initializeHashTable(&(*T));
实际上应该是
intializeHashTable( T );
此外,
while(!feof(fp))
总是错误的 - feof
不会 return 为真,直到 之后 你试图读取文件末尾,所以你会结束循环一次太频繁了。您应该检查输入操作的结果:
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
是错误的,这样做的行为是 未定义。它不会清除任何未读输入的输入流(在 MSVC 中除外,这是因为 Microsoft 决定将现有的不良行为编纂成法典)。
完全失去 fflush
调用。
结束编辑
scanf
调用应该是
scanf( "%s", name );
此处不需要 &
- name
将从类型“char
的 30 元素数组”隐式转换为 "pointer to char
"。 pass
也一样。
编辑
正如所写,这些 scanf
调用是不安全的 - 如果您输入的字符串比目标缓冲区长,scanf
会很乐意将这些额外的字符写入紧跟该缓冲区的内存中,导致从损坏的数据到段错误的任何事情。你需要确保你没有读到太多的字符。您可以使用字段宽度说明符来做到这一点,例如
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' );
还有很多其他问题,但从这些开始。