<think>我们被要求展示C语言中sscanf函数的所有用法,并给出示例及详解。根据引用内容,sscanf函数用于从字符串中按照指定格式解析数据。我们将通过多个示例展示其各种用法。
### sscanf函数基本介绍
`sscanf`函数原型:
```c
int sscanf(const char *str, const char *format, ...);
```
- `str`:要解析的源字符串。
- `format`:格式控制字符串,指定如何解析输入。
- `...`:可变参数,为接收解析结果的变量地址。
- 返回值:成功解析并赋值的参数个数。若失败或到达字符串结尾,则返回EOF。
### 示例程序
以下程序展示了`sscanf`的各种用法:
```c
#include <stdio.h>
int main() {
const char *str = "John Doe 25 3.1415 010 0x1A";
char name[50], surname[50];
int age, oct, hex;
float pi;
int count;
// 1. 基本用法:匹配字符串和整数
count = sscanf(str, "%s %s %d", name, surname, &age);
printf("1. 解析了 %d 项: 姓名: %s %s, 年龄: %d\n", count, name, surname, age);
// 2. 匹配浮点数
sscanf(str, "%*s %*s %*d %f", &pi); // %* 跳过前面的项
printf("2. 圆周率: %.4f\n", pi);
// 3. 匹配八进制和十六进制数
sscanf(str, "%*s %*s %*d %*f %o %x", &oct, &hex);
printf("3. 八进制: %o (十进制: %d), 十六进制: %x (十进制: %d)\n", oct, oct, hex, hex);
// 4. 使用宽度指定符读取字符串(防止溢出)
char first[10];
sscanf("ABCDEFGHIJKLM", "%9s", first); // 最多读取9个字符+结束符
printf("4. 安全读取: %s\n", first);
// 5. 匹配特定字符
char ch;
sscanf("A", "%c", &ch);
printf("5. 字符: %c\n", ch);
// 6. 使用%n获取已读取的字符数
int pos;
sscanf("12345abc", "%d%n", &age, &pos);
printf("6. 数值: %d, 位置: %d (剩余字符串: '%s')\n", age, pos, "12345abc"+pos);
// 7. 匹配集合
char letters[10];
sscanf("abc123", "%[a-z]", letters); // 只匹配小写字母
printf("7. 字母集合: %s\n", letters);
// 8. 排除集合
char not_digits[10];
sscanf("abc123", "%[^0-9]", not_digits); // 匹配非数字字符
printf("8. 非数字字符: %s\n", not_digits);
// 9. 复杂格式匹配(日期)
int year, month, day;
sscanf("2023-09-15", "%d-%d-%d", &year, &month, &day);
printf("9. 日期: %d年%02d月%02d日\n", year, month, day);
// 10. 使用%i自动识别进制
int num1, num2;
sscanf("010 0x10", "%i %i", &num1, &num2);
printf("10. 自动识别: 010->%d (八进制), 0x10->%d (十六进制)\n", num1, num2);
return 0;
}
```
### 输出说明
1. **基本匹配**:`%s`匹配字符串,`%d`匹配整数
2. **跳过项**:`%*s`跳过不需要的字符串
3. **进制匹配**:
- `%o`:八进制
- `%x`:十六进制
4. **防止溢出**:`%9s`限制读取长度(避免缓冲区溢出)
5. **字符匹配**:`%c`匹配单个字符
6. **位置记录**:`%n`记录已读取字符数(非消耗性)
7. **集合匹配**:
- `%[a-z]`:匹配小写字母
- `%[^0-9]`:匹配非数字字符
8. **日期解析**:`%d-%d-%d`匹配年月日
9. **自动识别进制**:`%i`自动识别八进制/十六进制/十进制
### 关键注意事项
1. **缓冲区安全**:使用宽度限制(如`%9s`)防止溢出[^2]
2. **返回值检查**:始终检查返回值以确认解析成功项数
3. **空白符处理**:`%s`会跳过空白符,`%c`则不会
4. **集合匹配**:
- `%[a-z]`:匹配连续的小写字母,遇到非小写字母停止
- `%[^0-9]`:匹配直到遇到数字为止
5. **特殊格式符**:
- `%*`:跳过匹配项(不保存)
- `%n`:不消耗输入,仅记录当前位置
### 高级用法示例
```c
// 11. 混合使用多种格式
char data[] = "ID:007,Name:Bond,Salary:1000000";
char id[10], name[50];
int salary;
sscanf(data, "ID:%[^,],Name:%[^,],Salary:%d", id, name, &salary);
printf("11. 特工 %s (%s), 工资: $%d\n", name, id, salary);
// 12. 匹配到指定字符结束
char time[] = "12:34:56";
int h, m, s;
sscanf(time, "%d:%d:%d", &h, &m, &s);
printf("12. 时间: %02d:%02d:%02d\n", h, m, s);
```
> **注意**:`sscanf`对格式字符串要求严格,若实际输入不匹配则解析失败。例如日期分隔符必须是`-`才能匹配`%d-%d-%d`。
---
§§相关问题§§
1. 如何用`sscanf`解析带空格的字符串?
2. `sscanf`与`fscanf`、`scanf`有何区别?
3. 为什么`sscanf`解析浮点数时可能存在精度损失?
4. 如何用`sscanf`实现复杂文本的结构化提取?
5. `sscanf`在解析失败时如何安全处理?</think>### C语言 `sscanf` 函数用法详解及示例
`sscanf` 函数是 C 语言中强大的字符串解析工具,用于从字符串中按指定格式提取数据。其原型为:
```c
int sscanf(const char *str, const char *format, ...);
```
- **`str`**:要解析的源字符串
- **`format`**:格式控制字符串
- **`...`**:接收解析结果的变量地址
- **返回值**:成功解析并赋值的参数个数
---
### 一、基础用法示例
```c
#include <stdio.h>
int main() {
char buffer[] = "John 25 95.5";
char name[20];
int age;
float score;
// 基础解析:字符串+整数+浮点数
int count = sscanf(buffer, "%s %d %f", name, &age, &score);
printf("1. 解析 %d 项: 姓名: %s, 年龄: %d, 分数: %.1f\n",
count, name, age, score);
return 0;
}
```
**输出**:
```
1. 解析 3 项: 姓名: John, 年龄: 25, 分数: 95.5
```
**说明**:`%s`/`%d`/`%f` 分别匹配字符串、整数、浮点数[^3]
---
### 二、高级用法示例
```c
#include <stdio.h>
int main() {
char data[] = "2023-09-15 12:34:56 ID:007 Salary:5000.50";
int year, month, day, hour, min, sec, id;
char name[20];
float salary;
// 1. 日期时间解析(带格式分隔符)
sscanf(data, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
printf("2. 日期: %04d/%02d/%02d 时间: %02d:%02d:%02d\n",
year, month, day, hour, min, sec);
// 2. 带前缀的数值解析(跳过无关文本)
sscanf(data, "%*s %*s ID:%d Salary:%f", &id, &salary); // %*s 跳过字符串
printf("3. 员工ID: %03d, 工资: %.2f\n", id, salary);
// 3. 限制读取长度(防止溢出)
char text[] = "ABCDEFGHIJKLMNOPQRST";
char safe_str[10];
sscanf(text, "%9s", safe_str); // 只读取前9字符
printf("4. 安全截断: %s\n", safe_str);
// 4. 字符集合匹配
char colors[] = "Red,Green,Blue";
char color1[10], color2[10], color3[10];
sscanf(colors, "%[^,],%[^,],%s", color1, color2, color3); // [^,]匹配非逗号字符
printf("5. 颜色: %s | %s | %s\n", color1, color2, color3);
// 5. 十六进制解析
char hex_data[] = "Color: 0xFF00FF";
unsigned int rgb;
sscanf(hex_data, "Color: %x", &rgb); // %x 解析十六进制
printf("6. RGB值: %06X\n", rgb);
return 0;
}
```
**输出**:
```
2. 日期: 2023/09/15 时间: 12:34:56
3. 员工ID: 007, 工资: 5000.50
4. 安全截断: ABCDEFGHI
5. 颜色: Red | Green | Blue
6. RGB值: FF00FF
```
---
### 三、特殊用法技巧
#### 1. 使用 `%n` 获取解析位置
```c
char log[] = "Error:404 at line:50";
int err_code, line, pos;
sscanf(log, "Error:%d at line:%d%n", &err_code, &line, &pos);
printf("7. 错误码: %d, 位置: %d, 剩余文本: '%s'\n",
err_code, pos, log + pos);
```
**输出**:
```
7. 错误码: 404, 位置: 16, 剩余文本: ''
```
#### 2. 浮点数精度控制
```c
char measure[] = "Diameter:3.1415926535";
double pi;
sscanf(measure, "Diameter:%lf", &pi); // %lf 双精度
printf("8. 圆周率: %.10f\n", pi);
```
**输出**:
```
8. 圆周率: 3.1415926535
```
#### 3. 解析失败处理
```c
char invalid[] = "Age:twenty";
int age;
if(sscanf(invalid, "Age:%d", &age) != 1) {
printf("9. 解析失败: 非数字年龄\n");
}
```
**输出**:
```
9. 解析失败: 非数字年龄
```
---
### 四、关键注意事项
1. **缓冲区安全**
始终指定字符串读取长度(如 `%9s`)防止溢出[^2]
```c
char unsafe[5];
sscanf("LongString", "%4s", unsafe); // 安全:只读4字符
```
2. **格式匹配严格性**
格式字符串必须与输入完全匹配:
```c
// 失败示例(缺少冒号)
sscanf("Key=Value", "Key:%s", buf); // 返回0
```
3. **数值类型匹配**
| 格式符 | 类型 | 示例 |
|--------|----------------|------------|
| `%d` | `int` | `123` |
| `%ld` | `long` | `123456L` |
| `%f` | `float` | `3.14f` |
| `%lf` | `double` | `3.141592` |
| `%x` | 十六进制整数 | `0xFF` |
4. **空白符处理**
`%s` 会自动跳过前导空白符,`%c` 则不会:
```c
sscanf(" A B", "%c", &ch); // ch=' ' (空格)
```
> **最佳实践**:始终检查返回值,验证成功解析的参数数量[^3]。
---