首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 語言格式化輸入輸出大全:printf/sprintf/scanf/sscanf 進階用法與最佳實踐

     編輯:關於C

函數族對比

函數輸出目標輸入源返回值
printf標準輸出—輸出字符數
sprintf字符串緩衝區—寫入字符數
scanf—標準輸入成功賦值項數
sscanf—字符串緩衝區成功賦值項數

sprintf 核心功能與實例

1. 數字格式化

sprintf(s, "%-8X", 12345);     // "12345   " 左對齊 16 進制大寫
sprintf(s, "%08X", 4567);      // "000011D7" 左補零
sprintf(s, "%10.3f", 3.14159); // "    3.142" 寬度 10,保留 3 位小數
sprintf(s, "%-10.3f", 3.14159);// "3.142     " 左對齊

2. 字符串連接與截取

// 直接連接
sprintf(dest, "%.5s%.4s", src1, src2);  // "abcde1234"

// 指定長度截取連接
sprintf(dest, "%.*s%.*s", 2, src1, 3, src2);  // "ab123"

// 動態長度
sprintf(dest, "%.*s%.*s", len1, src1, len2, src2);

3. 字符/ASCII 碼對照

for (int i=32; i<127; i++)
    printf("[ %c ]: %3d 0x%#04X\n", i, i, i);  // # 標誌產生 0X 前綴

4. 地址打印

sprintf(s, "%p", &i);           // 標準指針格式
sprintf(s, "%08X", (unsigned)&i);  // 手動 16 進制
sprintf(s, "%0*x", 2*sizeof(void*), &i);  // 等價寫法

5. 利用返回值避免 strlen

int len = sprintf(s, "%d", i);  // 直接獲得字符串長度

6. 類型安全陷阱

short si = -1;
sprintf(s, "%04X", si);           // 錯誤:輸出 "FFFFFFFF"(符號擴展)
sprintf(s, "%04X", (unsigned short)si);  // 正確:輸出 "FFFF"

int i = 100;
sprintf(s, "%.2f", i);            // 錯誤:整數按浮點解讀
sprintf(s, "%.2f", (double)i);    // 正確:輸出 "100.00"

sscanf 進階掃描集用法

掃描集 %[] 語法

  • %[a-z]:讀取 a-z 字符,遇其他停止
  • %[^a-z]:讀取非 a-z 字符,遇 a-z 停止
  • %[a-z,A-Z,0-9]:多範圍組合
  • %*[^=]:* 忽略賦值,跳過匹配內容

實戰案例:URL 解析

const char *url = "https://www.baidu.com:1234";
char protocol[32], host[128], port[8];
sscanf(url, "%[^:]://%[^:]:%[1-9]", protocol, host, port);
// protocol="http", host="www.baidu.com", port="1234"

其他常用模式

// 讀取固定長度
sscanf(s, "%40c", buf);

// 讀取到指定字符
char s[] = "notepad=1.0.0.1001";
char name[32];
sscanf(s, "%[^=]", name);        // "notepad"
sscanf(s, "%*[^=]=%s", name);    // "1.0.0.1001" (跳過前綴)

// 多字符分隔符
sscanf(s, "%[^=:]", name);       // 支持 = 或 : 分隔

scanf/sscanf 返回值處理

int cnt = sscanf(str, "%d %s", &a, buf);
if (cnt == 2) { /* 成功 */ }
else if (cnt == EOF) { /* 輸入結束 */ }
else { /* 格式不匹配 */ }

安全版本:snprintf

// 防止緩衝區溢出
int snprintf(char *buf, size_t n, const char *fmt, ...);
// 最多寫入 n-1 字符,自動添加 '\0'

綜合實戰:IP/MAC 地址轉換

// IP 字符串 → 整數
uint32_t ipstr2int(const char *ipstr) {
    uint a,b,c,d;
    sscanf(ipstr, "%u.%u.%u.%u", &a,&b,&c,&d);
    return (a<<24) | (b<<16) | (c<<8) | d;
}

// 整數 → IP 字符串(處理大小端)
char* int2ipstr(uint32_t ip, char *buf) {
    if (is_little_endian()) {
        sprintf(buf, "%u.%u.%u.%u",
            (uchar)*((uchar*)&ip+3),
            (uchar)*((uchar*)&ip+2),
            (uchar)*((uchar*)&ip+1),
            (uchar)*((uchar*)&ip+0));
    } else {
        sprintf(buf, "%u.%u.%u.%u",
            (uchar)*((uchar*)&ip+0),
            (uchar)*((uchar*)&ip+1),
            (uchar)*((uchar*)&ip+2),
            (uchar)*((uchar*)&ip+3));
    }
    return buf;
}

// MAC 字節數組 → 字符串
char* mac2str(const uchar *mac, char *buf) {
    sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X",
            mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
    return buf;
}

最佳實踐總結

  1. 優先用 snprintf:防止緩衝區溢出
  2. 類型匹配嚴格:格式符與實參類型必須一致
  3. 善用掃描集:%[] 比手動解析高效安全
  4. 檢查返回值:確認解析/格式化成功項數
  5. 避免格式化字符串漏洞:printf(user_input) → printf("%s", user_input)
  6. 大小端敏感操作:網絡序用 htonl/ntohl
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved