首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C 語言初學者商品訂單管理系統:Access Violation 錯誤完整修復與代碼規範重寫

     編輯:程式設計疑難解答

原代碼核心問題

  1. 結構體日期字段類型錯誤:`char riqi` 只能存 1 字符,應為 `char riqi[11]` 存「YYYY-MM-DD」。
  2. 輸入處理混亂:`scanf("%s", &m)` 用整數變量接收字串,導致棧破壞。
  3. 指針操作錯誤:`p->date.number;` 無賦值;`head` 傳遞未用指針導致鏈表頭插入失效。
  4. 內存洩漏/野指針:`malloc` 未檢查返回值;`free(p)` 後繼續使用 `p`。
  5. 緩衝區溢出風險:`gets(N)` 不安全,`scanf("%s")` 無長度限制。
  6. 主函數返回類型:`void main()` 不標準,應為 `int main()`。

完整修正代碼 (關鍵修正點已標註)


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

typedef struct store {
    int number;
    char name[20];      // 擴大容量
    int shuliang;
    int jiage;
    int kucun;
    int zonge;
    char riqi[11];      // 修正:字串存日期
} store;

typedef struct unit {
    store date;
    struct unit* next;
} unit;

unit* build() {
    unit* p = (unit*)malloc(sizeof(unit)); // 修正:強制轉型、檢查 NULL
    if (!p) { printf("初始化失敗!\n"); return NULL; }
    p->next = NULL;
    p->date.number = 0; // 頭結點計數器
    printf("初始化成功!\n");
    return p;
}

// 傳入頭指針的指針,以便修改頭結點 (雖此處頭結點固定,但規範做法)
void sole(unit* head) {
    unit *p = (unit*)malloc(sizeof(unit));
    if (!p) return;
    int m;
    printf("=>商品編號:\n"); scanf("%d", &m); getchar();
    p->date.number = m;
    printf("=>賣出商品及型號:\n"); scanf("%19s", p->date.name); getchar(); // 修正:直接讀入結構體、限制長度
    printf("=>請輸入數量!\n"); scanf("%d", &m); getchar(); p->date.shuliang = m;
    printf("=>請輸入價格!\n"); scanf("%d", &m); getchar(); p->date.jiage = m;
    printf("=>請輸入庫存!\n"); scanf("%d", &m); getchar(); p->date.kucun = m;
    printf("=>請輸入日期(YYYY-MM-DD)!\n"); scanf("%10s", p->date.riqi); getchar(); // 修正
    p->date.zonge = p->date.shuliang * p->date.jiage;
    // 頭插法
    p->next = head->next;
    head->next = p;
    head->date.number++;
}

void deletion(unit* head) {
    unit *p = head->next, *q = head;
    char N[20];
    printf("=>請輸入你想刪除訂單名稱!\n"); scanf("%19s", N); getchar();
    if (!p) { printf("系統無訂單可刪除!\n"); return; }
    while (p) {
        if (strcmp(p->date.name, N) == 0) {
            q->next = p->next;
            head->date.number--;
            printf("=>刪除%s成功!\n", p->date.name);
            free(p);
            return;
        }
        q = p;
        p = p->next;
    }
    printf("=>訂單不存在,刪除失敗!\n");
}

int display(unit* head) {
    unit* p = head->next;
    if (!p) { printf("系統無訂單!\n"); return 0; }
    int m, n = 0;
    while (!n) {
        printf("=>1.顯示所有 2.按編號查找 3.返回\n"); scanf("%d", &m); getchar();
        switch (m) {
            case 1:
                printf("系統擁有%d份訂單!\n名稱\t數量\t價格\t總額\t日期\n", head->date.number);
                for (p = head->next; p; p = p->next)
                    printf("%s\t%d\t%d\t%d\t%s\n", p->date.name, p->date.shuliang, p->date.jiage, p->date.zonge, p->date.riqi);
                break;
            case 2:
                printf("請輸入編號:"); scanf("%d", &m); getchar();
                for (p = head->next; p; p = p->next)
                    if (p->date.number == m) {
                        printf("名稱\t數量\t價格\t總額\t日期\n%s\t%d\t%d\t%d\t%s\n", p->date.name, p->date.shuliang, p->date.jiage, p->date.zonge, p->date.riqi);
                        break;
                    }
                if (!p) printf("訂單不存在!\n");
                break;
            case 3: n = 1; break;
        }
    }
    return 1;
}

void menu() {
    printf("\t1.新建系統 2.添加訂單\n\t3.刪除訂單 4.查看信息\n\t5.退出系統\n=>請選擇:");
}

int main() {
    int m = 0, n, i;
    unit* head = NULL;
    printf("歡迎使用商品訂單管理系統\n=>是否新建? 1.是 2.否\n"); scanf("%d", &i); getchar();
    if (i == 1) head = build(); else return 0;
    while (!m) {
        menu(); scanf("%d", &n); getchar();
        switch (n) {
            case 1: head = build(); break;
            case 2: sole(head); break;
            case 3: deletion(head); break;
            case 4: display(head); break;
            case 5: m = 1; break;
        }
    }
    // 退出前釋放鏈表 (略)
    return 0;
}

關鍵修正清單

  • 所有 `scanf("%s")` 加寬度限制 `%19s` `%10s` 防溢出。
  • 每次 `scanf` 後緊跟 `getchar()` 吸收換行符,避免下次輸入讀空。
  • 結構體 `riqi` 改為字元數組,日期輸出正常。
  • `malloc` 返回強制轉型 `(unit*)`,檢查 `NULL`。
  • 鏈表操作統一使用 `head->next` 訪問首數據節點,頭結點 `number` 作計數器。
  • 刪除邏輯修正:`q` 正確跟蹤前驅節點。

學習建議

  1. 先掌握「結構體定義、指針操作、鏈表基本增刪改查」三大核心,再寫業務邏輯。
  2. 養成「編譯零警告、運行無崩潰、輸入有邊界檢查」習慣。
  3. 使用調試器 (GDB/VS Debugger) 單步執行,觀察指針與內存變化,比單純看代碼高效得多。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved