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

C++ 程式首次運行正常二次崩潰:gets_s 與 cin 混用導致緩衝區殘留

     編輯:程式設計綜合問答

問題現象

C++ 程式第一次運行正常,第二次運行(或循環內多次讀取)時出現異常行為、崩潰或跳過輸入。程式碼混用 gets_s() 讀取字串與 cin >> ch 讀取字符。

根因分析

char line[100];
gets_s(line);        // ① 讀取整行(含空格),消費換行符 '\n'
char ch;
cin >> ch;           // ② 讀取字符,**跳過空白字符(含換行符)**,但後續殘留換行符
// 第三次循環 gets_s 讀到空行,或 cin 讀取失敗

核心衝突:gets_s 屬 C 標準庫,直接操作 stdin 緩衝區;cin 屬 C++ iostream,有獨立緩衝區且默認與 stdio 同步。兩者混用會導致緩衝區狀態不一致、殘留字符干擾後續讀取。

解決方案

方案一:統一使用 C++ iostream(推薦)

#include 
#include 
using namespace std;

int main() {
    string line;
    cout << "輸入字符串:";
    getline(cin, line);  // 安全、無長度限制、自動處理換行符
    
    char ch;
    cout << "輸入字符:";
    cin >> ch;           // 讀取字符,自動跳過前導空白
    cin.ignore(numeric_limits::max(), '\n'); // 清理殘留換行符
    
    // 業務邏輯...
    return 0;
}

方案二:統一使用 C stdio

#include 
#include 

int main() {
    char line[100];
    printf("輸入字符串:");
    fgets(line, sizeof(line), stdin);  // 安全替代 gets_s
    line[strcspn(line, "\n")] = 0;     // 移除結尾換行符
    
    char ch;
    printf("輸入字符:");
    scanf(" %c", &ch);  // 格式串前加空格,跳過空白字符
    
    // 業務邏輯...
    return 0;
}

方案三:若必須混用,手動同步緩衝區

ios::sync_with_stdio(true);  // 強制同步(默認即為 true)
cin.tie(nullptr);            // 解除 cin/cout 綁定(可選,提速)
// 但仍不推薦混用,極易出錯

程式碼具體錯誤修正

// 原程式碼邏輯錯誤:while 循環條件與內部 i 遞增邏輯衝突
while(line[i] != '\0') {
    while(line[i] != ch) i++;  // 若找不到 ch,i 會越界訪問 line[len] 導致 UB
    // ...
}

// 修正:使用標準庫算法
#include 
char* pos = find(line, line + strlen(line), ch);
if (pos != line + strlen(line)) {
    // 找到 ch,執行移除邏輯
    memmove(pos, pos + 1, strlen(pos));
}

最佳實踐總結

  • 禁用 gets_s/gets:C11 可選、C++17 棄用、極易緩衝區溢出
  • 統一 I/O 風格:全用 C++ iostream 或全用 C stdio,切勿混用
  • 字串處理用 std::string + 算法:安全、可讀、無手動記憶體管理
  • 輸入後清理緩衝區:cin.ignore() / scanf(" %c") 空格跳過空白

重構為現代 C++ 風格(std::string、getline、algorithm)後,程式將穩定、可讀、無緩衝區殘留問題。

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