準備跳槽,重拾 C++ 復習數據結構。第一天實現基於鏈表的棧,過程中遇到經典內存錯誤,記錄以自勉。
data (int) + next 指針。header。addElement、出棧 popElement、判空、打印、查找。class Stack {
private:
typedef int NODE_DATA_TYPE;
typedef struct Node {
NODE_DATA_TYPE data;
struct Node *next;
} Node;
Node *header;
public:
Stack() : header(nullptr) {}
~Stack() {
while (header) {
Node *temp = header;
header = header->next;
free(temp);
}
_ASSERTE(_CrtCheckMemory()); // 檢查內存洩漏
}
void addElement(NODE_DATA_TYPE data) {
Node *newNode = (Node*)malloc(sizeof(Node)); // 關鍵:sizeof(Node) 而非 sizeof(Node*)
newNode->data = data;
newNode->next = header;
header = newNode;
}
NODE_DATA_TYPE popElement() {
if (!header) return -1;
NODE_DATA_TYPE val = header->data;
Node *temp = header;
header = header->next;
free(temp);
return val;
}
// ... 其他方法
};
malloc(sizeof(Node*)) 導致堆損壞錯誤現象:在 free(temp) 時觸發 CRT detected that the application wrote to memory after end of heap buffer。
原因:分配內存時寫成 malloc(sizeof(Node*)),只分配了指針大小(4/8 字節),而非結構體大小。寫入 data 和 next 時越界破壞堆元數據。
教訓:sizeof(Node) 是結構體大小,sizeof(Node*) 是指針大小,兩者差異極大。動態分配結構體時務必用 sizeof(結構體類型)。
_CrtCheckMemory() 檢測堆完整性。_ASSERTE 宏在條件失敗時中斷,便於定位問題。searchElement 中修改了 header 導致棧內容丟失,應使用臨時指針遍歷。new/delete 替代 malloc/free,但理解底層分配機制有助於排查錯誤。看似簡單的棧實現,蘊含指針操作、內存管理、調試技巧等核心功力。一個 sizeof 的細微錯誤纏繞一晚,正是「細節決定成敗」的生動寫照。繼續保持,戰鬥不退縮!