Valgrind检测到未初始化值问题,求助排查C++队列代码错误
链表队列的未初始化值与内存问题排查
实现基于链表的队列时,使用Valgrind检测到「Conditional jump or move depends on uninitialised value(s)」错误,尝试调试未找到问题,相关代码、测试用例及Valgrind输出如下:
问题代码
#include <fstream> #include <iostream> #include <string> using namespace std; struct Node{ string item; Node* next; Node* prev; }; struct Queue{ int size; Node* head = NULL; Node* tail = NULL; }; //Makes queue Queue* createQueue(){ Queue* n = new Queue; n->head = NULL; n->tail = NULL; n->size = 0; return n; } //checks if empty bool isEmpty(Queue* List){ if( List->size == 0){ return true; }else{ return false; } } // add item to queue bool enqueue(Queue* List, string added){ Node* newy= new Node; if(List->tail == NULL){ List->head = List->tail = newy; return true; } List->tail->next = newy; List->tail = newy; List->size++; return true; } //remove item from queue string dequeue(Queue* List){ Node* tempo = List->head; if(List->head == NULL){ return "ERROR"; } else if (tempo->next !=NULL){ tempo = tempo->next; return List->head->item; free(List->head); List->head = tempo; }else{ return List->head->item; free(List->head); List->head= NULL; List->tail = NULL; } } // display the queue void print(Queue* List){ Node* yuuur = List->head; while(yuuur != NULL){ cout<<(yuuur->item)<<endl; yuuur = yuuur->next; } } // destroy queue void destroyQueue(Queue* List){ while(List->head !=NULL){ Node *tempo = List->head; List->head= List->head->next; delete tempo; } List->tail = NULL; List->head = NULL; delete List; }
测试代码
//test code int main(){ Queue* q = createQueue(); cout << boolalpha << isEmpty(q) << endl; cout << dequeue(q) << endl; enqueue(q, "Jos"); enqueue(q ,"An"); enqueue(q, "Peter"); print(q); //Jos, An en Peter worden op drie regels geprint string first = dequeue(q); cout << first << endl; //Jos wordt geprint print(q); //An en Peter worden geprint destroyQueue(q); return 0; }
Valgrind错误输出
==77== Memcheck, a memory error detector ==77== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==77== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info ==77== Command: student/labo13 ==77== ==77== Conditional jump or move depends on uninitialised value(s) ==77== at 0x400DDA: print(Queue*) (in /task/student/labo13) ==77== by 0x401002: main (in /task/student/labo13) ==77== ==77== Conditional jump or move depends on uninitialised value(s) ==77== at 0x400DDA: print(Queue*) (in /task/student/labo13) ==77== by 0x40103F: main (in /task/student/labo13) ==77== ==77== Conditional jump or move depends on uninitialised value(s) ==77== at 0x400DDA: print(Queue*) (in /task/student/labo13) ==77== by 0x401097: main (in /task/student/labo13) ==77== ==77== Conditional jump or move depends on uninitialised value(s) ==77== at 0x400E23: destroyQueue(Queue*) (in /task/student/labo13) ==77== by 0x4010A3: main (in /task/student/labo13) ==77== ==77== ==77== HEAP SUMMARY: ==77== in use at exit: 0 bytes in 0 blocks ==77== total heap usage: 10 allocs, 10 frees, 263 bytes allocated ==77== ==77== All heap blocks were freed -- no leaks are possible ==77== ==77== For counts of detected and suppressed errors, rerun with: -v ==77== Use --track-origins=yes to see where uninitialised values come from ==77== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
问题根源及修复方案
1. Node节点未初始化
创建Node对象时,next和prev指针未赋值,导致后续遍历(如print函数中访问yuuur->next)时读取未初始化的垃圾值,触发Valgrind错误。
修复:创建节点时初始化所有成员:
Node* newy = new Node{added, nullptr, nullptr};
2. enqueue函数size更新遗漏
当队列是空的(tail == NULL),添加第一个节点后未更新size,导致size值始终比实际元素数少1。
修复:在空队列添加节点后同步更新size:
if(List->tail == NULL){ List->head = List->tail = newy; List->size++; // 新增这行 return true; }
3. dequeue函数逻辑错误
return语句在内存释放代码之前,导致free/delete永远不会执行,且C++中new分配的内存必须用delete释放,不能混用free。
修复:先保存要返回的元素,再释放内存,最后返回:
string dequeue(Queue* List){ if(List->head == NULL){ return "ERROR"; } Node* tempo = List->head; string item = tempo->item; // 先保存元素 if (tempo->next != nullptr){ List->head = tempo->next; }else{ List->head = nullptr; List->tail = nullptr; } delete tempo; // 用delete释放 List->size--; // 更新size return item; }
4. destroyQueue的指针访问风险
未初始化的next指针会导致循环中读取垃圾值,修复节点初始化后此问题自动解决。
修复后的完整代码
#include <fstream> #include <iostream> #include <string> using namespace std; struct Node{ string item; Node* next; Node* prev; }; struct Queue{ int size; Node* head = nullptr; Node* tail = nullptr; }; Queue* createQueue(){ Queue* n = new Queue; n->head = nullptr; n->tail = nullptr; n->size = 0; return n; } bool isEmpty(Queue* List){ return List->size == 0; } bool enqueue(Queue* List, string added){ Node* newy = new Node{added, nullptr, nullptr}; if(List->tail == nullptr){ List->head = List->tail = newy; List->size++; return true; } List->tail->next = newy; newy->prev = List->tail; // 双向链表维护prev指针 List->tail = newy; List->size++; return true; } string dequeue(Queue* List){ if(List->head == nullptr){ return "ERROR"; } Node* tempo = List->head; string item = tempo->item; if (tempo->next != nullptr){ List->head = tempo->next; List->head->prev = nullptr; }else{ List->head = nullptr; List->tail = nullptr; } delete tempo; List->size--; return item; } void print(Queue* List){ Node* yuuur = List->head; while(yuuur != nullptr){ cout << yuuur->item << endl; yuuur = yuuur->next; } } void destroyQueue(Queue* List){ while(List->head != nullptr){ Node *tempo = List->head; List->head = List->head->next; delete tempo; } delete List; } //test code int main(){ Queue* q = createQueue(); cout << boolalpha << isEmpty(q) << endl; cout << dequeue(q) << endl; enqueue(q, "Jos"); enqueue(q ,"An"); enqueue(q, "Peter"); print(q); string first = dequeue(q); cout << first << endl; print(q); destroyQueue(q); return 0; }
内容的提问来源于stack exchange,提问作者FieldyScop
相关产品推荐
相关产品推荐

