printf与scanf输入输出格式如何规范使用?

99ANYc3cd6
预计阅读时长 21 分钟
位置: 首页 C语言 正文

它们都定义在标准库头文件 <stdio.h> 中,所以使用前必须包含它:

c语言printf和scanf
(图片来源网络,侵删)
#include <stdio.h>

printf - 格式化输出函数

printf 的作用是将格式化的数据输出到标准输出设备(通常是你的屏幕)。

基本语法

int printf(const char *format, ...);
  • 返回值:它返回一个整数,表示成功打印的字符个数(不包括结尾的空字符 \0),如果发生错误,则返回一个负数。
  • format (格式控制字符串):这是一个双引号括起来的字符串,它定义了输出的格式,它包含两种类型的字符:
    • 普通字符:原样输出。
    • 格式说明符:以 开头,用来指定后面变量的输出格式。
  • (可变参数列表):这是一个“可变参数列表”,意味着你可以传入任意数量的参数,每个参数对应 format 字符串中的一个格式说明符。

常用格式说明符

格式说明符 类型 示例
%d%i 有符号十进制整数 printf("%d", 123);
%c 单个字符 printf("%c", 'A');
%s 字符串 (字符数组) printf("%s", "Hello");
%f 单精度浮点数 (默认保留6位小数) printf("%f", 3.14);
%lf 双精度浮点数 (用于 scanf 读入,printf 中用 %f 也可) printf("%lf", 3.1415926);
%e%E 科学计数法表示的浮点数 printf("%e", 1000.0); // 输出 000000e+03
%g%G 根据数值大小自动选择 %f%e printf("%g", 1000.0); // 输出 1000
%x%X 无符号十六进制整数 (小写/大写) printf("%x", 255); // 输出 ff
%o 无符号八进制整数 printf("%o", 255); // 输出 377
%u 无符号十进制整数 printf("%u", 255);
输出一个百分号 printf("%%"); // 输出

进阶用法:修饰符

在 和字母之间可以添加修饰符来更精确地控制输出。

  • 宽度:用数字指定最小输出宽度,如果不足,则用空格填充。
      printf("%5d", 99);   // 输出 "   99" (99前有3个空格)
      printf("%5s", "Hi"); // 输出 "   Hi" (Hi前有3个空格)
  • 对齐:默认是右对齐,在宽度前加 表示左对齐。
      printf("%-5d", 99);  // 输出 "99   " (99后有3个空格)
  • 精度
    • 对于浮点数 (%f, %e, %g),.数字 表示小数点后保留的位数。
        printf("%.2f", 3.14159); // 输出 "3.14"
    • 对于字符串 (%s),.数字 表示输出的最大字符数。
        printf("%.5s", "HelloWorld"); // 输出 "Hello"
    • 对于整数 (%d),.数字 表示输出的最小数字位数,不足时用前导零填充。
        printf("%05d", 99); // 输出 "00099"

示例代码

#include <stdio.h>
int main() {
    int age = 25;
    float height = 175.5f;
    char initial = 'J';
    char name[] = "John Doe";
    printf("--- Personal Info ---\n");
    printf("Name: %s\n", name);
    printf("Initial: %c\n", initial);
    printf("Age: %d years old\n", age);
    printf("Height: %.1f cm\n", height); // 保留一位小数
    printf("----------------------\n");
    // 使用宽度和对齐
    printf("|%-10s|%-10s|\n", "Column1", "Column2");
    printf("|%-10d|%-10.2f|\n", 100, 3.14159);
    return 0;
}

输出结果:

--- Personal Info ---
Name: John Doe
Initial: J
Age: 25 years old
Height: 175.5 cm
----------------------
|Column1   |Column2   |
|100       |3.14      |

scanf - 格式化输入函数

scanf 的作用是从标准输入设备(通常是你的键盘)读取数据,并根据格式说明符将其存储到指定的变量中。

c语言printf和scanf
(图片来源网络,侵删)

基本语法

int scanf(const char *format, ...);
  • 返回值:它返回一个整数,表示成功匹配并赋值的参数个数,如果读取失败(例如输入不匹配类型),则返回 0EOF (文件结束符,通常是 -1)。
  • format (格式控制字符串):和 printf 类似,包含普通字符和格式说明符。
  • (可变参数列表):必须是变量的地址,而不是变量本身,因为 scanf 需要知道把读到的数据存放到哪里,获取地址需要使用取地址运算符 &

关键点:变量地址

这是 scanf 最容易出错的地方,你必须传递变量的地址。

  • int a; -> &a (获取变量 a 的内存地址)
  • float b; -> &b
  • char c; -> &c
  • char str[100]; -> str (数组名 str 会“退化”为其首元素的地址,所以不需要 &)

常用格式说明符

scanf 的格式说明符和 printf 基本对应,但注意浮点数用的是 %lf

格式说明符 对应的变量类型
%d int
%c char
%s char[] (字符数组/字符串)
%f float
%lf double
%x int (以十六进制读取)
%u unsigned int

输入时的空白字符处理

scanf 在读取数据时,会自动跳过输入中的空白字符,包括空格、制表符 \t 和换行符 \n

  • %d, %f, %lf, %s 等都会自动跳过前导空白。
  • %c 不会跳过任何字符,它会读取输入缓冲区中的下一个字符,无论它是什么(包括空格和换行符)。

示例代码

#include <stdio.h>
int main() {
    int id;
    char name[50];
    double score;
    printf("Please enter your student ID: ");
    scanf("%d", &id); // 读取一个整数到 id 的地址中
    printf("Please enter your name: ");
    scanf("%s", name); // 读取一个字符串,name本身就是地址
    printf("Please enter your score: ");
    scanf("%lf", &score); // 注意:读取 double 必须用 %lf
    printf("\n--- Student Record ---\n");
    printf("ID: %d\n", id);
    printf("Name: %s\n", name);
    printf("Score: %.2f\n", score);
    return 0;
}

运行示例:

c语言printf和scanf
(图片来源网络,侵删)
Please enter your student ID: 1001
Please enter your name: Alice
Please enter your score: 95.5
--- Student Record ---
ID: 1001
Name: Alice
Score: 95.50

scanf 的常见陷阱与解决方案

陷阱1:缓冲区残留的换行符

假设你想先读一个整数,再读一个字符:

#include <stdio.h>
int main() {
    int num;
    char ch;
    printf("Enter a number: ");
    scanf("%d", &num); // 用户输入 "10" 并按回车
    printf("Enter a character: ");
    scanf("%c", &ch); // 问题在这里!ch 会接收到用户按下的回车符 '\n'
    printf("You entered number: %d and char: %c\n", num, ch);
    return 0;
}

运行示例:

Enter a number: 10
Enter a character: You entered number: 10 and char:

你会发现 ch 被赋值为换行符,而不是你期望输入的字符。

解决方案: 在读取 %c 之前,主动清空输入缓冲区,一个简单的方法是读取并丢弃缓冲区中的所有字符,直到遇到换行符或文件结尾。

// 在第二个 scanf 之前加上这行代码
while (getchar() != '\n'); // 读取并丢弃所有字符,直到遇到换行符

陷阱2:%s 的不安全性

scanf("%s", name); 非常危险,因为它不知道 name 数组有多大,如果用户输入的字符串超过了数组的容量(name 只有50个字符,但用户输入了100个),就会发生缓冲区溢出,可能覆盖掉其他重要数据,导致程序崩溃或安全漏洞。

解决方案: 使用 scanf 的宽度限制功能,指定最大读取的字符数(要为字符串末尾的 \0 预留一个位置)。

scanf("%49s", name); // 最多读取49个字符,留1位给 '\0'

更安全的替代方案: 使用 fgets 函数来读取整行输入,因为它可以指定最大读取长度,并且会读取换行符(你可以手动去掉它)。

fgets(name, sizeof(name), stdin);
// 去掉末尾可能的换行符
name[strcspn(name, "\n")] = 0;

总结与对比

特性 printf scanf
功能 输出数据到屏幕 输入数据从键盘
参数 格式字符串 + 变量值 格式字符串 + 变量地址 (&var)
返回值 成功打印的字符数 成功赋值的变量个数
浮点数 %f float%f,读 double%lf
安全性 相对安全 需要格外小心缓冲区溢出和换行符问题
常见用法 printf("Hello, %s!", name); scanf("%d", &age);

掌握 printfscanf 是学习C语言的第一步,也是进行交互式程序设计的基础,理解它们的格式说明符、参数传递方式以及常见的陷阱,对于编写健壮的C程序至关重要。

-- 展开阅读全文 --
头像
dede软件列表标题如何直接下载?
« 上一篇 01-20
dede列表页如何调用父栏目名称?
下一篇 » 01-20
取消
微信二维码
支付宝二维码

目录[+]