Appearance
输入 & 输出
输入和输出是程序与用户交互的重要方式。在C语言中,标准库提供了丰富的输入输出函数,用于从键盘读取数据和向屏幕输出数据。在本章节中,我们将学习C语言中的输入输出函数及其使用方法。
1. 标准输入输出流
在C语言中,有三个标准流:
- 标准输入流(stdin):通常对应于键盘,用于读取用户输入
- 标准输出流(stdout):通常对应于屏幕,用于输出数据
- 标准错误流(stderr):通常对应于屏幕,用于输出错误信息
这些流在<stdio.h>头文件中定义,是程序启动时自动打开的。
2. 格式化输出函数:printf
printf是C语言中最常用的输出函数,用于向标准输出流输出格式化的数据。
2.1 基本语法
c
int printf(const char *format, ...);2.2 说明
- format:格式控制字符串,包含普通字符和格式说明符
- ...:可变参数列表,对应格式说明符
- 返回值:成功输出的字符数
2.3 格式说明符
| 格式说明符 | 含义 | 示例 |
|---|---|---|
%d | 输出十进制整数 | printf("%d", 123); → 123 |
%i | 输出十进制整数(与%d相同) | printf("%i", 123); → 123 |
%o | 输出八进制整数 | printf("%o", 10); → 12 |
%x | 输出十六进制整数(小写) | printf("%x", 10); → a |
%X | 输出十六进制整数(大写) | printf("%X", 10); → A |
%u | 输出无符号十进制整数 | printf("%u", 123); → 123 |
%f | 输出浮点数 | printf("%f", 3.14); → 3.140000 |
%e | 输出科学计数法表示的浮点数(小写) | printf("%e", 123.45); → 1.234500e+02 |
%E | 输出科学计数法表示的浮点数(大写) | printf("%E", 123.45); → 1.234500E+02 |
%g | 自动选择%f或%e中较短的形式 | printf("%g", 123.45); → 123.45 |
%G | 自动选择%F或%E中较短的形式 | printf("%G", 123.45); → 123.45 |
%c | 输出单个字符 | printf("%c", 'A'); → A |
%s | 输出字符串 | printf("%s", "Hello"); → Hello |
%p | 输出指针地址 | printf("%p", &x); → 0x7ffc... |
%% | 输出百分号本身 | printf("%%"); → % |
2.4 修饰符
格式说明符可以包含修饰符,用于控制输出的宽度、精度等:
| 修饰符 | 含义 | 示例 |
|---|---|---|
%nd | 输出宽度为n的整数,右对齐 | printf("%5d", 123); → 123 |
%-nd | 输出宽度为n的整数,左对齐 | printf("%-5d", 123); → 123 |
%0nd | 输出宽度为n的整数,不足部分用0填充 | printf("%05d", 123); → 00123 |
%n.mf | 输出浮点数,总宽度为n,小数部分为m位 | printf("%8.2f", 3.14); → 3.14 |
%.mf | 输出浮点数,小数部分为m位 | printf("%.2f", 3.14159); → 3.14 |
%ns | 输出宽度为n的字符串,右对齐 | printf("%10s", "Hello"); → Hello |
%-ns | 输出宽度为n的字符串,左对齐 | printf("%-10s", "Hello"); → Hello |
2.5 示例
c
#include <stdio.h>
int main() {
int a = 123;
float b = 3.14159;
char c = 'A';
char d[] = "Hello, World!";
int *p = &a;
printf("整数: %d\n", a); // 整数: 123
printf("浮点数: %f\n", b); // 浮点数: 3.141590
printf("字符: %c\n", c); // 字符: A
printf("字符串: %s\n", d); // 字符串: Hello, World!
printf("指针地址: %p\n", p); // 指针地址: 0x7ffc...
// 使用修饰符
printf("\n使用修饰符:\n");
printf("右对齐,宽度5: %5d\n", a); // 右对齐,宽度5: 123
printf("左对齐,宽度5: %-5d\n", a); // 左对齐,宽度5: 123
printf("补0,宽度5: %05d\n", a); // 补0,宽度5: 00123
printf("浮点数,保留2位小数: %.2f\n", b); // 浮点数,保留2位小数: 3.14
printf("浮点数,宽度8,保留2位小数: %8.2f\n", b); // 浮点数,宽度8,保留2位小数: 3.14
printf("字符串,宽度15,左对齐: %-15s结束\n", d); // 字符串,宽度15,左对齐: Hello, World! 结束
return 0;
}3. 格式化输入函数:scanf
scanf是C语言中最常用的输入函数,用于从标准输入流读取格式化的数据。
3.1 基本语法
c
int scanf(const char *format, ...);3.2 说明
- format:格式控制字符串,包含格式说明符
- ...:可变参数列表,对应格式说明符,都是指针类型
- 返回值:成功读取并赋值的参数个数
3.3 格式说明符
| 格式说明符 | 含义 | 示例 |
|---|---|---|
%d | 读取十进制整数 | scanf("%d", &a); |
%i | 读取整数(自动识别十进制、八进制、十六进制) | scanf("%i", &a); |
%o | 读取八进制整数 | scanf("%o", &a); |
%x | 读取十六进制整数 | scanf("%x", &a); |
%u | 读取无符号十进制整数 | scanf("%u", &a); |
%f | 读取浮点数 | scanf("%f", &b); |
%e | 读取科学计数法表示的浮点数 | scanf("%e", &b); |
%c | 读取单个字符 | scanf("%c", &c); |
%s | 读取字符串(遇到空白字符停止) | scanf("%s", s); |
%p | 读取指针地址 | scanf("%p", &p); |
3.4 示例
c
#include <stdio.h>
int main() {
int a;
float b;
char c;
char d[50];
printf("请输入一个整数: ");
scanf("%d", &a);
printf("你输入的整数是: %d\n", a);
printf("请输入一个浮点数: ");
scanf("%f", &b);
printf("你输入的浮点数是: %.2f\n", b);
// 注意:在读取字符前,需要清除输入缓冲区的换行符
while (getchar() != '\n');
printf("请输入一个字符: ");
scanf("%c", &c);
printf("你输入的字符是: %c\n", c);
printf("请输入一个字符串: ");
scanf("%s", d); // 遇到空白字符停止
printf("你输入的字符串是: %s\n", d);
return 0;
}3.5 注意事项
- 地址传递:
scanf的参数必须是变量的地址,使用&运算符 - 字符串读取:
%s会在遇到空白字符(空格、制表符、换行符)时停止读取 - 输入缓冲区:输入的数据会先存储在输入缓冲区中,
scanf从缓冲区中读取数据 - 换行符处理:读取字符时,需要注意输入缓冲区中的换行符
- 返回值检查:应该检查
scanf的返回值,确保数据读取成功
4. 字符输入输出函数
4.1 字符输出函数:putchar
c
int putchar(int c);- 功能:向标准输出流输出一个字符
- 参数:要输出的字符(int类型,实际是char类型的ASCII码)
- 返回值:成功输出的字符,失败返回EOF
4.2 字符输入函数:getchar
c
int getchar(void);- 功能:从标准输入流读取一个字符
- 参数:无
- 返回值:成功读取的字符(int类型),失败返回EOF
4.3 示例
c
#include <stdio.h>
int main() {
char c;
printf("请输入一个字符: ");
c = getchar();
printf("你输入的字符是: ");
putchar(c);
printf("\n");
// 读取并输出多个字符,直到遇到换行符
printf("请输入一行字符: ");
while ((c = getchar()) != '\n') {
putchar(c);
}
printf("\n");
return 0;
}5. 字符串输入输出函数
5.1 字符串输出函数:puts
c
int puts(const char *s);- 功能:向标准输出流输出一个字符串,并自动添加换行符
- 参数:要输出的字符串
- 返回值:成功返回非负数,失败返回EOF
5.2 字符串输入函数:gets(不推荐使用)
c
char *gets(char *s);- 功能:从标准输入流读取一行字符串,直到遇到换行符
- 参数:存储字符串的字符数组
- 返回值:成功返回s,失败返回NULL
注意:gets函数不检查数组边界,可能导致缓冲区溢出,因此不推荐使用。
5.3 字符串输入函数:fgets(推荐使用)
c
char *fgets(char *s, int size, FILE *stream);- 功能:从指定流读取最多size-1个字符,直到遇到换行符或EOF
- 参数:
s:存储字符串的字符数组size:数组大小stream:输入流,标准输入为stdin
- 返回值:成功返回s,失败返回NULL
5.4 示例
c
#include <stdio.h>
#include <string.h>
int main() {
char s1[50] = "Hello, World!";
char s2[50];
// 输出字符串
puts(s1); // 输出Hello, World!并自动换行
// 输入字符串(使用fgets)
printf("请输入一行字符串: ");
fgets(s2, 50, stdin);
// 移除fgets读取的换行符
size_t len = strlen(s2);
if (len > 0 && s2[len - 1] == '\n') {
s2[len - 1] = '\0';
}
printf("你输入的字符串是: %s\n", s2);
return 0;
}6. 其他输入输出函数
6.1 格式化输出到字符串:sprintf
c
int sprintf(char *str, const char *format, ...);- 功能:将格式化的数据输出到字符串中
- 参数:
str:存储结果的字符数组format:格式控制字符串...:可变参数列表
- 返回值:成功输出的字符数
6.2 示例
c
#include <stdio.h>
int main() {
char s[100];
int a = 123;
float b = 3.14;
// 格式化输出到字符串
sprintf(s, "整数: %d, 浮点数: %.2f", a, b);
printf("格式化后的字符串: %s\n", s); // 格式化后的字符串: 整数: 123, 浮点数: 3.14
return 0;
}6.3 从字符串读取格式化数据:sscanf
c
int sscanf(const char *str, const char *format, ...);- 功能:从字符串中读取格式化的数据
- 参数:
str:要读取的字符串format:格式控制字符串...:可变参数列表,都是指针类型
- 返回值:成功读取并赋值的参数个数
6.4 示例
c
#include <stdio.h>
int main() {
char s[] = "123 3.14 A";
int a;
float b;
char c;
// 从字符串读取格式化数据
sscanf(s, "%d %f %c", &a, &b, &c);
printf("a = %d, b = %.2f, c = %c\n", a, b, c); // a = 123, b = 3.14, c = A
return 0;
}7. 输入输出的注意事项
7.1 输入缓冲区
当使用scanf、getchar等函数读取输入时,输入的数据会先存储在输入缓冲区中,然后由这些函数从缓冲区中读取。如果输入缓冲区中有剩余的数据,下一次读取会直接从缓冲区中获取,而不会等待用户输入。
7.2 示例:输入缓冲区问题
c
#include <stdio.h>
int main() {
int a;
char c;
printf("请输入一个整数: ");
scanf("%d", &a);
printf("你输入的整数是: %d\n", a);
printf("请输入一个字符: ");
c = getchar(); // 会读取输入缓冲区中的换行符
printf("你输入的字符是: '%c'\n", c); // 输出换行符
return 0;
}7.3 解决方法
c
#include <stdio.h>
int main() {
int a;
char c;
printf("请输入一个整数: ");
scanf("%d", &a);
printf("你输入的整数是: %d\n", a);
// 方法1:使用getchar清除换行符
while (getchar() != '\n');
printf("请输入一个字符: ");
c = getchar();
printf("你输入的字符是: '%c'\n", c);
return 0;
}7.4 安全性
- 缓冲区溢出:使用
gets函数时,可能会导致缓冲区溢出,应该使用fgets代替 - 格式字符串漏洞:使用
printf时,应该避免使用用户提供的格式字符串 - 类型匹配:确保
scanf的格式说明符与变量类型匹配
8. 示例:综合运用
让我们看一个综合运用输入输出函数的例子:
c
#include <stdio.h>
#include <string.h>
// 学生结构体
typedef struct {
int id;
char name[50];
int age;
float score;
} Student;
int main() {
Student students[3];
int i;
// 输入学生信息
for (i = 0; i < 3; i++) {
printf("请输入第%d个学生的信息:\n", i + 1);
printf("ID: ");
scanf("%d", &students[i].id);
// 清除输入缓冲区的换行符
while (getchar() != '\n');
printf("姓名: ");
fgets(students[i].name, 50, stdin);
// 移除fgets读取的换行符
size_t len = strlen(students[i].name);
if (len > 0 && students[i].name[len - 1] == '\n') {
students[i].name[len - 1] = '\0';
}
printf("年龄: ");
scanf("%d", &students[i].age);
printf("成绩: ");
scanf("%f", &students[i].score);
printf("\n");
}
// 输出学生信息
printf("学生信息表:\n");
printf("%-5s %-20s %-5s %-6s\n", "ID", "姓名", "年龄", "成绩");
printf("----------------------------------------\n");
for (i = 0; i < 3; i++) {
printf("%-5d %-20s %-5d %-6.1f\n",
students[i].id, students[i].name, students[i].age, students[i].score);
}
// 计算平均成绩
float sum = 0;
for (i = 0; i < 3; i++) {
sum += students[i].score;
}
float average = sum / 3;
printf("----------------------------------------\n");
printf("平均成绩: %.2f\n", average);
return 0;
}9. 小结
输入和输出是程序与用户交互的重要方式,C语言提供了丰富的输入输出函数。在本章节中,我们学习了:
- 标准输入输出流:
stdin、stdout、stderr - 格式化输出函数:
printf,用于向标准输出流输出格式化的数据 - 格式化输入函数:
scanf,用于从标准输入流读取格式化的数据 - 字符输入输出函数:
putchar、getchar,用于输入输出单个字符 - 字符串输入输出函数:
puts、fgets,用于输入输出字符串 - 其他输入输出函数:
sprintf、sscanf,用于字符串的格式化操作 - 输入输出的注意事项:输入缓冲区问题、安全性问题等
通过合理使用这些输入输出函数,可以编写出更加友好、交互性更强的C程序。在实际编程中,应该根据具体的需求选择合适的输入输出函数,并注意处理输入缓冲区、安全性等问题。