C 语言怎么从字符串里提取数字?附 3 种方法

编程狮(w3cschool.cn) 2026-08-20 14:26:31 浏览数 (45)
反馈

C 语言怎么从字符串里提取数字?

你在做竞赛题、读传感器数据或者解析混合文本时,一定碰到过这种情况:拿到了一串像 "abc123def456" 这样的字符,真正有用的数字却夹在字母中间。C语言提取数字,最直白的做法是用 sscanf 按格式读,要一段段抠就用指针遍历,要处理负号小数就得自己写判断。

本文基于 C99 标准验证,覆盖 sscanf、指针遍历、strtol 三种做法,并附上横向对比和踩坑清单。看完你不仅能从混合串里把数字抠出来,还能理解它们各自的适用边界,下次解析文本可以自己选型。今天这篇文章,编程狮就把这块讲透。

一、先搞清楚要提取的是哪种数字

所谓 C语言提取数字,指的是从一个包含字母、符号的混合字符串里,把其中的数值部分识别并取出来。它可能是一段(如 "123"),也可能是多段(如 "123""456"),还可能带负号或小数点。

C 语言没有 Java、Python 那样现成的「提取所有数字」函数,所以思路分两类:一类是按已知格式用 sscanf 读,另一类是自己遍历字符逐个拼。这种 字符判断 是字符串处理的基本功。

⚠️ 注意:C 语言字符串以 \0 结尾,手动遍历时一定要判断 '\0' 终止,否则会越界读到乱码甚至崩溃。

1.1 C 和 C++ 在这里怎么选

如果你的项目是 C++,可以直接用 std::string 配合更方便的函数;纯 C 环境则只能用字符数组和指针。C 语言教程 打好的基础,在 C++ 里同样用得上,两者字符串处理方式很接近,学透一个另一个很容易上手。

二、方法一:sscanf 按格式读取(最省事)

如果数字的位置和格式相对固定,比如 "id=123" 这种「前缀 + 数字」,用 sscanf 按格式符 %d 直接读最方便。它适合「格式已知、只取其中几段」的场景。

#include <stdio.h>


int main() {
    char s[] = "id=123";
    int n;
    sscanf(s, "id=%d", &n);  // n 得到 123
    printf("提取到的数字是 %d\n", n);
    return 0;
}

上面这段做的是:用 "id=%d" 这个格式串,跳过前面的 "id=",把后面的整数读进 n。前提是格式要对得上,否则读不到。如果字符串里数字前面还有别的内容,比如 "user:123" 想取 123,就得把 user: 也写进格式串跳过去,或者先用别的方式定位到数字起点再读。

💡 小提示:sscanf 的返回值等于成功读入的变量个数,读之前最好判断一下,避免读到的其实是垃圾值。

三、方法二:指针遍历逐个拼(灵活)

当数字散落在多处、格式不固定时,用指针从头扫到尾,遇到数字字符就拼进缓冲区,遇到非数字就当一个数字结束。这种写法完全自己掌控,能处理任意散落的数字段。这种纯 C 的写法在 C++ 里也完全成立,想系统学 C++ 可以看 C++ 教程

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


int main() {
    char s[] = "abc123def456";
    int i = 0, num = 0, started = 0;
    while (s[i] != '\0') {
        if (isdigit((unsigned char)s[i])) {
            num = num * 10 + (s[i] - '0');
            started = 1;
        } else if (started) {
            printf("提取到 %d\n", num);
            num = 0;
            started = 0;
        }
        i++;
    }
    if (started) printf("提取到 %d\n", num);
    return 0;
}

上面这段做的是:逐字符判断是不是数字,是就累加进 num,遇到字母就输出当前数字并清零。运行后会依次打印 123456

⚠️ 注意:isdigit 来自 ctype.h,判断字符是不是 0-9。直接写 s[i] &= '0' && s[i] <= '9' 也行,效果一样,还省一次函数调用,但可读性稍差。

四、方法三:strtol 按位置转换(带符号)

strtol 能把字符串开头一段合法的数字(支持正负号、进制)转成 long,并返回「下一个没转换的字符位置」,非常适合一段段提取,而且天然支持负号。它比 atoi 强大得多:atoi 只能转十进制整数且出错时一声不吭,而 strtol 能明确告诉你转换停在了字符串的哪个位置,便于继续往下解析。

#include <stdio.h>
#include <stdlib.h>


int main() {
    char s[] = "abc-123def456";
    char *p = s;
    long n;
    while (*p) {
        n = strtol(p, &p, 10);
        if (*p == '\0') break;
        printf("提取到 %ld\n", n);
        p++; // 跳过非数字字符
    }
    return 0;
}

上面这段做的是:从 p 指向的位置尝试转换数字,strtol 自动跳过前导非数字、转换 -123,并把 p 移到数字之后。循环往复就能把所有数字段抠出来。和字符串处理相对,如果你要做的是把内容从磁盘读进来再解析,可以看这篇 C 语言怎么从文件里读取内容

顺带说一下 strtol 的第三个参数 base:传 10 按十进制、16 可以解析十六进制(如 "0x1f"),传 0 则会自动识别 0x 前缀。解析进制混合的文本时,这个参数特别好用。

方法 适合场景 能否多段 支持符号
sscanf 格式固定 有限
指针遍历 格式自由 需自写
strtol 按位置转换

表:三种提取方法横向对比。格式固定用 sscanf,格式自由用指针遍历或 strtol,需要支持符号和进制用 strtol。

C 语言提取数字的三种方法怎么选?

五、踩坑清单

把读者最容易卡住的三个点列出来:

  • 越界遍历:手动遍历忘了判断 '\0',会一直读到字符串外面。
  • 数字溢出num = num * 10 + ... 累加大数可能超过 int 上限,超长数字用 long long 或字符串存。
  • sscanf 格式对不上:格式串和实际字符串不一致时读到的会是垃圾值,务必检查返回值。
  • strtol 忽略前导空白strtol 会跳过开头的空格再转换,如果输入可能以空白开头,要先把首尾空白清理掉,否则容易误读。

总结

C语言提取数字,格式固定用 sscanf 最省事,格式自由用指针遍历或 strtol 更灵活。新手建议先把字符遍历的逻辑想清楚,再选工具。

要点带走:

  • 遍历字符串一定要判断 '\0' 终止;
  • 累加大数注意 int 溢出,改 long long
  • sscanf 格式要对得上,否则读到的不可信。

把 C语言基础 打牢,尤其是 字符判断 这类基本功,你处理文本会更顺手。下一步建议把 C 语言字符串处理的基础打牢,再去了解 C++ 里更现代的 std::string 写法,处理文本会轻松很多。

一句话选型:格式已知、只要其中几段用 sscanf 最省事;数字散落、格式自由用指针遍历或 strtol 更灵活;需要支持负号、进制或一段段连续提取时,strtol 是首选。

延伸学习

想把 C 语言文本解析这块系统补齐,可以按这个顺序来:

  1. 想横向看各语言定位,可以看 编程语言对比,选语言时更有底气;
  2. 想动手练,C 语言入门体验课 是边学边写的形式,适合巩固。

常见问题

Q:sscanf 一次能提取多个数字吗?
A:能。格式串里写多个 %d 并传入多个地址即可,例如 sscanf(s, "%d,%d", &a, &b) 可同时读两个用逗号分隔的数字。

Q:怎么处理带小数点的数字?
A:sscanf%f 读小数;指针遍历则需要自己判断 '.' 并分别拼整数部分和小数部分,逻辑更繁琐。

Q:strtol 和 atoi 有什么区别?
A:atoi 只能转十进制整数且出错时不报错;strtol 能指定进制、能检测转换到哪里、出错时有更明确的返回,安全性和可控性都更好。

Q:提取出的数字想存成字符串而不是整数怎么办?
A:用指针遍历时,把数字字符直接追加进一个字符数组(记得留 \0 结尾)即可;用 sprintf(buf, "%d", n) 也能把整数重新格式化进字符串。

C

0 人点赞