在C语言中,字符输入/输出功能允许程序与用户进行交互,读取用户的输入信息并展示输出结果。同时,验证输入的作用在于确保用户输入的数据符合预期,以提高程序的稳定性和可靠性,防止无效输入引发的错误或异常行为,从而提供更好的用户体验。
基础概念
-
输入(Input):指的是向程序填充数据的过程,通常来源于用户输入、文件读取或其他外部数据源。
-
输出(Output):指的是将数据显示在屏幕上、打印机上或写入文件的过程。
-
缓冲区:
- 输入/输出操作通常通过缓冲区进行,以提高效率。
- 用户输入的字符首先存储在输入缓冲区,直到程序准备好读取。
- 程序输出的字符首先写入输出缓冲区,然后在适当的时机(如缓冲区满或遇到换行符)刷新到输出设备。
-
输入验证:
- 输入验证是检查用户输入是否符合程序预期或特定格式的过程。
- 它是确保程序健壮性和安全性的重要步骤。
- 防止无效或恶意输入导致程序崩溃或产生不可预测的行为。
- 确保用户输入的数据符合程序内部逻辑的要求。
-
验证方法:
- 格式验证:检查输入是否符合预期的格式,如日期、电子邮件地址等。
- 范围验证:确保输入值在预期的范围内,如年龄、价格等。
- 类型验证:确认输入是预期的数据类型,如整数、浮点数等。
在C语言中还有EOF和 FILE两个重要概念,分别代表文件结束标记和文件类型:
-
EOF:
EOF(End Of File)是一个预定义的宏,通常在 <stdio.h>头文件中定义。它表示文件的结束标记,用于在读取文件时检测是否已经到达文件的末尾。在大多数系统中,EOF 的值通常是 -1,但这个值并不是由C标准规定的,而是依赖于具体的系统和编译器,当使用如 scanf(), fgetc(), fgets() 等函数读取文件时,如果到达文件末尾,这些函数通常会返回 EOF,从而允许程序知道已经没有更多的数据可以读取了。 -
FILE:
FILE是C标准库 <stdio.h>中定义的一个结构体类型,用于表示一个文件流。这个结构体包含了管理文件所需的所有信息,如文件描述符、缓冲区、位置指示器等,C标准库提供了一系列的函数来操作FILE
类型的对象,如 fopen(), fclose(), fread(), fwrite(), fseek(), ftell() 等。这些函数使得C语言程序能够以高级的方式处理文件,而无需关心底层操作系统的细节。 -
输入验证与缓冲区的关系:
在进行输入验证时,需要注意缓冲区中可能残留的数据。例如,如果用户输入了不符合要求的数据,这些数据可能会留在stdin缓冲区中。在下次输入时,如果不先清空缓冲区,这些残留数据可能会被误读为新的输入,导致程序出错。因此,在进行输入验证时,需要妥善处理缓冲区中的数据。
单字符标准输入
函数名 | 描述 |
---|---|
getchar | 从标准输入(stdin)读取一个字符 |
C语言中的单字符输入使用 getchar() 函数, getchar()函数可以读取用户在终端输入的一个字符。
// getchar.c
#include <stdio.h>
int main() {
printf("请输入一个字符:\n");
char ch = getchar(); // 在终端输入一个字符
printf("你输入的字符是:%c\n", ch); // 输出输入的字符
return 0;
}
单字符标准输出
函数名 | 描述 |
---|---|
putchar | 输出一个字符到标准输出(stdout) |
#include <stdio.h>
int main() {
char ch = 'a';
putchar(ch);
return 0;
}
标准输入
函数名 | 描述 |
---|---|
scanf | 从标准输入(stdin)读取格式化的数据 |
fgets | 从标准输入(stdin)读取一个字符串,直到遇到换行符或EOF(也可用于标准输入)(gets函数已被弃用) |
sacnf()函数:
在C语言中使用 scanf()函数 从标准输入读取数据,并根据指定的格式进行解析。虽然它不仅仅用于字符输入,但可以用来读取字符或字符串。
#include <stdio.h>
int main() {
char name[20];
int age;
float height;
printf("你好呀老铁,你叫什么名字?:\n");
scanf("%19s", name); // %19s 限制输入的最大字符数为19,防止溢出
printf("你今年几岁了?:\n");
scanf("%d", &age);
printf("你多高呀?:\n");
scanf("%f", &height);
printf("你好呀%s,你今年%d岁了,身高%.2f米。\n", name, age, height);
return 0;
}
fgets():
函数用于从指定的文件流中读取一行数据,直到达到指定的字符数,或者读到换行符或EOF为止。
stdin:
是C语言中的一个标准输入流,它是一个指向FILE的指针,一般情况下,stdin与程序的标准输入设备(比如键盘键盘)相关联,可以使用像fgets这样的函数从stdin中读取数据。
sscanf:
函数用于从一个字符串中读取与指定格式匹配的输入。
#include <stdio.h>
#include <string.h>
// 定义用户信息的结构体
typedef struct {
char name[20];
int age;
float height;
} UserInfo;
int main() {
UserInfo user;
char buffer[100];
printf("你好呀老铁,你叫什么名字?:\n");
fgets(buffer, sizeof(buffer), stdin);
buffer[strcspn(buffer, "\n")] = 0;
strncpy(user.name, buffer, sizeof(user.name) - 1);
printf("你今年几岁了?:\n");
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "%d", &user.age);
printf("你多高呀?:\n");
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "%f", &user.height);
printf("你好呀%s,你今年%d岁了,身高%.2f米。\n", user.name, user.age, user.height);
return 0;
}
标准输出
函数名 | 描述 |
---|---|
printf | 将格式化的数据输出到标准输出(stdout) |
puts | 输出一个字符串到标准输出(stdout),并在末尾添加换行符 |
#include <stdio.h>
int main() {
printf("Hello, World!\n");
printf("This is a number: %d\n", 123);
printf("This is a floating point number: %.2f\n", 3.14159);
printf("This is a character: %c\n", 'A');
printf("This is a string: %s\n", "Hello from a string");
puts("This is a line printed by puts function.");
return 0;
}
puts函数适用于简单的字符串输出需求,尤其是当需要在输出后自动换行的时候,printf函数则更加灵活和强大,适用于需要格式化输出或同时输出多种数据类型的情况。
输入输出流
函数名 | 描述 |
---|---|
fopen | 打开一个文件,并返回一个与之相关联的文件指针 |
fclose | 关闭一个打开的文件流 |
fprintf | 将格式化的数据写入文件 |
fscanf | 从文件中读取格式化的数据 |
fputc | 将一个字符写入到指定的文件流中 |
fgetc | 从指定的文件流中读取一个字符 |
fputs | 将一个字符串写入到指定的文件流中 |
fgets | 从指定的文件流中读取一个字符串,直到遇到换行符或EOF |
fwrite | 将一块数据写入到指定的文件流中 |
fread | 从指定的文件流中读取一块数据 |
fseek | 设置文件流的位置指示器 |
ftell | 返回当前文件流的位置指示器 |
fflush | 刷新一个输出或更新文件流 |
setvbuf | 设置文件流的缓冲模式 |
在运行以下代码前需要在c语言文件所在的文件夹里先新建一个 example.txt 文件,并在里面输入一些内容。
fopen:
打开一个文件,并返回一个与之相关联的文件指针
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w"); // 打开文件用于写入
if (file == NULL) {
perror("Error opening file");
return 1;
}
printf("File opened successfully.\n");
fclose(file); // 关闭文件
return 0;
}
fclose:
关闭一个打开的文件流
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
printf("File opened successfully.\n");
fclose(file);
printf("File closed successfully.\n");
} else {
perror("Error opening file");
}
return 0;
}
fprintf:
将格式化的数据写入文件
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
fprintf(file, "Hello GGBond\n"); // 写入格式化字符串
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fscanf:
从文件中读取格式化的数据
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file) {
char buffer[100];
if (fscanf(file, "%99s", buffer) == 1) { // 读取格式化字符串
printf("Read: %s\n", buffer);
}
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fputc:
将一个字符写入到指定的文件流中
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
fputc('A', file); // 在文件里写入字符A
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fgetc:
从指定的文件流中读取一个字符
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file) {
char ch = fgetc(file); // 读取一个字符
if (ch != EOF) {
printf("Read character: %c\n", ch);
}
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fputs:
将一个字符串写入到指定的文件流中
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
fputs("Hello, World!\n", file); // 写入一个字符串
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fgets:
从指定的文件流中读取一个字符串,直到遇到换行符或EOF
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file) {
char buffer[100];
if (fgets(buffer, sizeof(buffer), file)) { // 读取一个字符串
printf("Read string: %s", buffer);
}
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fwrite:
将一块数据写入到指定的文件流中
#include <stdio.h>
int main() {
FILE *file = fopen("example.bin", "wb");
if (file) {
int data[] = {1, 2, 3, 4, 5};
fwrite(data, sizeof(int), 5, file); // 写入一块数据
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fread:
从指定的文件流中读取一块数据
#include <stdio.h>
int main() {
FILE *file = fopen("example.bin", "rb");
if (file) {
int data[5];
fread(data, sizeof(int), 5, file); // 读取一块数据
for (int i = 0; i < 5; i++) {
printf("%d ", data[i]);
}
printf("\n");
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fseek 和 ftell:
设置文件流的位置指示器 和 返回当前文件流的位置指示器
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "r");
if (file) {
fseek(file, 0, SEEK_END); // 定位到文件末尾
long size = ftell(file); // 获取当前位置,即文件大小
printf("File size: %ld bytes\n", size);
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
fflush:
刷新一个输出或更新文件流
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
fprintf(file, "Hello, World!\n");
fflush(file); // 强制刷新缓冲区,确保数据写入文件
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
setvbuf:
设置文件流的缓冲模式
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
if (setvbuf(file, NULL, _IONBF, 0) != 0) { // 设置为不带缓冲
perror("Error setting buffer");
} else {
printf("Buffer set successfully.\n");
}
fclose(file);
} else {
perror("Error opening file");
}
return 0;
}
输入验证函数
函数名 | 描述 |
---|---|
feof | 检查文件流是否已到达文件末尾(EOF) |
ferror | 检查文件流是否有错误发生 |
clearerr | 清除文件流的错误标志和EOF标志 |
新建一个example.txt文件,在里面随意输入内容,随后新建C语言文件:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file;
char buffer[100];
file = fopen("example.txt", "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
// 尝试从文件中读取数据,直到遇到EOF或发生错误
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}
// 使用feof检查是否已到达文件末尾
if (feof(file)) {
printf("End of file reached.\n");
}
// 使用ferror检查文件流是否有错误发生
if (ferror(file)) {
printf("An error occurred during file operations.\n");
}
// 使用clearerr清除文件流的错误标志和EOF标志
clearerr(file);
// 再次检查以确认标志已被清除
if (!feof(file) && !ferror(file)) {
printf("EOF and error flags have been cleared.\n");
}
fclose(file);
return 0;
}
运行后在终端输出如下内容:
函数名称及用法表
单字符标准输入
函数名 | 描述 | 标准使用方法 |
---|---|---|
getchar | 从标准输入(stdin)读取一个字符 | int ch = getchar(); |
单字符标准输出
函数名 | 描述 | 标准使用方法 |
---|---|---|
putchar | 输出一个字符到标准输出(stdout) | putchar('A'); |
标准输入
函数名 | 描述 | 标准使用方法 |
---|---|---|
scanf | 从标准输入(stdin)读取格式化的数据 | int num; scanf("%d", &num); |
fgets | 从标准输入(stdin)读取一个字符串,直到遇到换行符或EOF | char buffer[100]; fgets(buffer, 100, stdin); |
标准输出
函数名 | 描述 | 标准使用方法 |
---|---|---|
printf | 将格式化的数据输出到标准输出(stdout) | printf("Hello, World!\n"); |
puts | 输出一个字符串到标准输出(stdout),并在末尾添加换行符 | puts("Hello, World!"); |
输入输出流
函数名 | 描述 | 标准使用方法 |
---|---|---|
fopen | 打开一个文件,并返回一个与之相关联的文件指针 | FILE *fp = fopen("file.txt", "r"); |
fclose | 关闭一个打开的文件流 | fclose(fp); |
fprintf | 将格式化的数据写入文件 | fprintf(fp, "Hello, File!\n"); |
fscanf | 从文件中读取格式化的数据 | int num; fscanf(fp, "%d", &num); |
fputc | 将一个字符写入到指定的文件流中 | fputc('A', fp); |
fgetc | 从指定的文件流中读取一个字符 | int ch = fgetc(fp); |
fputs | 将一个字符串写入到指定的文件流中 | fputs("Hello, File!\n", fp); |
fgets | 从指定的文件流中读取一个字符串,直到遇到换行符或EOF | char buffer[100]; fgets(buffer, 100, fp); |
fwrite | 将一块数据写入到指定的文件流中 | char data[5] = "data"; fwrite(data, sizeof(char), 4, fp); |
fread | 从指定的文件流中读取一块数据 | char buffer[4]; fread(buffer, sizeof(char), 4, fp); |
fseek | 设置文件流的位置指示器 | fseek(fp, 10, SEEK_SET); |
ftell | 返回当前文件流的位置指示器 | long pos = ftell(fp); |
fflush | 刷新一个输出或更新文件流 | fflush(fp); |
setvbuf | 设置文件流的缓冲模式 | setvbuf(fp, NULL, _IONBF, 0); |
输入验证函数
函数名 | 描述 | 标准使用方法 |
---|---|---|
feof | 检查文件流是否已到达文件末尾(EOF) | if (feof(fp)) { /* EOF reached */ } |
ferror | 检查文件流是否有错误发生 | if (ferror(fp)) { /* Error occurred */ } |
clearerr | 清除文件流的错误标志和EOF标志 | clearerr(fp); |