任何程序都离不开输入与输出(I/O)。C语言本身没有内置的输入输出语句,而是通过标准库函数来实现。
最常用的输入输出函数包括printf()(格式化输出)、scanf()(格式化输入)、
getchar() / putchar()(字符I/O)以及fgets() / puts()(字符串I/O)。
掌握这些函数是编写交互式程序的基础。
printf() 函数用于将数据按照指定的格式输出到标准输出(通常是屏幕)。其基本语法:
int printf(const char *format, ...);
返回值:成功时返回输出的字符数,失败时返回负数。
| 格式符 | 输出类型 | 示例 | 32
|---|---|---|
%d 或 %i | 十进制整数 | printf("%d", 100); |
%u | 无符号十进制整数 | printf("%u", 40000); |
%o | 八进制整数 | printf("%o", 100); → 144 |
%x / %X | 十六进制整数(小写/大写) | printf("%x", 100); → 64 |
%f | 浮点数(小数形式) | printf("%f", 3.14); → 3.140000 |
%e / %E | 浮点数(科学计数法) | printf("%e", 3.14); → 3.140000e+00 |
%g / %G | 根据值自动选择 %f 或 %e | printf("%g", 0.000123); → 0.000123 |
%c | 单个字符 | printf("%c", 'A'); |
%s | 字符串 | printf("%s", "Hello"); |
%p | 指针地址 | printf("%p", &x); |
%% | 输出百分号 | printf("%%"); → % |
可以在 % 和格式符之间插入修饰符来控制输出的宽度、精度、对齐方式等:
%5d 输出至少占5个字符宽度,右对齐;%-5d 左对齐。%.2f 保留两位小数;%.5s 只输出字符串前5个字符。+ 显示正号;0 用0填充空白;# 显示进制前缀(如0x)。#include <stdio.h>
int main() {
int num = 123;
double pi = 3.1415926;
char str[] = "C Programming";
printf("默认: %d\n", num);
printf("宽度5: %5d\n", num);
printf("左对齐: %-5d|\n", num);
printf("补零: %05d\n", num);
printf("精度2: %.2f\n", pi);
printf("宽度8精度3: %8.3f\n", pi);
printf("字符串截断: %.5s\n", str);
printf("科学计数法: %e\n", pi);
return 0;
}
scanf() 函数用于从标准输入(键盘)读取数据并按照格式存储到变量中。基本语法:
int scanf(const char *format, ...);
返回值:成功读取并赋值的变量个数,若失败返回EOF(-1)。
scanf 的第二个参数开始必须是变量的地址,对于普通变量需使用取地址符 &,对于指针或数组名则不用。
与printf类似,但scanf的格式说明符略有不同:
%d:读取十进制整数%f:读取浮点数(float)%lf:读取双精度浮点数(double)%c:读取单个字符(包括空白字符)%s:读取字符串,遇到空白字符停止%x:读取十六进制整数#include <stdio.h>
int main() {
int age;
float height;
double weight;
char name[50];
printf("请输入年龄: ");
scanf("%d", &age);
printf("请输入身高(cm): ");
scanf("%f", &height);
printf("请输入体重(kg): ");
scanf("%lf", &weight); // 注意double用%lf
printf("请输入姓名: ");
scanf("%s", name); // name是数组名,本身就是地址,不加&
printf("姓名: %s, 年龄: %d, 身高: %.1fcm, 体重: %.2fkg\n", name, age, height, weight);
return 0;
}
scanf("%s", ...) 不会读取空格,且不检查缓冲区大小,容易导致缓冲区溢出。更安全的做法是使用 fgets()。
scanf 严格按照格式字符串进行匹配,如果输入与预期不符,会提前结束并返回已成功读取的数量。常用技巧:
#include <stdio.h>
int main() {
int a, b;
printf("请输入两个整数: ");
int count = scanf("%d %d", &a, &b);
if (count == 2) {
printf("a = %d, b = %d\n", a, b);
} else {
printf("输入无效!\n");
}
return 0;
}
getchar() 从标准输入读取一个字符(包括空格和换行),putchar() 输出一个字符。
#include <stdio.h>
int main() {
char ch;
printf("请输入一个字符: ");
ch = getchar(); // 读取一个字符
printf("你输入的字符是: ");
putchar(ch); // 输出该字符
putchar('\n'); // 换行
// 循环读取直到回车
printf("请输入一行字符: ");
while ((ch = getchar()) != '\n') {
putchar(ch);
}
putchar('\n');
return 0;
}
getchar() 和 scanf 都受输入缓冲区影响,例如在 scanf 后直接使用 getchar() 可能会读取到残留的换行符,需要额外处理。
由于 scanf("%s") 不能读取带空格的字符串且不安全,推荐使用 fgets() 读取字符串。输出可使用 puts() 或 printf()。
#include <stdio.h>
int main() {
char line[100];
printf("请输入一行文字: ");
fgets(line, sizeof(line), stdin); // 读取最多99个字符+'\0',包括换行符
printf("你输入的是: ");
puts(line); // 输出字符串并自动换行
// 移除fgets读取的换行符(如果需要)
size_t len = strlen(line);
if (len > 0 && line[len-1] == '\n') {
line[len-1] = '\0';
}
printf("去掉换行后: %s\n", line);
return 0;
}
fgets() 替代 gets()(gets() 在C11中已废弃),可以有效防止缓冲区溢出。
当混合使用 scanf 和 getchar 或多次调用 scanf 时,输入缓冲区中残留的换行符可能导致程序行为异常。典型场景:
#include <stdio.h>
int main() {
int n;
char ch;
printf("输入一个整数: ");
scanf("%d", &n);
printf("输入一个字符: ");
ch = getchar(); // 这里直接读取了上次输入后的换行符
printf("n=%d, ch=%c\n", n, ch);
return 0;
}
解决方法:清空缓冲区。常见方式:
while (getchar() != '\n'); 读取并丢弃剩余字符。scanf 格式字符串中加入空格,如 scanf("%d ", &n);(会跳过空白)。fflush(stdin) 但此方法非标准(C标准未定义),不推荐。int n;
char ch;
scanf("%d", &n);
while (getchar() != '\n'); // 清空缓冲区
ch = getchar(); // 现在可以正确读取字符
#include <stdio.h>
#include <string.h>
#define MAX_NAME 50
int main() {
char name[MAX_NAME];
int age;
float score;
char gender;
printf("===== 学生信息录入 =====\n");
printf("姓名: ");
fgets(name, sizeof(name), stdin);
// 去除换行符
name[strcspn(name, "\n")] = '\0';
printf("年龄: ");
scanf("%d", &age);
while (getchar() != '\n'); // 清空缓冲区
printf("性别 (M/F): ");
scanf("%c", &gender);
while (getchar() != '\n');
printf("成绩: ");
scanf("%f", &score);
printf("\n===== 学生信息 =====\n");
printf("姓名: %s\n", name);
printf("年龄: %d\n", age);
printf("性别: %c\n", gender);
printf("成绩: %.1f\n", score);
return 0;
}
scanf("%d", age); 错误,应为 &age。double 使用 %lf,float 使用 %f。gets() 或 scanf("%s") 未限制长度可能导致溢出。fflush(stdin):虽然在某些编译器有效,但C标准未定义,不可移植。scanf 的返回值可能导致使用未初始化的变量。
输入输出是程序与用户交互的桥梁。熟练运用 printf、scanf 以及更安全的 fgets 可以让你编写出健壮的交互程序。
下一章我们将学习流程控制语句(条件判断与循环),使程序能够根据不同的条件执行不同的逻辑。