使用 scanf 函数 (最常见)
scanf 是C标准库中的函数,用于从标准输入(通常是键盘)读取格式化数据。

(图片来源网络,侵删)
基本语法
int scanf(const char *format, ...);
format: 格式化字符串,用于告诉scanf期望读取什么样的数据,对于float,格式说明符是%f。- 可变参数列表,需要传入与
format中说明符数量和类型相匹配的变量的地址。
示例代码
#include <stdio.h>
int main() {
float price;
float temperature;
// 提示用户输入
printf("请输入一个商品的价格: ");
// 从键盘读取一个浮点数,存入 price 变量的地址中
// & 是取地址运算符
scanf("%f", &price);
printf("你输入的价格是: %.2f\n", price); // %.2f 表示保留两位小数
printf("请输入当前的温度: ");
scanf("%f", &temperature);
printf("你输入的温度是: %.1f\n", temperature); // %.1f 表示保留一位小数
return 0;
}
编译和运行
假设你将代码保存为 get_float.c:
# 编译 (使用 gcc) gcc get_float.c -o get_float # 运行 ./get_float
运行示例:
请输入一个商品的价格: 99.98
你输入的价格是: 99.98
请输入当前的温度: 36.6
你输入的温度是: 36.6
使用 scanf_s 函数 (更安全)
scanf_s 是微软在Visual C++ (MSVC) 中引入的一个安全版本的scanf,它在标准C中不是必须的,但在Windows平台上开发时强烈推荐使用。
scanf_s 与 scanf 的主要区别在于,对于读取某些类型的数据(如char, wchar_t, string),它需要一个额外的参数来指定缓冲区的大小,以防止缓冲区溢出,对于%f(读取float)和%lf(读取double),行为与scanf完全相同,不需要额外参数。
示例代码 (仅适用于MSVC编译器,如Visual Studio)
#include <stdio.h>
int main() {
float score;
printf("请输入你的考试分数: ");
// 在MSVC下,使用 scanf_s 读取 float 和 scanf 一样
scanf_s("%f", &score);
printf("你的分数是: %f\n", score);
return 0;
}
注意: 如果你使用的是GCC或Clang等非MSVC编译器,scanf_s是不可用的,为了代码的可移植性,scanf通常是更好的选择。
从字符串转换获取 float
你得到的数据可能不是直接从键盘输入的,而是来自一个字符串(从文件中读取的一行,或者网络接收到的数据),这时,你可以使用标准库中的 strtof 函数。
strtof (string to float) 函数非常强大,因为它可以:
- 将字符串开头的数字部分转换为
float。 - 能够识别并跳过前导的空白字符。
- 能够处理科学计数法(
23e4)。 - 最重要的是,它能告诉你转换是否成功,以及是否有额外的非数字字符在字符串后面。
函数原型
float strtof(const char *nptr, char **endptr);
nptr: 指向要转换的字符串的指针。endptr: 一个char**类型的指针。endptr不是NULL,函数会将转换停止后的位置(即第一个非数字字符的地址)存储在*endptr指向的变量中,这对于检查整个字符串是否都是有效的数字非常有用。- 返回值:
- 成功时,返回转换后的
float值。 - 如果转换的值超出了
float的表示范围,会返回HUGE_VALF(表示正无穷)或-HUGE_VALF(表示负无穷),并设置errno为ERANGE。 - 如果无法转换任何数字(例如字符串是 "abc"),则返回
0。
- 成功时,返回转换后的
示例代码
#include <stdio.h>
#include <stdlib.h> // 必须包含 strtof 的头文件
#include <errno.h> // 用于检查 errno
int main() {
const char *str1 = "123.45";
const char *str2 = "-99.99";
const char *str3 = "3.14e2"; // 科学计数法,等于 314.0
const char *str4 = " 123.45abc"; // 前导空格和尾部字符
const char *str5 = "hello"; // 无效数字
char *endptr; // 用于 strtof 的 endptr 参数
float num;
// 转换 str1
num = strtof(str1, &endptr);
printf("'%s' -> %f\n", str1, num);
// 转换 str2
num = strtof(str2, &endptr);
printf("'%s' -> %f\n", str2, num);
// 转换 str3
num = strtof(str3, &endptr);
printf("'%s' -> %f\n", str3, num);
// 转换 str4,演示 endptr 的作用
num = strtof(str4, &endptr);
printf("'%s' -> %f\n", str4, num);
printf("转换停止在字符: '%c'\n", *endptr); // 会打印 'a'
// 转换 str5,演示无效输入
errno = 0; // 在调用 strtof 前重置 errno
num = strtof(str5, &endptr);
if (errno == ERANGE) {
printf("错误:数值超出范围!\n");
} else if (endptr == str5) {
// endptr 仍然指向字符串的开头,说明没有数字被转换
printf("错误:'%s' 不是有效的数字!\n", str5);
} else {
printf("'%s' -> %f\n", str5, num);
}
return 0;
}
输出:
'123.45' -> 123.450000
'-99.99' -> -99.990000
'3.14e2' -> 314.000000
' 123.45abc' -> 123.450000
转换停止在字符: 'a'
错误:'hello' 不是有效的数字!
其他注意事项
float vs. double
在C语言中,float 是单精度浮点数,而 double 是双精度浮点数。
- 精度:
double提供的精度大约是float的两倍,能表示更多的小数位。 - 内存占用:
float通常占用4字节,double通常占用8字节。 - 性能: 在现代大多数处理器上,
float和double的计算速度几乎没有差别,除非有特殊的内存限制或遵循特定的数据格式标准,否则推荐直接使用double。
如果你使用 double,scanf 的格式说明符是 %lf (long float)。
double my_double;
scanf("%lf", &my_double); // 注意是 lf,不是 f
错误处理
scanf 在读取失败时会返回成功读取的项目个数。scanf("%f %d", &f, &i) 如果用户输入了 abc 123,它会返回 0,因为没有任何数据被成功读取,如果输入了 34 abc,它会返回 1,只成功读取了float,int变量i不会被赋值。
利用这个特性,你可以检查输入是否有效:
float number;
if (scanf("%f", &number) != 1) {
printf("输入无效,请输入一个数字!\n");
// 清除输入缓冲区中的错误数据,防止无限循环
while (getchar() != '\n');
}
| 方法 | 描述 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
scanf("%f", ...) |
从标准输入读取 | 简单直接,最常用 | 不安全,无法检测错误输入 | 交互式程序,简单的命令行工具 |
scanf_s("%f", ...) |
MSVC下的安全版本 | 在MSVC下更安全 | 可移植性差 | Windows平台下的C程序开发 |
strtof(...) |
从字符串转换 | 功能强大,能处理科学计数法,提供详细的错误信息 | 比scanf稍复杂 |
解析文件、网络数据、API返回的字符串等 |
对于初学者和大多数从键盘输入的场景,scanf("%f", &my_float) 是最需要掌握的方法。
