<think>我们被要求写一个C程序,展示sprintf的所有用法。sprintf函数用于将格式化的数据写入字符串中。它的原型如下:
int sprintf(char *str, const char *format, ...);
我们将通过多个示例来展示不同的格式化用法,包括基本类型、宽度和精度控制、对齐、科学计数法、字符串截取等。
注意:由于sprintf可能存在缓冲区溢出的风险,我们在使用时会确保缓冲区足够大,或者使用snprintf(但题目要求sprintf)。
我们将创建一个程序,包含多个示例,每个示例都打印出格式化后的字符串。
步骤:
1. 包含头文件<stdio.h>
2. 在main函数中,定义足够的缓冲区(例如buf[100])
3. 使用多个sprintf示例,并打印结果。
示例包括:
1. 整数和浮点数
2. 指定宽度和精度
3. 左对齐和右对齐
4. 字符串格式化
5. 八进制和十六进制
6. 科学计数法
7. 混合格式化
8. 使用*号动态指定宽度和精度
9. 格式化字符
10. 将多个数据格式化为一个字符串
同时,我们也会注意一些特殊用法,比如使用%n来记录已写入的字符数(虽然不常用,但也展示)。
最后,我们将输出每个示例的格式化字符串。
注意:由于sprintf不会检查目标缓冲区的大小,因此我们必须确保缓冲区足够大以避免溢出。
程序结构:
- 每个示例前打印说明
- 使用sprintf格式化
- 打印结果
我们将使用一个缓冲区,并在每个示例后打印并重置缓冲区(如果需要,也可以使用不同的缓冲区,但这里我们复用同一个,并在每个示例后打印)。
由于sprintf返回写入的字符数(不包括结尾的'\0'),我们也可以打印这个返回值。
但是,为了简洁,我们主要展示格式化结果。
开始编写程序:</think>### C语言 `sprintf` 函数完整用法示例程序
`sprintf` 是 C 语言中强大的字符串格式化函数,用于将格式化的数据写入字符串缓冲区。其函数原型为:
```c
int sprintf(char *str, const char *format, ...);
```
- **`str`**:目标字符串缓冲区
- **`format`**:格式控制字符串
- **`...`**:要格式化的数据
- **返回值**:成功写入的字符数(不包括结尾的 `\0`)
---
### 完整示例程序
```c
#include <stdio.h>
#include <math.h> // 用于数学函数
int main() {
char buffer[256]; // 目标缓冲区
// 1. 基本数据类型格式化
int num = 42;
float pi = 3.1415926535;
double sqrt2 = sqrt(2);
char letter = 'A';
sprintf(buffer, "整数: %d, 浮点数: %.2f, 双精度: %.4lf, 字符: %c",
num, pi, sqrt2, letter);
printf("1. %s\n", buffer);
// 2. 字符串拼接
char name[] = "Alice";
int age = 30;
sprintf(buffer, "姓名: %s, 年龄: %d", name, age);
printf("2. %s\n", buffer);
// 3. 数值格式控制
int value = 12345;
// 宽度与对齐
sprintf(buffer, "右对齐: [%8d], 左对齐: [%-8d], 补零: [%08d]",
value, value, value);
printf("3. %s\n", buffer);
// 4. 浮点数精度控制
double precise = 3.141592653589793;
sprintf(buffer, "默认: %f, 2位小数: %.2f, 科学计数: %.4e",
precise, precise, precise);
printf("4. %s\n", buffer);
// 5. 十六进制和八进制
int hex_num = 255;
sprintf(buffer, "十六进制: 0x%X, 小写: 0x%x, 八进制: %o",
hex_num, hex_num, hex_num);
printf("5. %s\n", buffer);
// 6. 指针格式化
int var = 100;
int *ptr = &var;
sprintf(buffer, "变量地址: %p, 值: %d", (void*)ptr, *ptr);
printf("6. %s\n", buffer);
// 7. 使用%n记录写入字符数
int count;
char text[] = "Hello World";
sprintf(buffer, "文本: %s%n", text, &count);
printf("7. %s (写入字符数: %d)\n", buffer, count);
// 8. 动态宽度和精度
int width = 10;
int precision = 3;
sprintf(buffer, "动态控制: %*.*f", width, precision, pi);
printf("8. %s\n", buffer);
// 9. 混合格式复杂示例
time_t now = time(NULL);
struct tm *t = localtime(&now);
sprintf(buffer, "%04d年%02d月%02d日 %02d:%02d:%02d | 状态: %s",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec,
(num > 40) ? "正常" : "警告");
printf("9. %s\n", buffer);
// 10. 安全使用建议(防止缓冲区溢出)
char long_str[] = "这是一个非常长的字符串,可能超过缓冲区大小";
int safe_count = snprintf(buffer, sizeof(buffer), "截断测试: %s", long_str);
if(safe_count >= sizeof(buffer)) {
printf("10. 警告: 需要 %d 字节,缓冲区仅 %zu 字节\n",
safe_count + 1, sizeof(buffer));
}
printf("10. %s\n", buffer);
return 0;
}
```
---
### 关键用法解析
#### 1. 基础格式化
```c
sprintf(buffer, "整数: %d, 浮点数: %.2f", 42, 3.1415);
```
- `%d`:格式化整数
- `%.2f`:保留2位小数的浮点数[^1]
#### 2. 宽度和对齐控制
```c
sprintf(buffer, "[%8s] [%-8s]", "右对齐", "左对齐");
```
- `%8s`:右对齐,宽度8字符
- `%-8s`:左对齐,宽度8字符
- `%08d`:用0填充空白(如`00123`)
#### 3. 动态格式控制
```c
int width = 10, prec = 3;
sprintf(buffer, "%*.*f", width, prec, 3.141592);
// 等效于 "%10.3f"
```
#### 4. 特殊格式符
| 格式符 | 用途 | 示例 |
|--------|---------------------|--------------|
| `%p` | 指针地址 | `0x7ffd...` |
| `%x` | 十六进制(小写) | `ff` |
| `%X` | 十六进制(大写) | `FF` |
| `%o` | 八进制 | `377` |
| `%e` | 科学计数法 | `3.14e+00` |
| `%n` | 记录已写入字符数 | 存储到整型变量 |
#### 5. 安全注意事项
```c
// 危险:可能溢出
sprintf(small_buf, "%s", long_str);
// 安全:使用 snprintf
snprintf(buf, sizeof(buf), "%s", long_str);
```
始终检查返回值:
```c
int needed = snprintf(NULL, 0, "格式: %d", large_num);
if(needed > buf_size) {
// 处理缓冲区不足
}
```
---
### 程序输出示例
```
1. 整数: 42, 浮点数: 3.14, 双精度: 1.4142, 字符: A
2. 姓名: Alice, 年龄: 30
3. 右对齐: [ 12345], 左对齐: [12345 ], 补零: [00012345]
4. 默认: 3.141593, 2位小数: 3.14, 科学计数: 3.1416e+00
5. 十六进制: 0xFF, 小写: 0xff, 八进制: 377
6. 变量地址: 0x7ffc..., 值: 100
7. 文本: Hello World (写入字符数: 11)
8. 动态控制: 3.142
9. 2023年09月15日 14:30:22 | 状态: 正常
10. 截断测试: 这是一个非常长的字符...
```
> **最佳实践**:
> 1. 对用户输入数据使用 `snprintf` 防止缓冲区溢出[^2]
> 2. 浮点数精度控制可避免累积误差
> 3. 检查返回值确保格式化成功
> 4. 复杂格式建议分步处理