C語言 sscanf 用法、應用與注意事項徹底解析【附初學者範例程式】

目次

1. 前言

在 C 語言中,當解析字串並提取特定資料時,有一個便利的函式 sscanf。本文將從 sscanf 的基本用法到應用與注意事項,詳細說明。 學習 C 語言時,常會遇到「想處理使用者輸入的資料」或「想從字串中取出數值」等情況。了解 scanfsscanf 的差異,並適當運用 sscanf,即可編寫更安全且彈性的程式。 本文將說明以下重點。
  • sscanf 函式的基本
  • sscanf 的使用方法(附範例程式碼)
  • sscanf 的應用技巧
  • 常見錯誤與其對策
  • sscanf 安全使用的注意事項
那麼,首先來看看 sscanf 的基本功能。

2. C語言 sscanf 函式是什麼?

2.1 sscanf 概述

sscanf 是 C 語言標準函式庫中提供的函式,用來解析字串並轉換成指定的資料型別。雖然與 scanf 類似,但 sscanf 的不同之處在於 不是從標準輸入,而是從字串取得資料

2.2 sscanf 的基本語法

sscanf 的基本格式如下。
int sscanf(const char *str, const char *format, ...);
  • str:要解析的字串
  • format:格式指定子(定義資料型別)
  • ...:存放轉換後值的變數(指標)
作為返回值,會回傳成功轉換的輸入項目數量。失敗時則回傳 0EOF-1)。

2.3 與 scanf 的差異

以下以表格整理 sscanfscanf 的差異。
項目sscanfscanf
輸入來源字串標準輸入(鍵盤)
用途解析既有字串接收使用者輸入
彈性高(可指定格式)低(輸入受限)
安全性安全性較低(有緩衝區溢位風險)輸入控制較困難
錯誤處理可利用返回值適當處理因為是標準輸入,需要即時處理
如上所述,sscanf 適合解析既有字串,使用方式與標準輸入不同。

3. sscanf 的基本使用方法(附範例程式碼)

sscanf 可用於從字串取得整數、浮點數、字串等值。此處說明基本用法,並搭配範例程式碼介紹。

3.1 sscanf 的基本語法

使用 sscanf 時的基本語法如下。
int sscanf(const char *str, const char *format, ...);
  • str:要解析的字串
  • format:格式指定子(%d、%f、%s 等)
  • ...:存放資料的變數指標
回傳值為成功轉換的輸入項目數量。若發生錯誤,會回傳 0EOF-1)。

3.2 從字串取得整數

讓我們看看使用 sscanf 從字串中取得整數的方法。
#include <stdio.h>

int main() {
    char str[] = "123";
    int num;

    sscanf(str, "%d", &num);
    printf("取得的數值: %dn", num);

    return 0;
}
輸出結果
取得的數值: 123
如同這樣,指定 "%d" 後,即可從字串 "123" 取得整數 123

3.3 從字串取得多個值

使用 sscanf 可以從單一字串取得多個值。
#include <stdio.h>

int main() {
    char str[] = "100 200";
    int a, b;

    sscanf(str, "%d %d", &a, &b);
    printf("a = %d, b = %dn", a, b);

    return 0;
}
輸出結果
a = 100, b = 200
在解析以空格分隔的資料時很有用。

3.4 同時取得字串與數值

接下來介紹使用 sscanf 解析字串與數值兩者的方法。
#include <stdio.h>

int main() {
    char str[] = "name: John age: 30";
    char name[50];
    int age;

    sscanf(str, "name: %s age: %d", name, &age);
    printf("姓名: %s, 年齡: %dn", name, age);

    return 0;
}
輸出結果
姓名: John, 年齡: 30
如同這樣,結合 %s%d 即可同時取得字串與數值。

3.5 sscanf 回傳值的活用

檢查 sscanf 的回傳值即可判斷解析是否成功。
#include <stdio.h>

int main() {
    char str[] = "42";
    int num;
    int result = sscanf(str, "%d", &num);

    if (result == 1) {
        printf("取得成功: %dn", num);
    } else {
        printf("取得失敗n");
    }

    return 0;
}
輸出結果
取得成功: 42
回傳值 1 表示成功取得 1 個值。失敗時會是 0EOF,因此可進行適當的錯誤處理。

3.6 小結

  • sscanf 可從字串取得整數、浮點數、字串等。
  • 也能同時取得多筆資料。
  • 確認 sscanf 的回傳值即可進行錯誤處理。

4. sscanf 的應用技巧

sscanf 除了取得基本的數值和字串外,還可用於更高階的資料解析。在此,我們將詳細說明其應用方式,包括 格式指定子的活用特定資料的抽取逗號分隔資料的解析不同資料型別的處理錯誤處理

4.1 靈活運用格式指定子

sscanf 的格式指定子若能善加利用,將能更彈性地解析資料。特別是,透過以下的 指定子的組合,即可處理不同的資料型別。
指定子說明
%d取得整數
%f取得浮點數
%s取得字串(空白分隔)
%c取得單一字元
%[A-Za-z]取得特定字元範圍的字串

範例:取得含空格的字串

一般的 %s 會以空格分隔取得字串,但使用 %[^ ] 則可 取得至換行符號的全部字元
#include <stdio.h>

int main() {
    char str[] = "Hello World!";
    char result[50];

    sscanf(str, "%[^
]", result);
    printf("取得的字串: %sn", result);

    return 0;
}
輸出結果
取得的字串: Hello World!
這樣使用 %[^ ],即可正確取得含空格的字串。

4.2 抽取特定資料

sscanf 也適合從字串中 抽取特定資料

範例:日期解析

例如,從像 “2025-02-01” 這樣的日期資料中,可分別取得年、月、日。
#include <stdio.h>

int main() {
    char date[] = "2025-02-01";
    int year, month, day;

    sscanf(date, "%d-%d-%d", &year, &month, &day);
    printf("年: %d, 月: %d, 日: %dn", year, month, day);

    return 0;
}
輸出結果
年: 2025, 月: 2, 日: 1

4.3 解析逗號分隔資料

在處理 CSV(Comma-Separated Values)資料時,使用 sscanf 會很方便。

範例:CSV 資料解析

#include <stdio.h>

int main() {
    char input[] = "Apple,120,2.5";
    char product[20];
    int quantity;
    float price;

    sscanf(input, "%[^,],%d,%f", product, &quantity, &price);
    printf("商品名稱: %s, 數量: %d, 價格: %.2fn", product, quantity, price);

    return 0;
}
輸出結果
商品名稱: Apple, 數量: 120, 價格: 2.50

4.4 解析不同資料型別

介紹使用 sscanf 處理數值與字串混合資料的方法。

範例:ID、名稱、分數的解析

#include <stdio.h>

int main() {
    char input[] = "ID123 Name:Taro Score:95";
    char id[10], name[20];
    int score;

    sscanf(input, "ID%s Name:%s Score:%d", id, name, &score);
    printf("ID: %s, 名稱: %s, 分數: %dn", id, name, score);

    return 0;
}
輸出結果
ID: 123, 名稱: Taro, 分數: 95

4.5 應用錯誤處理

利用 sscanf 的返回值進行錯誤檢查是很重要的。

範例:執行輸入檢查

#include <stdio.h>

int main() {
    char str[] = "42";
    int num;
    int result = sscanf(str, "%d", &num);

    if (result == 1) {
        printf("取得成功: %dn", num);
    } else {
        printf("取得失敗n");
    }

    return 0;
}
輸出結果
取得成功: 42
這樣透過檢查 sscanf 的返回值,即可適當處理輸入錯誤。

4.6 小結

  • sscanf 的格式指定子若能活用,將能彈性地解析資料。
  • 可抽取特定資料(日期時間或逗號分隔資料等)。
  • 透過活用 sscanf 的返回值,可進行錯誤檢查,實現安全的處理。

5. 使用 sscanf 時的注意事項與安全風險

sscanf 是便利的函式,但若使用不當,可能會導致 緩衝區溢位未預期的行為。特別是處理從外部取得的資料時,需要適當的錯誤處理與驗證。 在此說明使用 sscanf 時應注意的要點,以及避免安全風險的方法。

5.1 緩衝區溢位的風險

使用 sscanf 時,若未考慮適當的緩衝區大小,可能會導致 緩衝區溢位

危險的程式碼範例

#include <stdio.h>

int main() {
    char name[10];
    char str[] = "VeryLongUserName";

    sscanf(str, "%s", name);
    printf("名稱: %sn", name);

    return 0;
}
問題點
  • name 的大小是 10 位元組,但 "VeryLongUserName" 是 16 位元組。
  • 緩衝區溢位發生,可能導致記憶體破壞

安全的程式碼範例

#include <stdio.h>

int main() {
    char name[10];
    char str[] = "VeryLongUserName";

    sscanf(str, "%9s", name);  // 指定 9,因為 9 個字元加上結尾的 '\0'
    printf("名稱: %sn", name);

    return 0;
}
使用 %9s 可限制最多讀取 9 個字元,防止記憶體破壞。

5.2 對於非預期輸入的錯誤檢查

如果不檢查 sscanf 的返回值,當傳入錯誤資料時,程式可能異常運作。

有問題的程式碼

#include <stdio.h>

int main() {
    char str[] = "abc";
    int num;

    sscanf(str, "%d", &num);  // 失敗但未檢查錯誤
    printf("取得的數值: %dn", num);

    return 0;
}
此時,num 的值不確定(垃圾值),可能導致未預期的行為。

安全的程式碼

#include <stdio.h>

int main() {
    char str[] = "abc";
    int num;

    if (sscanf(str, "%d", &num) == 1) {
        printf("取得的數值: %dn", num);
    } else {
        printf("錯誤: 無法取得數值。n");
    }

    return 0;
}
輸出結果
錯誤: 無法取得數值。
這樣即使有錯誤的輸入,也能安全地繼續處理。

5.3 輸入資料的驗證

當非預期的資料進入時,程式的運作可能不穩定。因此,在使用 sscanf 前,先對資料進行 驗證(validation) 是重要的。

範例:使用者輸入的驗證

#include <stdio.h>
#include <ctype.h>

int is_number(const char *str) {
    while (*str) {
        if (!isdigit(*str)) return 0;  // 若包含非數字則錯誤
        str++;
    }
    return 1;
}

int main() {
    char input[] = "42a";  // 作為數值不正確
    int num;

    if (is_number(input)) {
        sscanf(input, "%d", &num);
        printf("取得的數值: %dn", num);
    } else {
        printf("錯誤: 輸入的數值無效。n");
    }

    return 0;
}
輸出結果
錯誤: 輸入的數值無效。
這樣事先檢查資料是否為數值,即可實現安全的處理。

5.4 fgets 結合的安全字串處理

可以使用 fgets 取代 sscanf,安全地處理輸入。

安全的字串取得

#include <stdio.h>

int main() {
    char buffer[100];

    printf("請輸入字串: ");
    fgets(buffer, sizeof(buffer), stdin);

    printf("取得的字串: %s", buffer);

    return 0;
}
fgets 能防止緩衝區溢位,同時取得使用者輸入,與 sscanf 結合使用可提升安全性。

5.5 小結

  • 為防止緩衝區溢位,於格式指定子設定最大長度。
  • 檢查返回值,以確認資料取得是否成功。
  • 事先驗證輸入資料,防止處理不正當資料。
  • 善用 fgets 等,執行安全的輸入處理。

6. 常見錯誤與其對策

sscanf 是便利的函式,但若使用不當會導致意外的行為。本節將詳細說明初學者容易犯的錯誤與其對策

6.1 指標誤用導致的段錯誤 (Segmentation Fault)

錯誤程式碼

#include <stdio.h>

int main() {
    char *str = "123 456";  // 字串常量不可修改
    int a, b;

    sscanf(str, "%d %d", &a, &b);
    printf("a = %d, b = %dn", a, b);

    return 0;
}
此程式碼使用 sscanf 取得整數,但 str 指向字串常量("123 456",存放於不可修改的記憶體區域。 解決方案: 使用 char str[] 形式。

修正程式碼

#include <stdio.h>

int main() {
    char str[] = "123 456";  // 定義為陣列(可寫入)
    int a, b;

    sscanf(str, "%d %d", &a, &b);
    printf("a = %d, b = %dn", a, b);

    return 0;
}

6.2 格式指定子錯誤

錯誤程式碼

#include <stdio.h>

int main() {
    char str[] = "123.45";
    int num;

    sscanf(str, "%d", &num);  // 嘗試以整數解析
    printf("取得的數值: %dn", num);

    return 0;
}
此程式碼嘗試將 "123.45" 以整數 %d 解析。因小數點的關係,無法正確取得值。 解決方案: 使用 %f

修正程式碼

#include <stdio.h>

int main() {
    char str[] = "123.45";
    float num;

    sscanf(str, "%f", &num);
    printf("取得的數值: %.2fn", num);

    return 0;
}
輸出
取得的數值: 123.45

6.3 未進行錯誤檢查

錯誤程式碼

#include <stdio.h>

int main() {
    char str[] = "abc";
    int num;

    sscanf(str, "%d", &num);  // 字串 "abc" 無法轉換為數值
    printf("取得的數值: %dn", num);

    return 0;
}
"abc" 無法轉換為整數,num 的值會變成垃圾值,導致意外的行為。 解決方案: 檢查 sscanf 的返回值。

修正程式碼

#include <stdio.h>

int main() {
    char str[] = "abc";
    int num;

    if (sscanf(str, "%d", &num) == 1) {
        printf("取得的數值: %dn", num);
    } else {
        printf("錯誤: 無法取得數值。n");
    }

    return 0;
}
輸出
錯誤: 無法取得數值。

6.4 含空格的字串無法正確取得

錯誤程式碼

#include <stdio.h>

int main() {
    char str[] = "Hello World";
    char word1[10], word2[10];

    sscanf(str, "%s %s", word1, word2);
    printf("字詞1: %s, 字詞2: %sn", word1, word2);

    return 0;
}
%s 預設以空白作為分隔,因此會把 Hello World"World" 放入另一個變數。 解決方案: 使用 %[^ ] 取得直到換行的字串

修正程式碼

#include <stdio.h>

int main() {
    char str[] = "Hello World";
    char sentence[50];

    sscanf(str, "%[^
]", sentence);
    printf("取得的字串: %sn", sentence);

    return 0;
}
輸出
取得的字串: Hello World

6.5 數值超出範圍

錯誤程式碼

#include <stdio.h>

int main() {
    char str[] = "999999999999";
    int num;

    sscanf(str, "%d", &num);
    printf("取得的數值: %dn", num);

    return 0;
}
若超過 int 型的最大值(通常為 2147483647),會發生溢位,導致意外的行為。 解決方案: 使用 long long

修正程式碼

#include <stdio.h>

int main() {
    char str[] = "999999999999";
    long long num;

    sscanf(str, "%lld", &num);
    printf("取得的數值: %lldn", num);

    return 0;
}
輸出
取得的數值: 999999999999

6.6 總結

  • 避免指標誤用,並確保適當的記憶體。
  • 防止格式指定子錯誤,請依資料型別使用相應的指定子。
  • 務必進行錯誤檢查,以防止意外的行為。
  • 取得含空格的字串時,使用 %[^ ]
  • 若超過 int 範圍,請使用 long long
  • 檢查以避免傳遞 NULL 指標。

7. FAQ(常見問題)

sscanf 在使用時,開發者常有的疑問將詳細說明。從基本用法到進階,並以具體範例回答。

7.1 sscanf 與 scanf 的差異是?

scanfsscanf 兩者皆是根據格式指定子取得資料的函式,但 輸入來源不同。
項目sscanfscanf
輸入來源字串 (char[])標準輸入 (stdin)
用途解析現有字串取得使用者輸入
彈性高(資料轉換容易)低(即時輸入)
錯誤處理容易不易

範例:scanf 的使用

#include <stdio.h>

int main() {
    int num;
    printf("請輸入數值: ");
    scanf("%d", &num);
    printf("輸入的數值: %dn", num);
    return 0;
}
從標準輸入(鍵盤)取得值。

範例:sscanf 的使用

#include <stdio.h>

int main() {
    char str[] = "123";
    int num;
    sscanf(str, "%d", &num);
    printf("解析的數值: %dn", num);
    return 0;
}
將現有字串 "123" 轉換為數值。

7.2 如何使用 sscanf 取得含空格的字串?

預設的 %s 會將 空格視為分隔符。若要取得含空格的字串,請使用 %[^ ]

範例:取得含空格的字串

#include <stdio.h>

int main() {
    char str[] = "Hello World!";
    char result[50];

    sscanf(str, "%[^
]", result);
    printf("取得的字串: %sn", result);
    return 0;
}
輸出
取得的字串: Hello World!

7.3 sscanf 的返回值意義是?

sscanf 的返回值會回傳 成功取得的資料筆數。若取得失敗則回傳 0EOF(-1)。

範例:檢查返回值

#include <stdio.h>

int main() {
    char str[] = "42";
    int num;
    int result = sscanf(str, "%d", &num);

    if (result == 1) {
        printf("取得成功: %dn", num);
    } else {
        printf("取得失敗n");
    }

    return 0;
}
輸出
取得成功: 42

7.4 如何使用 sscanf 同時取得數值與字串?

sscanf 可同時解析數值與字串。

範例:ID、名稱、分數的解析

#include <stdio.h>

int main() {
    char input[] = "ID123 Name:Taro Score:95";
    char id[10], name[20];
    int score;

    sscanf(input, "ID%s Name:%s Score:%d", id, name, &score);
    printf("ID: %s, 名稱: %s, 分數: %dn", id, name, score);
    return 0;
}
輸出
ID: 123, 名稱: Taro, 分數: 95

7.5 如何進行 sscanf 的錯誤處理?

若不進行錯誤檢查,可能會有不預期的資料進入。 請使用 sscanf 的返回值進行檢查。

範例:輸入檢查

#include <stdio.h>

int main() {
    char str[] = "abc";  // 作為數值無效的字串
    int num;

    if (sscanf(str, "%d", &num) == 1) {
        printf("取得的數值: %dn", num);
    } else {
        printf("錯誤: 無法取得數值。n");
    }

    return 0;
}
輸出
錯誤: 無法取得數值。

7.6 是否應該改用 strtok

視情況而定,strtok 可能更適合。
用途sscanfstrtok
字串解析使用格式指定子指定分隔字元
取得方式依照格式取得值將字串切割為標記
彈性高(可取得整數、字串、小數點等)適合連續的標記處理

範例:使用 strtok 進行字串分割

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

int main() {
    char input[] = "apple,banana,orange";
    char *token = strtok(input, ",");

    while (token != NULL) {
        printf("水果: %sn", token);
        token = strtok(NULL, ",");
    }
    return 0;
}
輸出
水果: apple
水果: banana
水果: orange

7.7 總結

  • scanfsscanf 的差異sscanf 用於字串解析
  • 取得含空格的字串 → 使用 %[^ ]
  • 錯誤檢查 → 確認 sscanf 的返回值
  • 同時取得數值與字串 → 正確指定格式
  • 替代方案 → 判斷何時使用 strtok
  • 安全的使用方式指定緩衝區大小·錯誤檢查·搭配 fgets

8. 總結

在本文中,我們詳細說明了 C 語言的 sscanf 函數,從基本用法到應用、注意事項、常見錯誤及其對策、FAQ。最後,彙總 重要要點,並介紹安全且有效使用 sscanf 的最佳實踐。

8.1 本文的總結

sscanf 的基本

  • sscanf從字串解析資料 的函式。
  • scanf 不同,處理字串而非標準輸入 是其特點。
  • 基本語法:
  int sscanf(const char *str, const char *format, ...);
  • 格式指定子 可用於取得整數、浮點數、字串等。

sscanf 的使用方法

  • 取得數值
  sscanf("123", "%d", &num);
  • 取得多筆資料
  sscanf("100 200", "%d %d", &a, &b);
  • 同時取得數值與字串
  sscanf("ID123 Name:Taro Score:95", "ID%s Name:%s Score:%d", id, name, &score);
  • 取得含空格的字串
  sscanf("Hello World!", "%[^
]", buffer);

8.2 使用 sscanf 時的注意事項

錯誤的使用方式問題點解決方案
%s 未指定長度緩衝區溢位 風險%9s 等方式指定長度
未進行錯誤檢查處理未預期的資料 之可能性務必確認 sscanf 的返回值
NULL 指標段錯誤 (Segmentation Fault)確認指標不為 NULL
%d 取得 999999999999整數溢位使用 long long 型並指定 %lld

8.3 sscanf 的最佳實踐

✅ 1. 指定緩衝區大小

char name[10];
sscanf(str, "%9s", name);  // 取得最多 9 個字元(+ '\0')
防止緩衝區溢位!

✅ 2. 進行錯誤檢查

if (sscanf(str, "%d", &num) != 1) {
    printf("錯誤: 無法取得數值。n");
}
確認資料取得是否成功!

✅ 3. 結合使用 fgets

char buffer[100];
fgets(buffer, sizeof(buffer), stdin);
確保使用者輸入時的安全性!

✅ 4. 解析字串時,分別使用 strtoksscanf

char *token = strtok(str, ",");
while (token != NULL) {
    printf("%sn", token);
    token = strtok(NULL, ",");
}
sscanf 用於格式指定,strtok 用於切割 token!

8.4 為了活用本文

📌 實際撰寫程式碼並測試 📌 學習格式指定子的變化 📌 具備撰寫安全程式碼的意識

8.5 總結

🔹 code> 是 從字串解析資料 的便利函式 🔹 從 基本用法應用技巧 都能廣泛活用 🔹 了解 注意事項並適當進行錯誤處理 是重要的 🔹 透過指定緩衝區大小及結合使用 fgets 提升安全性 正確使用 sscanf,實踐安全的 C 語言程式設計!

9. 參考文獻

侍エンジニア塾