目录
一.getchar()函数
getchar()
是C语言中的一个标准库函数,用于从标准输入(通常是键盘)读取一个字符。它是stdio.h
库的一部分,常用于简单的字符输入操作。
1.基本功能
getchar()
读取标准输入中的下一个字符,并将其作为一个int
类型的值返回。尽管返回值是int
类型,但它实际上是一个字符的ASCII值。
2.使用方法
int ch = getchar();
在这段代码中,
getchar()
从标准输入中读取一个字符,并将其返回的字符值存储在ch
变量中。
示例:
(1).读取单个字符
#include <stdio.h>
int main() {
int ch;
printf("请输入一个字符: ");
ch = getchar();
printf("你输入的字符是: %c\n", ch);
return 0;
}
解释:
- 程序等待用户输入一个字符。用户输入的字符被
getchar()
读取并存储在ch
中。 printf
函数随后输出用户输入的字符。
(2).读取多个字符(直到遇到换行符)
#include <stdio.h>
int main() {
int ch;
printf("请输入一行文字,按回车结束: ");
while ((ch = getchar()) != '\n' && ch != EOF) {
printf("读取字符: %c\n", ch);
}
printf("输入结束。\n");
return 0;
}
解释:
- 程序使用
while
循环来读取字符,直到遇到换行符('\n'
)或文件结束符(EOF
)。 - 每次读取的字符都会被输出。
(3).处理输入中的空白字符
#include <stdio.h>
int main() {
int ch;
printf("请输入字符,输入结束请按 Ctrl+D (Linux) 或 Ctrl+Z (Windows):\n");
while ((ch = getchar()) != EOF) {
if (ch == ' ' || ch == '\n' || ch == '\t') {
printf("[空白字符]\n");
} else {
printf("读取字符: %c\n", ch);
}
}
printf("输入结束。\n");
return 0;
}
解释:
- 这个程序读取用户输入的每个字符,并检查它是否是空白字符(空格、换行符、制表符)。
- 如果是空白字符,程序会输出
[空白字符]
,否则输出字符本身。 - 当用户按下
Ctrl+D
或Ctrl+Z
时,输入结束。
3.返回值
-
读取的字符: 如果读取成功,
getchar()
返回读取的字符的ASCII值。例如,如果用户输入字符'A'
,getchar()
将返回值65
(即'A'
的ASCII码)。 -
EOF (End of File): 如果在读取时遇到文件结束符(通常是在控制台输入时按下
Ctrl+D
或Ctrl+Z
),getchar()
将返回常量EOF
,其值通常为-1
。EOF
用于指示输入的结束或错误情况。
4.应用场景
简单字符输入:
getchar()
通常用于简单的字符输入操作,例如读取单个字符或控制台中的用户输入。处理空白字符: 当你需要明确处理空白字符(例如空格、制表符或换行符)时,
getchar()
特别有用。相比于scanf
,getchar()
不会跳过空白字符,因此你可以逐字符地处理输入。控制输入流:
getchar()
在处理输入流时非常灵活,可以用于跳过不需要的字符。例如,在多行输入或复杂输入格式的情况下,它可以帮助你控制和过滤输入内容。
5.注意事项
返回类型为
int
: 尽管getchar()
用于读取单个字符,但它的返回类型是int
而不是char
。这样设计是为了能够返回EOF
来表示文件结束或错误。为了避免潜在的错误,通常应该使用int
类型来存储getchar()
的返回值。缓冲区问题: 在控制台输入时,用户输入的内容通常会先进入缓冲区。当按下回车键时,缓冲区中的内容才会被
getchar()
逐个读取。因此,getchar()
不会在每个字符输入时立即返回,而是等待用户按下回车键。错误处理: 当使用
getchar()
时,程序应该考虑EOF
的可能性,尤其是在文件输入或批处理输入的情况下。忽略这一点可能会导致程序未正确处理输入结束的情况。
二.fgets()函数
fgets
是C语言中用于从文件流中读取一行字符串的标准库函数。它提供了一种安全、方便的方法来读取输入,避免了诸如缓冲区溢出等常见问题。fgets
通常用于读取用户输入、从文件中读取数据等场景。
1.函数原型
char *fgets(char *str, int n, FILE *stream);
str
: 指向字符数组的指针,fgets
会将读取到的字符串存储在该数组中。n
: 要读取的最大字符数,包括结尾的空字符\0
。也就是说,fgets
最多读取n-1
个字符。stream
: 输入流指针,指明从哪个流中读取数据。常见的流有标准输入流stdin
,文件流等。
返回值
- 成功: 返回指向读取字符串的指针,即参数
str
。 - 失败或到达文件末尾: 返回
NULL
。
2.工作原理
fgets
函数从指定的输入流stream
中读取字符,并将其存储到str
指向的字符数组中,直到发生以下任一情况:
- 读取了
(n - 1)
个字符: 为了保证字符串以\0
结尾,fgets
最多读取n - 1
个字符。- 遇到换行符
\n
:fgets
会读取换行符,并将其存储在str
中。- 到达文件末尾
EOF
: 如果在读取过程中遇到文件末尾,读取操作结束。读取完成后,
fgets
会在读取的字符串末尾自动添加一个空字符\0
,以表示字符串的结束。
3.使用示例
(1).从标准输入读取一行字符串
#include <stdio.h>
int main() {
char buffer[100];
printf("请输入一行文本:");
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
printf("您输入的是:%s", buffer);
} else {
printf("读取输入时发生错误。\n");
}
return 0;
}
解释:
fgets(buffer, sizeof(buffer), stdin)
从标准输入读取最多99
个字符(保留1个字符给\0
),并存储在buffer
中。- 如果读取成功,程序会输出用户输入的内容。
注意: 由于 fgets
会将换行符 \n
一并读取并存储,如果不想要这个换行符,需要手动去除。
(2).从文件中读取内容
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
perror("无法打开文件");
return 1;
}
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s", line);
}
fclose(fp);
return 0;
}
解释:
- 打开名为
example.txt
的文件,读取其中的内容并逐行打印到标准输出。 fgets
在每次循环中读取一行内容,直到文件结束。
4.处理换行符
正如前面提到的,fgets
会将输入中的换行符 \n
一并读取并存储在目标字符串中。如果在处理时不需要这个换行符,可以使用以下方法去除:
方法1:手动检查并替换
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
}
解释:
- 首先获取字符串的长度
len
。 - 如果最后一个字符是
\n
,将其替换为\0
。
方法2:使用 strcspn
函数
buffer[strcspn(buffer, "\n")] = '\0';
解释:
strcspn
函数返回buffer
中第一个匹配\n
的位置索引,然后将该位置的字符替换为\0
。
5.与其他输入函数的比较
(1). fgets
vs gets
-
gets
: 从标准输入读取一行,直到遇到换行符或文件结束符。不安全,因为无法指定读取的最大长度,容易导致缓冲区溢出。 -
fgets
: 可以指定最大读取长度,安全性更高。建议始终使用fgets
代替gets
。
(2). fgets
vs scanf
-
scanf
: 按照指定的格式从输入中读取数据,默认会忽略空白字符,读取字符串时会在遇到空白字符时停止。 -
fgets
: 读取整行输入,包括空白字符和换行符,更适合读取包含空格的字符串
示例:
char str1[100], str2[100];
// 使用 scanf
scanf("%s", str1);
// 输入:Hello World
// str1 的值为:"Hello"
// 使用 fgets
fgets(str2, sizeof(str2), stdin);
// 输入:Hello World
// str2 的值为:"Hello World\n"
(3). fgets
vs fgetc
-
fgetc
: 每次从指定流中读取一个字符,适合逐字符处理输入。 -
fgets
: 一次读取一行或指定长度的字符串,效率更高。
6、常见错误和注意事项
(1). 忘记检查返回值
在使用
fgets
时,应该始终检查其返回值,以确保读取成功。
错误示例:
fgets(buffer, sizeof(buffer), stdin);
// 未检查返回值,可能导致程序处理空指针
正确示例:
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
// 处理读取的数据
} else {
// 错误处理
}
(2). 未正确处理换行符
如前所述,
fgets
会保留输入中的换行符,如果不想要这个换行符,需要手动去除。
(3). 缓冲区大小不足
确保提供给
fgets
的缓冲区足够大,以容纳预期的输入数据和结尾的空字符。
错误示例:
char buffer[10];
fgets(buffer, 100, stdin); // 错误:缓冲区只有10个字节,却试图读取100个字符
正确示例:
char buffer[100];
fgets(buffer, sizeof(buffer), stdin); // 正确:缓冲区大小与读取长度匹配
(4). 多次读取时的缓冲区残留
在某些情况下,输入流中可能残留未读取的字符,需要在下一次读取前清空缓冲区。
char buffer1[50], buffer2[50];
printf("输入第一行:");
fgets(buffer1, sizeof(buffer1), stdin);
printf("输入第二行:");
fgets(buffer2, sizeof(buffer2), stdin);
如果在第一次输入时输入的字符超过了 buffer1
的大小,剩余的字符会留在输入缓冲区中,影响第二次读取。为避免这种情况,可以在每次读取后清空缓冲区。
清空缓冲区的方法:
int c;
while ((c = getchar()) != '\n' && c != EOF);
7.综合示例
示例:读取用户输入并处理
#include <stdio.h>
#include <string.h>
int main() {
char name[50];
int age;
char input[100];
// 读取姓名
printf("请输入您的姓名:");
if (fgets(name, sizeof(name), stdin) != NULL) {
// 去除换行符
name[strcspn(name, "\n")] = '\0';
} else {
printf("读取姓名失败。\n");
return 1;
}
// 读取年龄
printf("请输入您的年龄:");
if (fgets(input, sizeof(input), stdin) != NULL) {
// 将字符串转换为整数
age = atoi(input);
} else {
printf("读取年龄失败。\n");
return 1;
}
printf("姓名:%s,年龄:%d\n", name, age);
return 0;
}
解释:
- 首先使用
fgets
读取用户的姓名,并去除结尾的换行符。 - 然后再次使用
fgets
读取用户的年龄输入,并使用atoi
将其转换为整数。 - 最后输出用户输入的信息。
三.sscanf函数
sscanf
是C语言中用于从字符串中读取并解析数据的标准库函数。它的作用类似于scanf
,但sscanf
从字符串中读取数据,而scanf
是从标准输入中读取数据。sscanf
非常适合从已知格式的字符串中提取数值、字符等数据。
1.函数原型
int sscanf(const char *str, const char *format, ...);
str
: 要解析的源字符串。sscanf
会从这个字符串中读取数据。format
: 格式字符串,指定了要解析的数据格式。它的语法和scanf
的格式字符串相同,包括各种格式说明符(如%d
,%s
,%f
等)。...
: 可变参数列表,提供用于存储从字符串中读取的数据的指针。
返回值
- 成功: 返回成功读取并匹配的项数。
- 失败: 返回
EOF
,如果在解析过程中遇到错误或在尝试读取时到达字符串末尾
2.工作原理
sscanf
函数根据format
字符串中的格式说明符,从源字符串str
中逐一读取和解析数据。每个格式说明符都对应于一个传入的变量地址,sscanf
将解析后的数据存储在这些变量中。格式说明符示例
%d
: 读取一个整数。%f
: 读取一个浮点数。%s
: 读取一个字符串,遇到空白字符(如空格、换行)时停止。%c
: 读取单个字符。
示例:
(1).从字符串中解析数据
#include <stdio.h>
int main() {
const char *str = "100 3.14 hello";
int num;
float pi;
char word[20];
int count = sscanf(str, "%d %f %s", &num, &pi, word);
printf("读取到 %d 项数据:\n", count);
printf("整数: %d\n", num);
printf("浮点数: %.2f\n", pi);
printf("字符串: %s\n", word);
return 0;
}
输出:
读取到 3 项数据:
整数: 100
浮点数: 3.14
字符串: hello
解释:
sscanf
解析字符串"100 3.14 hello"
,并将数据分别存储在num
,pi
,word
中。- 返回值
count
表示成功读取了3项数据。
3.常见用法和注意事项
(1). 解析特定格式的字符串
sscanf
特别适用于解析具有固定格式的字符串,比如日期、时间、IP地址等。
示例:解析日期
#include <stdio.h>
int main() {
const char *date = "2024-08-17";
int year, month, day;
sscanf(date, "%d-%d-%d", &year, &month, &day);
printf("年: %d, 月: %d, 日: %d\n", year, month, day);
return 0;
}
输出:
年: 2024, 月: 8, 日: 17
解释:
- 解析字符串
"2024-08-17"
中的年份、月份和日期,并分别存储在year
,month
,day
中。
(2). 处理多余的输入
如果源字符串中的内容多于格式说明符指定的内容,
sscanf
只会处理指定的部分,忽略其余部分。
示例:部分解析字符串
#include <stdio.h>
int main() {
const char *str = "42 3.14 some extra text";
int num;
float pi;
int count = sscanf(str, "%d %f", &num, &pi);
printf("读取到 %d 项数据:\n", count);
printf("整数: %d\n", num);
printf("浮点数: %.2f\n", pi);
return 0;
}
输出:
读取到 2 项数据:
整数: 42
浮点数: 3.14
解释:
sscanf
只解析了前两个数据项(整数和浮点数),忽略了字符串末尾的额外内容。
(3). 不匹配的格式
如果字符串中的内容与格式说明符不匹配,
sscanf
会停止解析,并返回已成功读取的项数。
示例:格式不匹配
#include <stdio.h>
int main() {
const char *str = "hello 3.14";
int num;
float pi;
int count = sscanf(str, "%d %f", &num, &pi);
printf("读取到 %d 项数据:\n", count);
return 0;
}
输出:
读取到 0 项数据:
(4). 忽略特定数据
sscanf
还可以使用*
来忽略某些输入数据,不存储在任何变量中。
示例:忽略数据
#include <stdio.h>
int main() {
const char *str = "42 skip this 3.14";
int num;
float pi;
sscanf(str, "%d %*s %f", &num, &pi);
printf("整数: %d\n", num);
printf("浮点数: %.2f\n", pi);
return 0;
}
输出:
整数: 42
浮点数: 3.14
解释:
sscanf
使用%*s
忽略了"skip this"
字符串部分,只提取了整数和浮点数。
(5). 返回值处理
sscanf
的返回值用于检查是否成功解析了预期的项数。在实际编程中,应该根据返回值来验证解析操作的成功与否。
示例:检查返回值
#include <stdio.h>
int main() {
const char *str = "100 3.14";
int num;
float pi;
int result = sscanf(str, "%d %f", &num, &pi);
if (result == 2) {
printf("成功读取两个数值:%d 和 %.2f\n", num, pi);
} else {
printf("解析失败,已成功读取 %d 项数据。\n", result);
}
return 0;
}
输出:
成功读取两个数值:100 和 3.14
解释:
- 如果
sscanf
成功解析了两个值,程序输出成功消息。否则,输出失败消息。
4.常见错误和陷阱
(1). 未匹配到预期的数据
如果输入字符串的格式与格式说明符不匹配,
sscanf
会停止解析,返回已经成功解析的项数。确保格式字符串与输入字符串的格式一致非常重要。(2). 忘记检查返回值
忽略
sscanf
的返回值可能导致错误的程序行为。检查返回值是验证解析操作成功与否的关键步骤。(3). 缓冲区溢出
当读取字符串数据(如使用
%s
)时,确保目标缓冲区有足够的空间以避免溢出。使用长度限制格式符号(如%99s
)可以防止缓冲区溢出。(4). 处理多余输入
如果
sscanf
只读取了部分输入数据,而程序的逻辑依赖于完整的数据解析,可能会导致问题。合理设计格式说明符和字符串输入非常重要。
5.sscanf
与其他输入函数的比较
(1). sscanf
vs scanf
-
scanf
: 从标准输入中读取数据,适用于直接的用户输入操作。 -
sscanf
: 从字符串中读取数据,适用于解析已经存在的字符串内容。
(2). sscanf
vs fscanf
-
fscanf
: 从文件流中读取数据,适用于从文件中解析数据。 -
sscanf
: 从字符串中读取数据,适用于解析内存中的字符串。
(3). sscanf
vs strtok
-
strtok
: 用于分割字符串,可以按指定的分隔符逐一提取子字符串。 -
sscanf
: 直接解析字符串中的数据,并将其转换为相应的数据类型。
6.综合示例
示例:解析复杂字符串
#include <stdio.h>
int main() {
const char *str = "Name: John Doe, Age: 30, Score: 85.5";
char name[50];
int age;
float score;
int count = sscanf(str, "Name: %[^,], Age: %d, Score: %f", name, &age, &score);
if (count == 3) {
printf("姓名: %s\n", name);
printf("年龄: %d\n", age);
printf("分数: %.1f\n", score);
} else {
printf("解析字符串失败。\n");
}
return 0;
}
输出:
姓名: John Doe
年龄: 30
分数: 85.5
解释:
- 使用
sscanf
从格式化字符串中提取姓名、年龄和分数。%[^,]
格式说明符用于读取直到遇到逗号,
的所有字符,这样可以处理包含空格的姓名。
四.fscanf()函数
fscanf
是C语言中用于从文件中读取并解析数据的标准库函数。它的作用类似于scanf
,但fscanf
从文件流中读取数据,而scanf
是从标准输入中读取数据。fscanf
适合从文件中逐行或逐项读取并解析数据。
1.函数原型
int fscanf(FILE *stream, const char *format, ...);
参数说明
stream
: 文件指针,指向要读取的文件流(通常是通过fopen
打开的文件)。format
: 格式字符串,指定了要解析的数据格式。它的语法和scanf
的格式字符串相同,包括各种格式说明符(如%d
,%s
,%f
等)。...
: 可变参数列表,提供用于存储从文件中读取的数据的指针。
返回值
- 成功: 返回成功读取并匹配的项数。
- 失败: 如果遇到文件结束符
EOF
,则返回EOF
。如果遇到错误,返回负数。
2.工作原理
fscanf
函数根据 format
字符串中的格式说明符,从文件流 stream
中逐一读取和解析数据。每个格式说明符都对应于一个传入的变量地址,fscanf
将解析后的数据存储在这些变量中。
格式说明符示例
%d
: 读取一个整数。%f
: 读取一个浮点数。%s
: 读取一个字符串,遇到空白字符(如空格、换行)时停止。%c
: 读取单个字符。
示例:从文件中解析数据
假设有一个文本文件 data.txt
,内容如下:
42 3.14 hello
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r"); // 打开文件进行读取
if (file == NULL) {
perror("无法打开文件");
return 1;
}
int num;
float pi;
char word[20];
int count = fscanf(file, "%d %f %s", &num, &pi, word);
printf("读取到 %d 项数据:\n", count);
printf("整数: %d\n", num);
printf("浮点数: %.2f\n", pi);
printf("字符串: %s\n", word);
fclose(file); // 关闭文件
return 0;
}
输出:
读取到 3 项数据:
整数: 42
浮点数: 3.14
字符串: hello
解释:
fscanf
从文件data.txt
中解析数据,并将数据分别存储在num
,pi
,word
中。- 返回值
count
表示成功读取了3项数据。
3.常用用法和注意事项
(1). 读取一行数据
fscanf
通常按格式说明符读取数据,直到匹配结束,或者遇到文件结束符EOF
。它不会自动处理行结束符,因此如果要按行读取数据,可以结合fgets
和sscanf
使用。
示例:逐行读取数据
假设文件 data.txt
内容如下:
42 3.14 hello
43 2.71 world
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("无法打开文件");
return 1;
}
int num;
float pi;
char word[20];
while (fscanf(file, "%d %f %s", &num, &pi, word) != EOF) {
printf("整数: %d, 浮点数: %.2f, 字符串: %s\n", num, pi, word);
}
fclose(file);
return 0;
}
输出:
整数: 42, 浮点数: 3.14, 字符串: hello
整数: 43, 浮点数: 2.71, 字符串: world
(2). 文件指针位置
fscanf
读取数据后,文件指针会移动到读取结束的位置。下一次调用fscanf
会从当前文件指针位置继续读取。
(3). 遇到EOF
当
fscanf
遇到文件结束符EOF
时,它会返回EOF
,通常是-1
。这可以用来判断是否已经读取到文件末尾。
(4). 忽略特定数据
类似于
sscanf
,fscanf
也可以使用*
来忽略某些输入数据,而不存储在任何变量中。
示例:忽略数据
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("无法打开文件");
return 1;
}
int num;
float pi;
while (fscanf(file, "%d %*s %f", &num, &pi) != EOF) {
printf("整数: %d, 浮点数: %.2f\n", num, pi);
}
fclose(file);
return 0;
}
解释:
fscanf
使用%*s
忽略了字符串部分,只提取了整数和浮点数。
(5). 返回值处理
与
sscanf
类似,fscanf
的返回值表示成功读取并解析的数据项数。在实际编程中,应该根据返回值来验证解析操作的成功与否。
示例:检查返回值
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("无法打开文件");
return 1;
}
int num;
float pi;
while (fscanf(file, "%d %f", &num, &pi) == 2) { // 期望成功读取2项数据
printf("整数: %d, 浮点数: %.2f\n", num, pi);
}
fclose(file);
return 0;
}
解释:
- 只有在成功解析了两个值时才输出结果。如果
fscanf
未能成功读取两个值,将停止读取。
(6). 处理多余输入
如果文件中的内容多于格式说明符指定的内容,
fscanf
只会处理指定的部分,忽略其余部分。
4.常见错误和陷阱
(1). 格式不匹配
如果文件中的内容与格式说明符不匹配,
fscanf
会停止解析,并返回已成功读取的项数。确保格式字符串与文件内容格式一致非常重要。
(2). 忘记检查返回值
忽略
fscanf
的返回值可能导致错误的程序行为。检查返回值是验证解析操作成功与否的关键步骤。
(3). 文件结束符
fscanf
在读取到文件结束符EOF
时会返回EOF
,这与常规的返回值检查不同,处理文件结束符时需要特别注意。
5.fscanf
与其他输入函数的比较
(1). fscanf
vs scanf
-
scanf
: 从标准输入中读取数据,适用于直接的用户输入操作。 -
fscanf
: 从文件流中读取数据,适用于从文件中解析数据。
(2). fscanf
vs sscanf
-
sscanf
: 从字符串中读取数据,适用于解析内存中的字符串。 -
fscanf
: 从文件流中读取数据,适用于从文件中解析数据。
(3). fscanf
vs fgets
-
fgets
: 从文件中读取一整行字符串,适用于逐行读取文件内容,通常结合sscanf
使用以进一步解析数据。 -
fscanf
: 按照格式说明符从文件中读取数据,适用于逐项解析数据。
6.综合示例
示例:从文件中读取并解析数据
假设有一个文本文件 students.txt
,内容如下:
John 20 85.5
Alice 22 90.0
Bob 21 78.5
#include <stdio.h>
int main() {
FILE *file = fopen("students.txt", "r");
if (file == NULL) {
perror("无法打开文件");
return 1;
}
char name[50];
int age;
float score;
while (fscanf(file, "%s %d %f", name, &age, &score) == 3) {
printf("姓名: %s, 年龄: %d, 分数: %.1f\n", name, age, score);
}
fclose(file);
return 0;
}
输出:
姓名: John, 年龄: 20, 分数: 85.5
姓名: Alice, 年龄: 22, 分数: 90.0
姓名: Bob, 年龄: 21, 分数: 78.5
解释:
fscanf
从文件students.txt
中解析每一行数据,并输出到屏幕上。它通过格式说明符%s %d %f
解析每行中的姓名、年龄和分数。
完!
一键三连支持一下吧,非常感谢!