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

C 語言學生信息管理系統:scanf_s 參數順序錯誤導致崩潰與邏輯漏洞修復

     編輯:程式設計綜合問答

問題現象

代碼編譯無錯,但運行時在輸入電話號碼(scanf_s("%d", &p->tel))等環節崩潰,或邏輯異常(如驗證碼模塊、文件讀寫、鏈表操作)。

關鍵錯誤定位

1. scanf_s 參數順序/取址錯誤(導致崩潰)

// 錯誤代碼
scanf_s("%d", &p->tel);  // p 是結構體指針,p->tel 是 int,&p->tel 正確
// 但原代碼寫為:
scanf_s("%d", &p->tel);  // 這行其實正確,崩潰可能在其他類似行

// 真正的問題行(原代碼片段):
scanf_s("%s", p->name);  // ❌ 缺少 &,且 %s 對應 char[] 不需 &,但緩衝區大小未指定
// scanf_s 要求 %s/%c 必須提供緩衝區大小:
scanf_s("%s", p->name, (unsigned)sizeof(p->name)); // ✅

// 另一常見錯誤:
scanf_s("%c", &p->sex); // 讀取單字符,需跳過換行符
// 正確:
scanf_s(" %c", &p->sex, 1); // 格式符前加空格跳過空白,指定寬度 1

VS 中 scanf_s 嚴格要求:

  • %s、%c、%[ 格式符**必須**緊跟緩衝區大小參數(rsize_t 類型)。
  • 否則運行時拋出 Invalid parameter 導致崩潰。

2. 文件讀寫模式錯誤

// 錯誤
if ((fp = fopen_s("StuInfo.txt","r")) == NULL)  // ❌ fopen_s 返回 errno_t,不返回 FILE*
// 正確
errno_t err = fopen_s(&fp, "StuInfo.txt", "r");
if (err != 0) { /* 錯誤處理 */ }

// 寫入模式 "a" (追加) 會導致重複數據,建議 "w" (覆蓋) 或先清空文件

3. 鏈表創建邏輯漏洞

  • 頭結點 loc_head 分配後未檢查 malloc 返回值。
  • tail->GoOn 作為循環控制字段混雜在數據結構中,不符合單一職責。建議單獨變量控制循環。
  • 輸入完成後 tail->next = NULL 正確,但若首次輸入即選 0,loc_head 已分配卻未初始化數據,會產生「垃圾節點」。

4. 排序函數效率與正確性

void Info_Paixu(SDate *stu, int n) {
    // 冒泡排序交換整個結構體(包含數組字段),極其低效且危險
    // 建議:僅交換指針(結構體指針數組),或交換關鍵字段(學號、姓名...)
    // 或使用 qsort 配合比較函數
}

5. 查找函數邏輯錯誤

if(flag=0) break; // ❌ 賦值而非比較,永遠為 0 (false),不會 break
// 正確
if(flag == 0) break;

6. 主循環 goto 濫用

大量 goto Order、goto e、goto lab1 導致控制流極難維護。建議重構為 while(1) 循環 + switch + 函數返回狀態碼控制流程。

修復建議清單

  1. **全部 scanf_s 檢查**:%s/%c/%[ 後加緩衝區大小;%c 前加空格跳過換行;指針取址正確。
  2. **文件操作改用 fopen_s 正確語法**,讀取用 "r",寫入用 "w" 覆蓋模式。
  3. **鏈表創建重構**:先讀取節點數或動態擴展,避免垃圾頭節點;分離控制變量與數據結構。
  4. **排序改用指針交換或 qsort**.
  5. **修正 if(flag=0) 為 ==**.
  6. **消除 goto**,用結構化循環重寫主菜單。
  7. **添加錯誤檢查**:malloc、fopen_s、scanf_s 返回值必須判斷。

此代碼屬典型教學級 C 程序,存在大量 VS scanf_s 特有陷阱、指針操作不規範、控制流混亂。建議以「模塊化、參數校驗、資源檢查、結構化流程」為原則逐模塊重寫,而非單點修補。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved