是什么 📚 C 语言标准输入输出库的 C++ 版本。
📚 C 语言里叫 <stdio.h>,C++ 里改叫 <stdio.h>,所有函数都放在 std 命名空间里。
📚 它提供了 printf、scanf、 fopen 等经典的格式化 IO 函数。
类比 🏠 如果说 <iostream> 是"用流的方式搬数据"(cin >> x,cout << x), 那 <stdio.h> 就是"用格式化字符串搬数据"(printf("%d", x))。
🏠 iostream 类型安全、可扩展;
🏠 cstdio 更简洁、格式化更灵活、运行更快, 但写错格式化符会出 bug。
常用函数(每个函数附完整示例)
控制台输入输出 printf(格式, 参数...) —— 格式化输出到屏幕
复制 #include <stdio.h>
int main () {
printf ("年龄:%d,成绩:%.1f\n" , 20 , 95.5 );
return 0 ;
}scanf(格式, 地址...) —— 从键盘格式化读入(变量要加 &)
复制 #include <stdio.h>
int main () {
int x;
printf ("请输入一个整数:" );
scanf ("%d" , &x);
printf ("你输入的是:%d\n" , x);
return 0 ;
}puts(字符串) —— 输出字符串并自动换行
复制 #include <stdio.h>
int main () {
puts ("Hello World" ); // 输出后自动换行
return 0 ;
}gets(字符串) —— 读一行(已废弃,不安全,勿用,用 fgets)
复制 #include <stdio.h>
int main () {
// 不要使用 gets(),缓冲区无边界检查,会溢出
printf ("gets()已废弃,请使用fgets()\n" );
return 0 ;
}getchar() —— 读一个字符,返回 int(EOF 时为 -1)
复制 #include <stdio.h>
int main () {
printf ("请输入一个字符:" );
int c = getchar ();
putchar (c);
putchar ('\n' );
return 0 ;
}putchar(字符) —— 输出一个字符
复制 #include <stdio.h>
int main () {
putchar ('A' );
putchar ('\n' );
return 0 ;
}文件操作 🎯 fopen(文件名, 模式) —— 打开文件,成功返回 FILE*,失败返回 NULL
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
printf ("文件打开成功\n" );
fclose (fp);
} else {
printf ("文件打开失败\n" );
}
return 0 ;
}fopen(文件名, 模式) —— 打开文件,成功返回 FILE*,失败返回 NULL
📌 模式:"r"读、"w"写(覆盖)、"a"追加、"r+"读写、"w+"读写(覆盖)、"a+"读写(追加)
📌 加 b 表示二进制:"rb"、"wb"、"ab"
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "w" );
if (fp == NULL) {
printf ("文件打开失败\n" );
return 1 ;
}
fprintf (fp, "Hello World\n" );
fclose (fp);
printf ("文件写入成功\n" );
return 0 ;
}fclose(文件指针) —— 关闭文件,刷新缓冲区
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "w" );
if (fp) {
fprintf (fp, "hello\n" );
fclose (fp);
printf ("文件已关闭\n" );
}
return 0 ;
}fprintf(文件, 格式...) —— 格式化写入文件
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("scores.txt" , "w" );
if (fp) {
fprintf (fp, "%s 考了 %d 分\n" , "小明" , 88 );
fclose (fp);
}
return 0 ;
}fscanf(文件, 格式...) —— 从文件格式化读取
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("scores.txt" , "r" );
if (fp) {
int score;
fscanf (fp, "%d" , &score);
printf ("分数:%d\n" , score);
fclose (fp);
}
return 0 ;
}fgets(缓冲区, 大小, 文件) —— 读一行(含换行符),最多读 大小-1 个字符
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
char buf[256 ];
fgets (buf, sizeof (buf), fp);
printf ("读到:%s" , buf);
fclose (fp);
}
return 0 ;
}fputs(字符串, 文件) —— 写字符串(不自动加换行)
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "w" );
if (fp) {
fputs ("一行文字\n" , fp);
fclose (fp);
}
return 0 ;
}fread(缓冲区, 大小, 个数, 文件) —— 二进制读,返回实际读到的元素数
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.bin" , "rb" );
if (fp) {
int arr[10 ];
size_t n = fread (arr, sizeof (int ), 10 , fp);
printf ("读到 %zu 个整数\n" , n);
fclose (fp);
}
return 0 ;
}fwrite(缓冲区, 大小, 个数, 文件) —— 二进制写,返回实际写入的元素数
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.bin" , "wb" );
if (fp) {
int arr[10 ] = {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 };
size_t n = fwrite (arr, sizeof (int ), 10 , fp);
printf ("写入 %zu 个整数\n" , n);
fclose (fp);
}
return 0 ;
}feof(文件) —— 是否到文件末尾(到末尾返回非0)
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
char buf[256 ];
while (!feof (fp)) {
if (fgets (buf, 256 , fp))
printf ("%s" , buf);
}
fclose (fp);
}
return 0 ;
}ferror(文件) —— 是否出错(出错返回非0)
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
char buf[256 ];
fgets (buf, 256 , fp);
if (ferror (fp)) printf ("读取出错\n" );
fclose (fp);
}
return 0 ;
}rewind(文件) —— 把文件指针移回开头
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
char buf[256 ];
fgets (buf, 256 , fp);
rewind (fp); // 读完后回到开头再读一遍
fgets (buf, 256 , fp);
fclose (fp);
}
return 0 ;
}fseek(文件, 偏移, 起点) —— 移动文件指针;起点:SEEK_SET/SEEK_CUR/SEEK_END
复制 #include <stdio.h>
int main () {
FILE * fp = fopen ("data.txt" , "r" );
if (fp) {
fseek (fp, 10 , SEEK_SET); // 从开头向后移10字节
char buf[256 ];
fgets (buf, 256 , fp);
fclose (fp);
}
return 0 ;
}字符串缓冲区操作 🎯 sprintf(缓冲区, 格式...) —— 格式化写入字符数组(不安全,可能溢出)
复制 #include <stdio.h>
int main () {
char buf[100 ];
sprintf (buf, "x=%d" , 42 );
printf ("%s\n" , buf);
return 0 ;
}snprintf(缓冲区, 大小, 格式...) —— 安全版本,最多写 大小-1 个字符
复制 #include <stdio.h>
int main () {
char buf[100 ];
snprintf (buf, sizeof (buf), "x=%d" , 42 );
printf ("%s\n" , buf);
return 0 ;
}sscanf(字符串, 格式...) —— 从字符串格式化读取
复制 #include <stdio.h>
int main () {
int a, b;
sscanf ("10 20" , "%d %d" , &a, &b);
printf ("a=%d, b=%d\n" , a, b);
return 0 ;
}格式化说明符(printf / scanf 通用核心)
说明符 对应类型 示例
%d / %i int printf("%d", 42)
%ld long printf("%ld", 100000L)
%lld long long printf("%lld", 9999999999LL)
%u unsigned int printf("%u", 100u)
%f float/double printf("%f", 3.14)
%lf double(scanf) scanf("%lf", &x)
%e / %E 科学计数法 printf("%e", 1000.0) → 1.000000e+03
%g / %G 自动选格式 printf("%g", 3.14) → 3.14
%c char printf("%c", 'A')
%s char* 字符串 printf("%s", "hello")
%p 指针 printf("%p", ptr)
%% 百分号本身 printf("100%%") → 100%
%x / %X 十六进制 printf("%x", 255) → ff
%o 八进制 printf("%o", 8) → 10
进阶格式:%[宽度][.精度]说明符
printf("%5d", 42) → " 42"(占5位,右对齐)
printf("%-5d", 42) → "42 "(左对齐)
printf("%.2f", 3.14159) → "3.14"(保留2位小数)
printf("%05d", 42) → "00042"(补零)
复制 #include <stdio.h>
int main () {
// 基本输出
int age = 20 ;
double score = 95.5 ;
printf ("年龄:%d,成绩:%.1f\n" , age, score);
// 基本输入(注意变量要加 & 取地址)
int x;
printf ("请输入一个整数:" );
scanf ("%d" , &x);
printf ("你输入的是:%d\n" , x);
// 写文件
FILE * fp = fopen ("data.txt" , "w" );
if (fp) {
fprintf (fp, "Hello %s, 你考了 %d 分\n" , "小明" , 88 );
fclose (fp);
}
// 读文件
fp = fopen ("data.txt" , "r" );
if (fp) {
char buf[256 ];
while (fgets (buf, sizeof (buf), fp)) {
printf ("%s" , buf);
}
fclose (fp);
}
// 安全格式化到字符串
char buffer[100 ];
snprintf (buffer, sizeof (buffer), "PI = %.4f" , 3.14159 );
printf ("%s\n" , buffer);
return 0 ;
}文件打开模式
"r" —— 只读(文件必须存在)
"w" —— 只写(文件不存在则创建,存在则清空!)
"a" —— 追加写(文件不存在则创建,存在则在末尾加)
"r+" —— 读写(文件必须存在)
"w+" —— 读写(创建或清空)
"a+" —— 读+追加写
加 'b' 表示二进制模式,如 "rb"、"wb"
⚠️ 1. scanf 的变量必须加 &(取地址),否则会崩溃。
2. 正确:scanf("%d", &x); 错误:scanf("%d", x); 2. printf 的格式化符和参数类型必须匹配,否则结果未定义。
3. 比如用 %d 输出 double 会得到乱码。
4. 3. sprintf 不检查缓冲区大小,容易溢出,推荐用 snprintf。
5. 4. fopen 可能失败(文件不存在、权限不足),一定要检查返回值 是否为 NULL,不要直接使用。
6. 5. 打开的文件必须 fclose,否则资源泄漏。
7. 6. C++ 中 <stdio.h> 和 <iostream> 可以混用,但默认是同步的, 混合大量输出时可能变慢。
8. 可用 ios::sync_with_stdio(false) 取消同步(但之后不要混用)。
💡 💡 竞赛中很多人喜欢用 printf/scanf,因为比 cin/cout 快、格式化方便。
💡 两者各有场景, 了解 cstdio 能看懂大量 C 语言代码和老项目。