Nano Hash - криптовалюты, майнинг, программирование

Почему моя функция печати перезаписывает предыдущие записи последней записью в следующем коде?

Это начало простой программы, которая будет хранить пользовательские записи в хеш-таблице. Это все еще очень просто (еще не добавил связанный список для обработки коллизий, хеш-функция очень проста и является временным заполнителем для более надежной, я еще не имел дело с освобождением всей памяти 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);
}

Я уверен, что с этим кодом есть и другие проблемы, и я ценю любые другие советы, которые кто-либо захочет дать здесь. Например, мне всегда интересно, какие части кода должны быть отдельными функциями, а какие следует/можно комбинировать вместе. Кажется, что некоторые из этих вещей должны быть отделены, но у меня было много проблем с выяснением того, как правильно передавать информацию из одной функции в другую.

ОБНОВЛЕНИЕ №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);
}
31.10.2018

  • С этим кодом так много проблем :-/, но главная проблема заключается в print_ht, почему вы выделяете ЧТО-НИБУДЬ в функции, которая должна печатать только то, что уже есть? 31.10.2018
  • Это связано с тем, что создаваемые вами записи хэш-таблицы содержат указатели, указывающие на автоматические переменные класса хранения. newnode->text = valid_input;, но valid_input определяется как локальная переменная char valid_input[BUF_SIZE_WORDS];. newnode->text должен указывать на память, выделенную из кучи. 31.10.2018
  • По сути, это та же проблема, что и здесь: stackoverflow.com/a/50591226/10396 31.10.2018
  • Если у вас есть функция strdup, вы можете сделать newnode->text = strdup(valid_input);. В противном случае newnode->text = malloc(strlen(valid_input)+1); strcpy(newnode->text, valid_input);. 31.10.2018
  • Снова это время года, и здесь мы можем наблюдать величественный экземпляр something = malloc(...); something = somethingelse; в его естественной среде обитания. Этот вид, получивший научное название Monstratorem quaeque, классифицируется как вызывающий наименьшее беспокойство из-за его активного репродуктивного цикла и обилия добычи. 31.10.2018
  • Благодарность! по какой-то причине я думал, что каждый раз, когда будет выполняться внешний цикл for(;;), будет создаваться новый буфер для valid_input... @AhmedMasud, спасибо, что указали на это! не знаю, почему я этого не понял :) 31.10.2018
  • @AhmedMasud, если у вас есть время, я хотел бы услышать о других проблемах с моим кодом (я обновил его с момента вашего последнего комментария, см. Обновление 1) 01.11.2018

Ответы:


1

Вы устанавливаете newnode->text = valid_input; для каждого узла. Но valid_input — это локальный буфер, объявленный внутри цикла for в word_input. Так что это недопустимый код - существование буфера вне этой функции не гарантируется.

На практике valid_input содержит адрес некоторой стековой памяти, которая повторно используется каждый раз, когда вы входите в эту функцию, поэтому все указатели node->text в конечном итоге указывают на одну и ту же память, содержащую последнее введенное значение.

Вы должны быть в состоянии убедиться, что это так, напечатав значение текстового указателя для всех узлов.

Что вам нужно сделать, так это создать новый буфер для каждой записи, которую вы хотите сохранить.

31.10.2018
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..