Это начало простой программы, которая будет хранить пользовательские записи в хеш-таблице. Он все еще очень простой (еще не добавлен связанный список, чтобы справиться со столкновениями, хеш-функция очень проста и является временным заполнителем для более надежной, я еще не занимался освобождением всей памяти malloc'd, и т. д.), но я хочу сначала разобраться с основными функциями, прежде чем идти дальше.
В этой версии моя последняя запись, кажется, перезаписывает предыдущие. Похоже, что записи все еще находятся в правильных местах (как определено хеш-функцией), но каким-то образом последний является тем, который размещается повсюду.
Извините, я знаю, что кода много, но я не уверен, как создать уменьшенную версию этого кода, чтобы изолировать проблему:
#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);
}
Я уверен, что с этим кодом есть другие проблемы, и я благодарен за любой другой совет, который кто-нибудь захочет дать здесь. Например, мне всегда интересно, какие части кода должны быть их собственными функциями, а какие должны / могут быть объединены вместе. Кажется, что некоторые из этих вещей должны быть отделены, но у меня было много проблем, чтобы понять, как правильно передавать информацию от одной функции к другой.
ОБНОВЛЕНИЕ # 1 (после некоторых комментариев):
Да, теперь это работает!
#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);
}