我正在实施一个跳过列表。它是什么并不重要,但它现在适用于1000个节点,而不是10000个节点。我得到的SegFaults没有意义,所以我艾德一些变量。令我惊讶的是,很多不应该改变的东西都变成了垃圾值。例如,我在函数insertNode之前和之后打印了inputValue。它有时会重置为零,而本应始终递增。让我们看看代码(跳过读取文件输入,问题发生在while周期):
int main(int argc, char** argv) {
string filename = "";
if( argc == 2 )
filename = argv[1];
else
return 0;
list = new skiplist();
fstream inputFile(filename.c_str(), ios_base::in);
inputFile >> numberofnodes;
inputFile >> list->minimumKey;
inputFile >> list->maximumKey;
printf("%d\n", numberofnodes);
printf("%d\n", list->minimumKey);
printf("%d\n", list->maximumKey);
list->Maxlevel = 1;
list->header = new node();
list->tail = new node();
list->header->key = list->minimumKey;
list->tail->key = list->maximumKey;
for ( int i=1; i<=MAXIMUMLEVEL; i++ ) {
list->header->forward[i] = list->tail;
list->tail->forward[i] = NULL;
}
int sanityCheck = 134153;
// insert nodes
int inputKey;
int inputValue = 0;
int * keys = new int[numberofnodes];
while (inputFile >> inputKey)
{
inputValue++;
keys[inputValue] = inputKey;
insertNode(inputKey, inputValue);
if(sanityCheck != 134153) // dark magic changes this value
keys[9999999999999999999999]++; // program crashes here
// it would otherwise crash on while
}
printf("\n\nNodes inserted: %d\n\n",inputValue);
我经营Valgrind无效的内存写/读发生在变量改变之后,至少我是这样认为的。所以我才加了精神正常检查。正如我所想的,在尝试访问密钥[9999999999999999999999]之前,没有无效的内存写入/读取。但那一行只能运行int sanitycheck is changed,我从来没有这样做过。
最后,这里是insertNode的代码。我没看到任何可能导致这个的东西:
void insertNode(int newKey, int newValue){
node * update[MAXIMUMLEVEL];
node * auxNode = list->header;
for(int i=list->Maxlevel; i >=1; i--) {
while ( auxNode->forward[i]->key < newKey ) {
auxNode = auxNode->forward[i];
}
update[i] = auxNode;
}
auxNode = auxNode->forward[1];
if ( auxNode->key == newKey ) {
auxNode->value = newValue;
} else {
int randomLevel = 1;
while ( (rand() / double(RAND_MAX)) < LEVELPROBABILITY && randomLevel < MAXIMUMLEVEL ) {
randomLevel++;
}
if ( randomLevel > list->Maxlevel ) {
for ( int i = list->Maxlevel+1; i <= randomLevel; i++ ) {
update[i] = list->header;
}
list->Maxlevel = randomLevel;
}
node * newNode = new node();
newNode->key = newKey;
newNode->value = newValue;
for ( int i=1; i<=MAXIMUMLEVEL; i++ ) {
newNode->forward[i] = NULL;
}
for ( int i=1; i<=list->Maxlevel; i++ ) {
newNode->forward[i] = update[i]->forward[i];
update[i]->forward[i] = newNode;
}
}
}
以及结构:
typedef struct node {
int key;
int value;
node * forward[MAXIMUMLEVEL+1];
}node;
struct skiplist {
int minimumKey;
int maximumKey;
int Maxlevel;
node * header;
node * tail;
};
EDIT:
#define MAXIMUMLEVEL 16
#define LEVELPROBABILITY 0.5
我甚至不用马洛克。有指针操作,但valgrind应该检测到如果我做了什么不好的权利?如果内存不足,就会出现例外。我创建的一个int,从来没有访问/write/change,怎么可能被修改?很抱歉这篇文章很长,但我不知道问题出在哪里。
Valgrind未进行健全性检查的输出(keys[999...9]):http://pastebin.com/hWH3fri2
第155行是while(inputFile >> inputKey)
1条答案
按热度按时间91zkwejq1#
以下是clang的地址消毒器的输出(在setting it up properly之后):
第55行提到:
循环
保证
randomLevel <= MAXIMUMLEVEL
.如果randomLevel == MAXIMUMLEVEL
和MAXIMUMLEVEL > list->Maxlevel
,则第54行中的循环变成:注意,
update
被声明为node * update[MAXIMUMLEVEL];
。你会得到一个出界访问。我不太明白为什么你的代码似乎不能访问数组的第0个元素。根据我的经验,使用
[0, length_of_array)
形式的右半开范围也容易得多,这会导致以下形式的循环请注意
<
而不是<=
。一致使用右侧半开范围可以显著减少偏一错误的数量。一个快速解决方法是像
node::forward
一样将update
声明为注意
+1
。一个更好的解决方案可能是重写代码,使其使用右半开范围,其中
MAXIMUMLEVEL
从范围[0, MAXIMUMLEVEL)
获得解释,不再是最大值,而是上确界(并表示层数)。