【问题标题】:C++ array is not empty where it should beC++ 数组在它应该在的地方不是空的
【发布时间】:2018-04-29 20:59:19
【问题描述】:

我正在尝试使用一个动态数组编写一个哈希映射,该数组存储一组指向链表结构的指针。我遇到了一些奇怪的内存问题。似乎我的数组中有不应该的指针。

我得到一个错误,即使应该从我正在执行的单个插入生成的索引是 16,当我循环遍历数组时,也有一些非零项:

start 
16 //(output of index from insert)
dumbtest //(get of nonexistent key)
0 // result of get of non-existent key
HashTable:
    0   0x0--
    0x0

    1   0x0--
    0x0

    2   0xeb-- //Why is this not 0x0?  
        0xeb

我得到一个错误:Thread 1: EXC_BAD_ACCESS (code=1, address=0x80000002c)

从字符串库中的这一行开始:

 _LIBCPP_INLINE_VISIBILITY
    bool __is_long() const _NOEXCEPT
        {return bool(__r_.first().__s.__size_ & __short_mask);}

我猜这是将数组中的垃圾视为指针然后尝试将随机字节转换为“key”属性的字符串的结果。

这是类文件

#include "hashtable.hpp"
using namespace std;

HashTable::HashTable()
{
    this->length = 32;
    this->buck = new LinkedList *[32];
};


unsigned int HashTable::hash(string key)
{
    int hash = 7;
    for (int i = 0; i < key.length(); i++) {
        hash = hash*31 * key[i];
    }
    hash = hash % this->length;
    return std::abs(hash);
}

int HashTable::find(string key)
{
    int index = this->hash(key);
    LinkedList *curr = this->buck[index];
    while(curr != nullptr)
    {
        if(curr->key == key)
        {
//            std::cout << curr;
            int val = curr->value;
            return val;
        }

        curr = curr->next;
    }
    return 0;
}


void HashTable::output()
{
    cout << "\nHashTable:\n";
    for(int i = 0; i < this->length; i++)
    {
        LinkedList *curr = this->buck[i];
        cout << "\t";
        cout << i;
        cout << "\t";
        cout << curr;
        cout << "--\n\t";
        while (curr != nullptr){
            cout << "\t";
            cout << curr;
            cout << ":";
            cout << curr->key;
            cout << ",";
            cout << curr->value;
            cout << ",";
            cout << curr->next;
            curr = curr->next;
        }
        cout << this->buck[i];
        cout << "\n";
        cout << "\n";
    }
}

void HashTable::insert(string key, int value)
{
    unsigned int index = this->hash(key);
    cout << index;
    LinkedList *curr = this->buck[index];
    LinkedList *ins = new LinkedList{
        key,
        value,
        NULL,
    };
    if (curr == nullptr){
        this->buck[index] = ins;
    }
    else
    {
        while(curr->next != nullptr)
        {
            curr = curr->next;
        }

        curr->next = ins;
    }
}



void HashTable::rehash()
{
    this->length = 2 * this->length;
    LinkedList** old = this->buck;
    this->buck = new LinkedList* [this->length];
    for (int i=0; i < this->length; i++)
    {
        LinkedList* curr = old[i];
        while(curr != nullptr)
        {
            this->insert(curr->key, curr->value);
            curr = curr->next;
        }
    }
}

然后是我的标题

#ifndef hashtable_hpp
#define hashtable_hpp

#include <stdio.h>
#include <string>
#include <iostream>


struct LinkedList
{
    std::string key;
    int value;
    LinkedList *next;
};


class HashTable
{
private:
    int length;
    LinkedList** buck;
    unsigned int hash(std::string key);
    void rehash();

public:
    HashTable();
    int find(std::string key);
    void insert(std::string key, int value);
    bool remove(std::string key);
    void output();

};
#endif /* hashtable_hpp */

这是运行它的主文件:

#include <stdio.h>
#include <string>
#include <iostream>
#include "hashtable/hashtable.hpp"

int main(int argc, const char * argv[])
{
    std::cout << "start\n";

    HashTable ht;
    ht.insert("test", 3);
//    ht.output();
    std::cout << "\ndumbtest\n";
    int dumbval = ht.find("testy");
    std::cout << dumbval;
    ht.output();

    std::cout << "\ntest\n";
    int val = ht.find("test");
    std::cout << val;

    std::cout << "\nend";
    return 0;
}

这是堆栈跟踪:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x80000002c)
  * frame #0: 0x00000001000021bd algStudy`std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<<char, std::__1::char_traits<char>, std::__1::allocator<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) [inlined] std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__is_long(this="") const at string:1221
    frame #1: 0x00000001000021bd algStudy`std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<<char, std::__1::char_traits<char>, std::__1::allocator<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) [inlined] std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__get_pointer(this="") const at string:1315
    frame #2: 0x00000001000021bd algStudy`std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<<char, std::__1::char_traits<char>, std::__1::allocator<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) [inlined] std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::data(this="") const at string:1129
    frame #3: 0x00000001000021bd algStudy`std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<<char, std::__1::char_traits<char>, std::__1::allocator<char> >(__os=0x00007fff9b480660, __str="") at ostream:1047
    frame #4: 0x0000000100002067 algStudy`HashTable::output(this=0x00007ffeefbff4c8) at hashtable.cpp:63
    frame #5: 0x00000001000014c5 algStudy`main(argc=1, argv=0x00007ffeefbff5e8) at main.cpp:23
    frame #6: 0x00007fff6388d015 libdyld.dylib`start + 1
    frame #7: 0x00007fff6388d015 libdyld.dylib`start + 1

有什么想法吗?

【问题讨论】:

  • 你没有初始化buck,所以它的内容就是内存中发生的任何事情。如果您希望将它们初始化为 nullptr,则需要明确地执行此操作。
  • 所以我必须循环并在构造函数中将每个值设置为nullptr?
  • nvm,知道了,谢谢this-&gt;buck = new LinkedList *[32]()
  • 你可以使用向量代替手动内存管理
  • 是的,无论如何这只是为了练习,所以我想我会在做这件事的同时进行内存管理。

标签: c++ memory


【解决方案1】:

从您的代码中,我可以告诉您从堆中分配链表,这意味着您不能保证操作系统会帮助您清除分配的内存。

实际上,nullptr 意味着它只是指向您无法读取/写入的地址 NULL(零),因此该指针为“null”。

有一个比循环和设置为 nullptr 更好的 C 语言解决方案:在分配 HashTable::buck 后添加这一行

memset(buck,0,sizeof(buck));

此行将HashTable::buck 空间中的字节设置为零。

【讨论】:

  • 从技术上讲,memsetting 为零不能保证指向nullptrs。
  • 呼应@Sneftel。你想要std::fill,而不是memset
  • 在 C++ 中使用 C 风格的解决方案不是一个好主意。有更好的方法来做事,这些方法集成在语言中。
猜你喜欢
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
相关资源
最近更新 更多