代碼實現了帶頭結點的鏈式隊列,入隊 0~9 後出隊 8 個元素,結果全為 0。經分析,核心問題在於 InitQueue 初始化邏輯錯誤導致頭結點丟失,進而使入隊操作無效、出隊訪問野指針。
Status InitQueue(LinkQueue *Q) {
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode)); // ① 分配頭結點
if(!Q->front) exit(0);
Q->front = NULL; // ② 立即置空,導致內存洩漏且頭結點丟失
return 1;
}
第 ② 行 Q->front = NULL; 直接切斷了對剛分配頭結點的引用,造成:
front 和 rear 均為 NULL(因 rear 也被賦值為 NULL)。Status EnQueue(LinkQueue *Q, QElemType e) {
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
p->data = e; p->next = NULL;
Q->rear->next = p; // 此時 Q->rear 為 NULL,解引用導致崩潰或未定義行為
Q->rear = p;
return 1;
}
因初始化錯誤導致 Q->rear == NULL,此處 Q->rear->next 直接解引用空指針,程式理應崩潰,若未崩潰則屬於未定義行為(UB),數據實際未入隊。
Status Dequeue(LinkQueue *Q, QElemType *e) {
QueuePtr p = Q->front->next; // Q->front 為 NULL,再次解引用空指針
*e = p->data;
Q->front->next = p->next;
if(Q->rear == p) Q->rear = Q->front;
free(p);
return 1;
}
同樣因 front == NULL 導致非法訪問。若運行環境未檢測到崩潰,讀取到的垃圾值恰好為 0,造成「出隊全為 0」的假象。
// 正確初始化:建立頭結點,front/rear 均指向它,next 置 NULL
Status InitQueue(LinkQueue *Q) {
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if (!Q->front) return 0; // 分配失敗返回錯誤碼,避免 exit(0)
Q->front->next = NULL;
return 1;
}
// 入隊:利用尾插法,rear 指向新結點
Status EnQueue(LinkQueue *Q, QElemType e) {
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if (!p) return 0;
p->data = e;
p->next = NULL;
Q->rear->next = p; // 關鍵:原尾結點 next 指向新結點
Q->rear = p; // 更新尾指針
return 1;
}
// 出隊:刪除頭結點之後的第一個結點
Status Dequeue(LinkQueue *Q, QElemType *e) {
if (Q->front == Q->rear) return 0; // 隊空判斷
QueuePtr p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if (Q->rear == p) Q->rear = Q->front; // 刪除最後一個元素時重置尾指針
free(p);
return 1;
}
InitQueue 後立即打印 Q->front、Q->rear 地址,確認頭結點存在。data,確認數據確實鏈接。掌握「頭結點不存數據、front 指向頭、rear 指向尾、空隊列 front==rear」這一核心不變量,鏈式隊列操作即可邏輯自洽。