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

C 語言 scanf/printf 常見坑:位址輸出、緩衝區殘留、goto 導致輸入跳過完整解析

     編輯:程式設計綜合問答

初學者常在 scanf/printf、緩衝區清理、goto 迴圈三個環節踩坑。本文逐一拆解「位址誤當值輸出」、「clear_kb 實作缺陷」、「goto 導致 scanf 被跳過」三大經典問題,並給出標準修正寫法。

程式碼問題重現

int main() {
    int ir = 0;
uur:
    printf("333\n");
    scanf("%d", &ir);
    clear_kb();
    printf("t=%d\n", ir);      // 正確:印出輸入值
    printf("t=%d\n", &ir);     // 錯誤:印出位址,且用 %d 解讀
    goto uur;
}

void clear_kb(void) {
    char junk[4096];
    // gets(junk); // 危險且已棄用
}

三大核心問題與修正

1. printf 印出位址卻用 %d 格式化

現象:printf("t=%d\n", &ir); 輸出負數(-58、-60 等),實為堆疊位址的高位元被視為負號。

原因:&ir 是 int* 型別,需用 %p 配合 (void*) 列印。

修正:

printf("ir value = %d\n", ir);        // 印值
printf("ir address = %p\n", (void*)&ir); // 印位址

2. clear_kb() 緩衝區清理失效

現象:輸入非數字字元後,scanf 失敗,殘留字元導致下一輪 scanf 直接讀取舊字元而非等待輸入。

標準清理模式:

void clear_kb(void) {
    int c;
    while ((c = getchar()) != '\n' && c != EOF) { /* discard */ }
}

進階:搭配 scanf 回傳值檢查

int ret = scanf("%d", &ir);
if (ret != 1) {          // 輸入非整數
    clear_kb();          // 清理錯誤字元
    continue;            // 重新提示
}

3. goto 迴圈導致 scanf 被「跳過」

現象:第二次迴圈 printf("333\n") 執行,但 scanf 似乎未等待輸入直接跑完。

真相:非 goto 問題,而是上一輪 scanf 失敗(如輸入 'a'),殘留 'a' 與 '\n' 留在 stdin,下一輪 scanf 立即讀取失敗返回,程式繼續跑,看起來像「跳過」。

根治:檢查 scanf 回傳值 + 失敗時清理緩衝區,而非依賴 goto。

重構後的健壯版本

#include 
#include 

void clear_stdin(void) {
    int c;
    while ((c = getchar()) != '\n' && c != EOF) {}
}

int main(void) {
    int ir;
    while (1) {
        printf("請輸入整數 (Ctrl+Z 結束): ");
        int ret = scanf("%d", &ir);
        if (ret == EOF) break;      // 使用者送出 EOF
        if (ret != 1) {             // 輸入非整數
            printf("輸入無效,請重新輸入。\n");
            clear_stdin();
            continue;
        }
        printf("您輸入的值 = %d\n", ir);
        printf("變數位址 = %p\n", (void*)&ir);
    }
    return 0;
}

最佳實務總結

錯誤模式正確做法
printf("%d", &var)printf("%p", (void*)&var)
忽略 scanf 回傳值必檢查 ret == 1 (或預期欄位數)
用 gets/fgets 清理 stdin用 getchar() 迴圈丟棄至換行/EOF
用 goto 構建主迴圈用 while(1) + break/continue
main() 省略回傳型別標準寫法 int main(void) 並 return 0;

總結

scanf/printf 看似簡單,實則暗藏型別、緩衝區、回傳值三大陷阱。養成「檢查回傳值、正確格式化字串、標準化緩衝區清理」三習慣,並以 while 取代 goto,即能寫出健壯、可維護的互動式主控台程式。

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