【发布时间】:2018-10-31 17:51:17
【问题描述】:
这是一个将用户条目存储在哈希表中的简单程序的开始。它仍然非常基本(尚未添加链表来处理冲突,哈希函数非常简单,并且是更强大的临时占位符,我还没有处理释放所有 malloc 的内存,等),但我想在继续之前先弄清楚基本功能。
在这个版本中,我的最新条目似乎覆盖了以前的条目。看起来条目仍然在正确的位置(由散列函数决定),但不知何故,最后一个是放置在任何地方的那个。
抱歉,我知道代码很多,但我不确定如何创建此代码的较小版本来隔离问题:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE_WORDS 4096
#define BUF_SIZE_NUMBERS 256
#define MAX_WORDS 10
typedef struct tablestruct
{
int val;
char* text;
struct tablestruct *next;
}
table;
// declare the hashing function that takes in the string to be hashed and the length of it
unsigned int hash(char *str, int length);
// // declare a linked list creation function
// lnode *createnode(char *str, htnode *hashtable);
// declare a hash table printing function
void print_ht(table *array[MAX_WORDS]);
int number_input();
int word_input(int num_words, table *array[MAX_WORDS]);
void empty_stdin();
int main(void)
{
// call number_input() to ask user for number of words they'd like to store, save that in word_count
int word_count = number_input();
// create hash table
table *array[MAX_WORDS];
for (int j = 0; j < MAX_WORDS; j++)
{
array[j] = malloc(sizeof(table));
array[j]->val = j;
}
// add some kind of a memory check?
// PUT word_input inside the if statement to make sure it worked?
// call word_input() and store the result in success
int success = word_input(word_count, array);
// if not successful:
if (!success)
{
fputs ("some kind of problem with word_input\n", stderr);
return 1;
}
// printf("\ncurrent address of the hash table: %p\n", &array[0]);
printf("printing hash table: \n");
print_ht(array);
// REMEMBER TO FREE WHATEVER'S MALLOC'ED
}
int number_input(void)
{
// a bunch of code is borrowed from David's answer here: https://stackoverflow.com/questions/52920852/why-is-the-following-code-not-allowing-me-to-get-user-input-with-fgets-yet-works?noredirect=1#comment92940817_52920852
int num_words = 0, /* number of words to enter */
word_count_check = 0; /* word count */
char buffer[BUF_SIZE_NUMBERS] = ""; /* buffer of sufficient size for input */
for (;;) /* loop continually until valid input of NUMBER OF WORDS USER WANTS TO ENTER or user cancels */
{
printf ("how many words would you like to enter? [1-%d]: ", MAX_WORDS);
// check for cancellation of input
if (!fgets (buffer, BUF_SIZE_NUMBERS, stdin))
{
fputs ("user canceled input\n", stderr);
return 1;
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a value\n");
continue;
}
size_t inlength = strlen(buffer);
if (inlength && buffer[inlength - 1] == '\n')
{
// printf("hurray!\n");
buffer[--inlength] = 0;
}
else if (inlength == BUF_SIZE_NUMBERS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_NUMBERS);
empty_stdin();
// continue;
}
// make sure user actually entered a proper int
if (sscanf (buffer, "%d", &num_words) != 1) /* sscanf is used for conversion */
{
fputs ("invalid conversion to int; please provide valid input\n", stderr);
continue;
}
// check if the number entered is out of range
if (num_words < 1 || num_words > MAX_WORDS)
fprintf (stderr, "%2d out of valid range.\n", num_words);
else
break; /*if the input has been validated, we can now break out of the for loop */
}
return(num_words);
}
int word_input(int num_words, table *array[MAX_WORDS])
{
int word_count = 0;
for(;;) /* loop until word_count == num_words is achieved */
{
// declare an array for storing input string
char buffer[BUF_SIZE_WORDS];
char valid_input[BUF_SIZE_WORDS];
// prompt user for input
printf("\nplease enter a string: ");
// get input and check for CTRL+D
if (!fgets(buffer, BUF_SIZE_WORDS, stdin))
{
fputs ("user canceled input\n", stderr);
exit(1);
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a word that's more than 0 characters\n");
// empty_stdin();
continue;
}
size_t inlength = strlen(buffer);
if (inlength && buffer[inlength - 1] == '\n')
{
buffer[--inlength] = 0;
// get rid of trailing spaces using sscanf
sscanf(buffer, "%s", valid_input);
inlength = strlen(valid_input);
printf("string length: %zu\n", inlength);
// call the hash function to get the hash code
int result = hash(&valid_input[0], inlength);
table *newnode = malloc(sizeof(table));
// store the current string in the newnode->text
newnode->text = valid_input;
// strcpy(newnode->text, valid_input); ??
// newnode->val = inlength;
// confirm string has been stored
printf("you've entered: %s\n", newnode->text);
// attach the node to correct slot in the hash table -- ADD LINKED LIST FUNCTIONALITY HERE TO DEAL WITH COLLISIONS!
array[result]->next = newnode;
// printf("address of the current HT entry is: %p\n", newnode);
// increment word count
word_count++;
printf("word_count = %i\n", word_count);
if (word_count == num_words)
{
printf("\nDONE!\n\n");
return word_count;
}
}
// check if the user entered too many characters
else if (inlength == BUF_SIZE_WORDS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_WORDS);
empty_stdin();
}
}
// return word_count;
}
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
// THIS HASH FUNCTION IS TOO BASIC AND NEEDS TO BE REPLACED WITH SOMETHING BETTER
unsigned int hash(char *str, int length)
{
int sum = 0;
for (int j = 0; j < length; j++)
{
sum += str[j];
}
printf("here's what the hashing function is returning: %i\n", (sum % MAX_WORDS));
return sum % MAX_WORDS;
}
void print_ht(table *array[MAX_WORDS])
{
// printf("address of the hash table inside print function: %p\n\n", array);
table *cursor = malloc(sizeof(table));
// add memory check
for (int i = 0; i < MAX_WORDS; i++)
{
printf("[%i] -> ", i);
cursor = array[i];
if (cursor->next)
{
table *temp = malloc(sizeof(table));
temp = cursor->next;
printf("%s\n", temp->text);
free(temp);
}
else
{
printf("empty\n");
}
}
free(cursor);
}
我确信这段代码还有其他问题,我感谢任何人愿意在这里提供的任何其他建议。例如,我总是想知道代码的哪些部分需要是它们自己的函数,哪些应该/可以组合在一起。似乎这些东西中的一些应该被分离出来,但我在弄清楚如何正确地将信息从一个函数传递到另一个函数时遇到了很多麻烦。
UPDATE #1(在一些 cmets 之后):
是的,现在可以使用了!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE_WORDS 4096
#define BUF_SIZE_NUMBERS 256
#define MAX_WORDS 10
typedef struct tablestruct
{
int val;
char* text;
struct tablestruct *next;
}
table;
// declare the hashing function that takes in the string to be hashed and the length of it
unsigned int hash(char *str, int length);
// // declare a linked list creation function
// lnode *createnode(char *str, htnode *hashtable);
// declare a hash table printing function
void print_ht(table *array[MAX_WORDS]);
int number_input();
int word_input(int num_words, table *array[MAX_WORDS]);
void empty_stdin();
int main(void)
{
// call number_input() to ask user for number of words they'd like to store, save that in word_count
int word_count = number_input();
// create hash table
table *array[MAX_WORDS];
for (int j = 0; j < MAX_WORDS; j++)
{
array[j] = malloc(sizeof(table));
array[j]->val = j;
}
// add some kind of a memory check?
// PUT word_input inside the if statement to make sure it worked?
// call word_input() and store the result in success
int success = word_input(word_count, array);
// if not successful:
if (!success)
{
fputs ("some kind of problem with word_input\n", stderr);
return 1;
}
// printf("\ncurrent address of the hash table: %p\n", &array[0]);
printf("printing hash table: \n");
print_ht(array);
// REMEMBER TO FREE WHATEVER'S MALLOC'ED
}
int number_input(void)
{
// a bunch of code is borrowed from David's answer here: https://stackoverflow.com/questions/52920852/why-is-the-following-code-not-allowing-me-to-get-user-input-with-fgets-yet-works?noredirect=1#comment92940817_52920852
int num_words = 0, /* number of words to enter */
word_count_check = 0; /* word count */
char buffer[BUF_SIZE_NUMBERS] = ""; /* buffer of sufficient size for input */
for (;;) /* loop continually until valid input of NUMBER OF WORDS USER WANTS TO ENTER or user cancels */
{
printf ("how many words would you like to enter? [1-%d]: ", MAX_WORDS);
// check for cancellation of input
if (!fgets (buffer, BUF_SIZE_NUMBERS, stdin))
{
fputs ("user canceled input\n", stderr);
return 1;
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a value\n");
continue;
}
size_t inlength = strlen(buffer);
if (inlength && buffer[inlength - 1] == '\n')
{
// printf("hurray!\n");
buffer[--inlength] = 0;
}
else if (inlength == BUF_SIZE_NUMBERS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_NUMBERS);
empty_stdin();
// continue;
}
// make sure user actually entered a proper int
if (sscanf (buffer, "%d", &num_words) != 1) /* sscanf is used for conversion */
{
fputs ("invalid conversion to int; please provide valid input\n", stderr);
continue;
}
// check if the number entered is out of range
if (num_words < 1 || num_words > MAX_WORDS)
fprintf (stderr, "%2d out of valid range.\n", num_words);
else
break; /*if the input has been validated, we can now break out of the for loop */
}
return(num_words);
}
int word_input(int num_words, table *array[MAX_WORDS])
{
int word_count = 0;
for(;;) /* loop until word_count == num_words is achieved */
{
// declare an array for storing input string
char buffer[BUF_SIZE_WORDS];
char valid_input[BUF_SIZE_WORDS];
// prompt user for input
printf("\nplease enter a string: ");
// get input and check for CTRL+D
if (!fgets(buffer, BUF_SIZE_WORDS, stdin))
{
fputs ("user canceled input\n", stderr);
exit(1);
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a word that's more than 0 characters\n");
// empty_stdin();
continue;
}
size_t inlength = strlen(buffer);
if (inlength && buffer[inlength - 1] == '\n')
{
buffer[--inlength] = 0;
// get rid of trailing spaces using sscanf
sscanf(buffer, "%s", valid_input);
inlength = strlen(valid_input);
printf("string length: %zu\n", inlength);
// call the hash function to get the hash code
int result = hash(&valid_input[0], inlength);
table *newnode = malloc(sizeof(table));
newnode->text = malloc(strlen(valid_input)+1);
strcpy(newnode->text, valid_input);
// confirm string has been stored
printf("you've entered: %s\n", newnode->text);
// attach the node to correct slot in the hash table -- ADD LINKED LIST FUNCTIONALITY HERE TO DEAL WITH COLLISIONS!
array[result]->next = newnode;
// printf("address of the current HT entry is: %p\n", newnode);
// increment word count
word_count++;
printf("word_count = %i\n", word_count);
if (word_count == num_words)
{
printf("\nDONE!\n\n");
return word_count;
}
}
// check if the user entered too many characters
else if (inlength == BUF_SIZE_WORDS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_WORDS);
empty_stdin();
}
}
// return word_count;
}
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
// THIS HASH FUNCTION IS TOO BASIC AND NEEDS TO BE REPLACED WITH SOMETHING BETTER
unsigned int hash(char *str, int length)
{
int sum = 0;
for (int j = 0; j < length; j++)
{
sum += str[j];
}
printf("here's what the hashing function is returning: %i\n", (sum % MAX_WORDS));
return sum % MAX_WORDS;
}
void print_ht(table *array[MAX_WORDS])
{
// printf("address of the hash table inside print function: %p\n\n", array);
table *cursor; // = malloc(sizeof(table));
// add memory check
for (int i = 0; i < MAX_WORDS; i++)
{
printf("[%i] -> ", i);
cursor = array[i];
if (cursor->next)
{
table *temp; //= malloc(sizeof(table));
temp = cursor->next;
printf("%s\n", temp->text);
// free(temp);
}
else
{
printf("empty\n");
}
}
// free(cursor);
}
【问题讨论】:
-
这段代码有很多问题:-/但主要问题在于 print_ht,为什么你要在一个只应该打印已经存在的东西的函数中 malloc'ing ANYTHING?跨度>
-
这是因为您创建的哈希表条目包含指向自动存储类变量的指针。
newnode->text = valid_input;但valid_input被定义为局部变量char valid_input[BUF_SIZE_WORDS];。newnode->text应该指向从堆分配的内存。 -
这与这里的问题基本相同:stackoverflow.com/a/50591226/10396
-
如果你有
strdup功能可用,你可以做newnode->text = strdup(valid_input);。否则,newnode->text = malloc(strlen(valid_input)+1); strcpy(newnode->text, valid_input);. -
又到了一年中的这个时候,在这里我们可以观察到
something = malloc(...); something = somethingelse;在其自然栖息地的壮丽标本。该物种在科学上被称为 Monstratorem quaeque,因其强大的繁殖周期和丰富的猎物而被归类为“最不值得关注的物种”。