Почему cout иногда не может выводить строки, но у printf нет проблем? - PullRequest
0 голосов
/ 13 ноября 2018

Проблема: при печати элементов в хэш-таблице элементы не верхнего уровня печатаются неправильно. Я добавляю элементы построчно из текстового файла. Сначала определяется количество строк, а затем создается хеш-таблица с размером, найденным в первом цикле файла.

конструктор хеша

hash::hash(unsigned int tSize)
{
    this->tableSize = tSize;
    hashTable.resize(tableSize);
    for (int i = 0; i < tableSize; i++)
    {
        hashTable[i] = new item;
        hashTable[i]->firstLetters = "__";
        hashTable[i]->str = "____";
        hashTable[i]->next = NULL;
    }
}

добавление элементов, установка значений и их печать

void hash::add(std::string key)
{
    int index = hafn(key);
    if (hashTable[index]->str == "____")
    {
        hashTable[index]->str = key;
        setFirstLetters(index,key[0],key[1]);
    }
    else
    {
        item *iter = hashTable[index];
        item *n_ptr = new item;
        n_ptr->str = key;
        setFirstLetters(n_ptr, key[0], key[1]);
        n_ptr->next = NULL;
        while (iter->next != NULL)
        {
            iter = iter->next;
        }
        iter->next = n_ptr;
    }
}

void hash::setFirstLetters(item *n_ptr, char a, char b)
{
    n_ptr->firstLetters[0] = a;
    n_ptr->firstLetters[1] = b;
}

void hash::setFirstLetters(int index, char a, char b)
{
    hashTable[index]->firstLetters[0] = a;
    hashTable[index]->firstLetters[1] = b;
}


void hash::print()
{
    int num;
    for (int i = 0; i < tableSize; i++)
    {
        num = numInIndex(i);
        printer(num, i);
        if (num > 1)
        {
            int c = 0;
            for (int j = num - 1; j > 0; j--)
            {
                printer(c, num, i);
                c++;
            }
        }
    }
}

void hash::printer(int num, int i)
{
    item *iter = hashTable[i];
    cout << "-------------------------------" << endl;
    cout << "index = " << i << endl;
    cout << iter->str << endl;
    cout << iter->firstLetters << endl;
    cout << "# of items = " << num << endl;
    cout << "-------------------------------" << endl;
    cout << endl;
}

void hash::printer(int numIn, int num, int i)
{
    item *iter = hashTable[i];
    for (int j = 0; j < numIn; j++)
    {
        iter = iter->next;
    }
    cout << "-------------------------------" << endl;
    cout << "index = " << i << endl;
    cout << iter->str << endl;
    cout << std::flush;
    cout << iter->firstLetters << endl; //this does not work, though the pointer is pointing to the correct values
    //printf("%s\n", iter->firstLetters.c_str()); //this works, even without flushing
    cout << "# of items = " << num << endl;
    cout << "-------------------------------" << endl;
    cout << endl;
}


    struct item
    {
        std::string str;
        std::string firstLetters;
        item *next;
    }; 

Проблема в том, что firstLetters печатается неправильно. firstLetters установлено правильно. Однако в элементах третьего и более поздних уровней (т. Е. С использованием того же хеш-индекса) firstLetters не печатается вообще.

Для большей ясности приведем пример вывода:

-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------

-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------

-------------------------------
index = 15
good

# of items = 3
-------------------------------

Обратите внимание, под заголовком «добавление элементов, установка значений и их печать» и в методе hash::add(std::string key) я использую setFirstLetters() для доступа к элементам внутри std::string firstLetters без предварительной их инициализации. Это приводит к тому, что любое изменение этих значений будет потеряно. При доступе к iter->firstLetters, когда пришло время печатать значения, невозможно получить доступ к фактическим данным. Чтобы избежать этого неопределенного поведения, я изменил определение hash::add(std::string key), чтобы установить значение firstLetters, прежде чем пытаться изменить их.

Новое определение hash::add()

void hash::add(std::string key)
{
    int index = hafn(key);
    if (hashTable[index]->str == "____")
    {
        hashTable[index]->str = key;
        setFirstLetters(index,key[0],key[1]);
    }
    else
    {
        item *iter = hashTable[index];
        item *n_ptr = new item;
        n_ptr->firstLetters = "__";        //here
        n_ptr->str = key;
        setFirstLetters(n_ptr, key[0], key[1]);
        n_ptr->next = NULL;
        while (iter->next != NULL)
        {
            iter = iter->next;
        }
        iter->next = n_ptr;
    }
}

Добавление этой строки исправляет вывод.
Это новый вывод:

-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------

-------------------------------
index = 15
will
wi
# of items = 3
-------------------------------

-------------------------------
index = 15
good
go
# of items = 3
-------------------------------

Этот тип поведения считается «неопределенным поведением». Здесь есть несколько движущихся частей, и единственной причиной такого поведения является отсутствие инициализации. В случаях, когда std::cout завершается с ошибкой, но printf() - нет, убедитесь, что все члены / переменные инициализированы перед тем, как попытается получить к ним доступ. В определенных случаях с использованием std::string оператор [] может функционировать должным образом только после обычной инициализации, используя оператор = или другие функции-члены std::string.

...