C语言输入输出函数详解---标准输入输出,文件流以及错误处理函数

一、标准输入输出函数(stdio.h)

1. 字符输入输出函数

(1) getchar()
int getchar(void);
  • 功能:从标准输入(stdin)读取一个字符

  • 返回值:成功返回读取的字符(转换为unsigned char后提升为int),失败或到达文件末尾返回EOF(-1)

  • 特点:

    • 无参数

    • 通常用于从键盘获取单个字符

    • 会缓冲输入,直到用户按下回车

  • 示例:

    int ch;
    while ((ch = getchar()) != EOF) {
        putchar(ch);
    }
    (2) putchar()
    int putchar(int c);
  • 功能:向标准输出(stdout)写入一个字符

  • 参数:c是要输出的字符(转换为unsigned char)

  • 返回值:成功返回写入的字符,失败返回EOF

  • 特点:

    • 比printf效率高

    • 只能输出单个字符

  • 示例:

    putchar('A');  // 输出字符A
    putchar(65);   // 同样输出字符A(ASCII码65)

2. 格式化输入输出函数

(1) printf()
int printf(const char *format, ...);
  • 功能:格式化输出到标准输出

  • 格式说明符:

    • %d/%i:有符号十进制整数

    • %u:无符号十进制整数

    • %o:无符号八进制

    • %x/%X:无符号十六进制

    • %f/%F:浮点数

    • %e/%E:科学计数法

    • %g/%G:自动选择%f或%e

    • %c:字符

    • %s:字符串

    • %p:指针地址

    • %%:百分号本身

  • 修饰符:

    • 宽度:%10d(最小宽度10)

    • 精度:%.2f(小数点后2位)

    • 左对齐:%-10d

    • 填充:%010d(用0填充)

  • 返回值:成功返回输出的字符数,失败返回负值

  • 示例:

    printf("Integer: %5d\nFloat: %.2f\nString: %s\n", 123, 3.14159, "hello");
    (2) scanf()
    int scanf(const char *format, ...);
  • 功能:从标准输入读取格式化输入

  • 格式说明符:

    • %d:读取整数

    • %f:读取浮点数

    • %c:读取字符

    • %s:读取字符串(遇到空白字符停止)

    • %[]:扫描字符集合

    • %%:匹配百分号

  • 修饰符:

    • *:抑制赋值(跳过该输入)

    • 宽度:%5s(最多读取5个字符)

  • 返回值:成功匹配并赋值的输入项数

  • 注意事项:

    • 必须传递变量地址(&)

    • 对%s存在缓冲区溢出风险

    • 空白字符(空格、制表符、换行符)会被跳过

  • 示例:

    int age;
    float height;
    char name[50];
    scanf("%d %f %49s", &age, &height, name);

    3. 行输入输出函数

    (1) gets() (已废弃)
    char *gets(char *s);
  • 问题:无法限制输入长度,极易导致缓冲区溢出

  • 替代方案:使用fgets()

(2) fgets()
char *fgets(char *s, int size, FILE *stream);

  • 功能:从指定流读取一行

  • 参数:

    • s:存储读取数据的缓冲区

    • size:最大读取字符数(包括空字符)

    • stream:文件流(stdin表示标准输入)

  • 特点:

    • 读取直到遇到换行符或EOF

    • 保留换行符(如果有)

    • 总是添加空字符('\0')

    • 比gets()安全

  • 返回值:成功返回s,失败或到达文件末尾返回NULL

  • 示例:

    char line[100];
    if (fgets(line, sizeof(line), stdin) != NULL) {
        // 处理读取的行
    }
    (3) puts()
    int puts(const char *s);
  • 功能:向标准输出写入字符串并自动添加换行符

  • 参数:s是要输出的字符串(必须以空字符结尾)

  • 返回值:成功返回非负值,失败返回EOF

  • 特点:

    • 比printf简单高效

    • 自动添加换行符

  • 示例:

    puts("Hello World");  // 输出"Hello World\n"

    二、文件输入输出函数

    1. 文件打开关闭

    (1) fopen()
    FILE *fopen(const char *filename, const char *mode);
  • 功能:打开文件

  • 模式:

    • "r":只读(文件必须存在)

    • "w":只写(存在则清空,不存在则创建)

    • "a":追加(存在则追加,不存在则创建)

    • "r+":读写(文件必须存在)

    • "w+":读写(存在则清空,不存在则创建)

    • "a+":读写(存在则追加,不存在则创建)

    • 添加"b"表示二进制模式(如"rb")

  • 返回值:成功返回文件指针,失败返回NULL

  • 示例

    FILE *fp = fopen("data.txt", "r");
    if (fp == NULL) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }
    (2) fclose()
  • 功能:关闭文件

  • 返回值:成功返回0,失败返回EOF

  • 注意事项:

    • 必须关闭所有打开的文件

    • 程序结束时未关闭的文件可能丢失数据

  • 示例:

    if (fclose(fp) == EOF) {
        perror("Error closing file");
    }

    2. 文件读写函数

    (1) fprintf()
    int fprintf(FILE *stream, const char *format, ...);
  • 功能:格式化写入文件

  • 与printf类似,但指定了输出流

  • 示例:

    fprintf(fp, "Name: %s, Age: %d\n", name, age);
    (2) fscanf()
    int fscanf(FILE *stream, const char *format, ...);
  • 功能:从文件格式化读取

  • 与scanf类似,但指定了输入流

  • 示例:

    fscanf(fp, "%s %d", name, &age);
    (3) fgetc()
    int fgetc(FILE *stream);
  • 功能:从文件读取一个字符

  • 返回值:成功返回读取的字符(转换为unsigned char后提升为int),失败或EOF返回EOF

  • 示例:

    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    (4) fputc()
    int fputc(int c, FILE *stream);
  • 功能:向文件写入一个字符

  • 参数:c是要写入的字符(转换为unsigned char)

  • 返回值:成功返回写入的字符,失败返回EOF

  • 示例:

    fputc('A', fp);
    (5) fgets() (文件版本)
  • 与标准输入版本相同,但可以指定文件流

  • 示例:

    char line[256];
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("%s", line);
    }
    (6) fputs()
    int fputs(const char *s, FILE *stream);
  • 功能:向文件写入字符串(不自动添加换行符)

  • 参数:s是要写入的字符串(必须以空字符结尾)

  • 返回值:成功返回非负值,失败返回EOF

  • 示例:

    fputs("Hello File", fp);

    3. 二进制文件读写

    (1) fread()
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
  • 功能:从文件读取二进制数据

  • 参数:

    • ptr:存储读取数据的内存指针

    • size:每个数据项的字节大小

    • nmemb:要读取的数据项数量

    • stream:文件流

  • 返回值:成功读取的数据项数量(可能小于nmemb)

  • 示例:

    struct Student {
        char name[50];
        int age;
    } s;
    
    size_t n = fread(&s, sizeof(struct Student), 1, fp);
    if (n != 1) {
        // 处理错误
    }
    (2) fwrite()
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

  • 功能:向文件写入二进制数据

  • 参数:与fread相同

  • 返回值:成功写入的数据项数量

  • 示例:

    struct Student s = {"Alice", 20};
    fwrite(&s, sizeof(struct Student), 1, fp);

    4. 文件定位函数

    (1) fseek()
    int fseek(FILE *stream, long offset, int whence);
  • 功能:设置文件位置指示器

  • 参数:

    • offset:偏移量

    • whence:

      • SEEK_SET:文件开头

      • SEEK_CUR:当前位置

      • SEEK_END:文件末尾

  • 返回值:成功返回0,失败返回非0

  • 示例:

    fseek(fp, 0, SEEK_SET);  // 定位到文件开头
    fseek(fp, -10, SEEK_END); // 定位到文件末尾前10字节
    (2) ftell()
    long ftell(FILE *stream);
  • 功能:获取当前文件位置

  • 返回值:当前位置(距文件开头的字节数),失败返回-1L

  • 示例:

    long pos = ftell(fp);
    (3) rewind()
    void rewind(FILE *stream);
  • 功能:将文件位置重置到开头

  • 相当于fseek(fp, 0, SEEK_SET)

  • 示例:

    rewind(fp);

    三、错误处理函数

    1. perror()

    void perror(const char *s);

  • 功能:打印最近一次系统错误的描述

  • 参数:s是自定义的前缀信息

  • 示例:

    FILE *fp = fopen("nonexist.txt", "r");
    if (fp == NULL) {
        perror("Error opening file");
        // 输出: Error opening file: No such file or directory
    }

   2. feof()

int feof(FILE *stream);
  • 功能:检测文件结束标志

  • 返回值:如果设置了文件结束标志返回非0,否则返回0

  • 注意事项:

    • 应该在读取操作失败后检查

    • 不能单独用于控制循环

  • 示例:

    while (1) {
        int ch = fgetc(fp);
        if (feof(fp)) break;
        // 处理字符
    }

    3. ferror()

    int ferror(FILE *stream);
  • 功能:检测文件错误标志

  • 返回值:如果设置了错误标志返回非0,否则返回0

  • 示例:

    if (ferror(fp)) {
        perror("File error occurred");
    }

    四、缓冲区控制函数

    1. fflush()

    int fflush(FILE *stream);

  • 功能:刷新输出缓冲区

  • 参数:

    • 输出流:强制写入缓冲数据

    • 输入流:行为由实现定义

    • NULL:刷新所有输出流

  • 返回值:成功返回0,失败返回EOF

  • 示例:

    printf("Please wait...");
    fflush(stdout);  // 立即显示,不等换行符

    2. setbuf()/setvbuf()

    void setbuf(FILE *stream, char *buf);
    int setvbuf(FILE *stream, char *buf, int mode, size_t size);
  • 功能:控制文件缓冲

  • 模式:

    • _IOFBF:全缓冲

    • _IOLBF:行缓冲

    • _IONBF:无缓冲

  • 示例:

    char buf[BUFSIZ];
    setvbuf(fp, buf, _IOFBF, BUFSIZ);

    五、其他实用函数

    1. sscanf()/sprintf()

    int sscanf(const char *str, const char *format, ...);
    int sprintf(char *str, const char *format, ...);
  • 功能:从字符串格式化输入/输出

  • 注意事项:

    • sprintf()存在缓冲区溢出风险,建议使用snprintf()

  • 示例:

    char str[100];
    int n = sprintf(str, "Value: %d", 42);  // str = "Value: 42"
    
    int val;
    sscanf("123 456", "%d", &val);  // val = 123

    2. snprintf()

    int snprintf(char *str, size_t size, const char *format, ...);
  • 功能:安全版本的sprintf()

  • 参数:size指定缓冲区大小

  • 返回值:如果缓冲区足够大,返回将要写入的字符数(不包括空字符)

  • 示例:

    char buf[20];
    int n = snprintf(buf, sizeof(buf), "Number: %d", 12345);
    // n = 12(实际需要13字节,包括空字符)
    // buf = "Number: 12345"(截断到19字符+空字符)

    六、最佳实践

  • 输入安全

    • 避免使用gets(),总是使用fgets()

    • 使用fgets()+sscanf()代替scanf()

    • 检查所有输入函数的返回值

  • 输出安全

    • 使用snprintf()代替sprintf()

    • 检查输出是否被截断

  • 文件操作

    • 总是检查fopen()返回值

    • 确保所有打开的文件都被关闭

    • 使用二进制模式处理非文本数据

  • 错误处理

    • 检查所有I/O操作的返回值

    • 使用perror()或strerror()报告错误

    • 适当处理EOF和错误条件

  • 性能考虑

    • 减少小规模I/O操作

    • 考虑使用缓冲

    • 批量读写数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值