C字符输入/输出和输入验证

C字符输入/输出和输入验证

  1. 介绍输入、输出、缓冲输入、无缓冲输入区别
  2. 通过键盘模拟文件结尾条件
  3. 使用重定向把程序和文件相连接
  4. 创建更友好的用户界面

单字符I/O

  • getchar()
  • putchar()

shell当中的echo示例:

/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 10:48:15 AM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 10:48:15 AM
 * Description: echo函数的模拟,结束标志是#
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>

int main(void)
{
    char ch;

    while ((ch = getchar()) != '#') // #为结束条件,但是一般不好
        putchar(ch);
    
    return 0;
    
}

两个概念:

  1. 缓冲
  2. 标准输入文件

缓冲区

什么是无缓冲区?

  1. 回显用户输入的字符后立即重复打印该字符--->正在等待的程序可立即使用输入的字符

有缓冲区:

  1. 用户在按下Enter键之前不会重复打印刚输入的字符--->用户输入的字符被收集并存储到一个缓冲区(buffer)临时存储,按下Enter键以后程序才使用用户输入的字符

声明一块区域,临时存储输入的内容,而不是马上输入就使用

为什么需要缓冲区?

  • 方便用户修正
  • 把若干个字符作为一个块(block)进行传输比逐个传输要快

缓冲分类:

  • 完全缓冲I/o--->实现存在一个缓冲区大小,当缓冲区填满了以后才会刷新缓冲区(内容才会被发送到目标区域)
  • 行缓冲I/O--->出现换行符时刷新缓冲区

文件、流、键盘输入

  • 文件(file)

文件的定义:

存储器中存储信息的区域

特点:

文件都保存在某种永久存储器中

操作文件的流程:

  1. 打开文件
  2. 内容写入文件
  3. 读取文件内容
  4. 关闭文件

不同操作系统存储文件的差异:

  1. 有些操作系统会把文件的内容存储在一处,文件相关的信息存储在另一处
  2. 有些操作系统在文件中创建一份文件描述,使用单个换行符标记行末尾
  3. 有些操作系统以最小字节衡量文件大小,有些操作系统以字节块的大小来衡量
  • 流(stream)

C程序处理文件并不是直接处理文件,而是通过流来处理文件.

什么是流?

是一个实际输入货输出映射的理想化数据流.不同属性和不同种类的输入,由属性更同意的流来表示

  • 键盘输入

stdin流表示键盘输入

stdout流表示屏幕输出

getchar()等函数都是标准I/O包成员

文件结尾

C中,getchar()函数读取文件检测到文件结尾时将返回一个特殊的值,EOF(end of file),其值为-1,scanf()函数检测到文件结尾时也返回EOF,定义在stdio.h文件中

为什么是-1?

getchar()函数的返回值通常介于0~127,这些值对应标准字符集,加上拓展字符集(符号可以转为int类型输出)以后返回值介于0~255之间,所以-1不会出现,可用于文件结尾.

EOF文件末尾:

/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 11:28:24 AM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 11:28:24 AM
 * Description: 使用EOF定义文件末尾
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>

int main(void)
{
    int ch;

    while ((ch = getchar()) != EOF)
        putchar(ch);
    
    return 0;
}

重定向和文件

使用上述代码编译了以后,调用进行重定向输入到文件中

.\Echo_EOF.exe > .\test.txt
输入内容
ctrl+z退出

这样输入的内容就输出到了test.txt(也可以写绝对路径)当中

也可以在test.txt文件中输入内容,使用重定向运算符<将文件中的内容输入到程序中

.\Echo_EOF.exe < .\test.txt

<运算符使test.txt文件与stdin流相关联.程序本身不关心输入流来自键盘还是文件

组合重定向:

制作文件的副本,叫save.txt

.\Echo_EOF.exe < .\test.txt > .\save.txt

或者:

.\Echo_EOF.exe > .\save.txt < .\test.txt

UnixLinuxWindows/DOS当中使用两个重定向运算符需要遵循以下原则:

  • 重定向运算符连接一个可执行程序和一个数据文件.(不能用于连接一个数据文件和另一个数据文件,或者一个程序和另一个程序)
  • 使用重定向运算符不能读取多个文件的输入,不能把输出定向至多个文件
  • 文件名和运算符之间的空格不必要

还有一些定向运算符:

  1. >>把数据添加到现有内容的结尾
  2. |运算符把一个文件的输出连接到另一个文件的输入

示例代码:

/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 12:20:08 PM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 12:20:08 PM
 * Description: 打开一个文件,并显示该文件
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>
# include<stdlib.h> // 为了使用exit()

int main(void)
{
    int ch;
    FILE * fp; // iobuffer类型,定义在stdio.h宏文件中
    char fName[50]; // 存储文件名

    printf("输入文件名:");
    scanf("%s", fName);
    fp = fopen(fName, "r"); // 打开待读取文件
    if (fp == NULL)
    {
        printf("文件不存在!");
        exit(1);
    }

    while ((ch = getc(fp)) != EOF) // getc()方法必须要传一个iobuffer类型的参数 ---> getchar()无形参
        putchar(ch);
    fclose(fp); // 关闭文件
    
    return 0;
}

使用缓冲输入:

注意:

  1. 缓冲输入要求用户按下Enter键发送输入,这一动作替换了换行符
  2. 处理换行符

示例代码:

/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 12:35:52 PM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 12:35:52 PM
 * Description: 一个简单的递增猜数字程序,题目关键点在于练习字符io函数
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>

int main(void)
{
    int guess = 1;
    char response;

    printf("输入一个整数,在1到100之间.");
    printf("\n我猜他是: %d?", guess);
    while ((response = getchar()) != 'y')
    {
        if (response == 'n')
            printf("这个数是: %d?\n", ++guess);
        else
            printf("我只知道y或者n.\n");
        while (getchar() != '\n')
            continue; // 跳过剩余的输入行
    }
    
    return 0;
}

混合数值和字符输入:

需要注意:

  • getchar()函数会把字符、空格、制表符、换行符都读取
  • scanf()函数会跳过空格、制表符、换行符
/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 12:57:58 PM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 12:57:58 PM
 * Description: 使用scanf()函数处理换行符
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>
void display(char cr, int lines, int width);

int main(void)
{
    int ch; // 待打印字符
    int rows, cols; // 打印的行列数
    printf("输入两个整数:\n");
    while ((ch = getchar()) != '\n')
    {
        if (scanf("%d %d", &rows, &cols) != 2) // 上一个写法scanf()函数把换行符赋值给了ch,刚还是结束条件,所以没有输入就退出程序了
            break;
        display((char) ch, rows, cols);
        printf("输入另一个行和列:\n");
        printf("输入一个新行或者quit退出.\n");
    }

    getchar();

    printf("退出!");
    
    return 0;
}

void display(char cr, int lines, int width)
{
    int row, col;

    for (row = 1; row <= lines; row++) // 打印行
    {
        for (col = 1; col <= width; col++) // 打印列
            putchar(cr);
        putchar('\n'); // 结束一行开始零一行
    }
    
}

示例代码:

/**
 * @Author: Lucifer
 * @Date: 5/1/2023, 1:34:38 PM
 * @LastEditors: Lucifer
 * @LastEditTime: 5/1/2023, 1:34:38 PM
 * Description: 求两数平方和,用了结构化--->分了几个函数,核心函数:sum_squares()函数
 * Copyright: Copyright (©)}) 2023 Your Name. All rights reserved.
 */
# include<stdio.h>
# include<stdbool.h>
long get_long(void); // 验证输入是一个整数
bool bad_limits(long begin, long end, long low, long high); // 验证范围的上下限是否有效
double sum_squares(long a, long b); // 计算a ~ b的整数平方和

int main(void)
{
    const long MIN = -10000000L; // 范围下限
    const long MAX = +10000000L; // 范围上限
    long start;
    long stop;
    double answer;

    printf("这个项目是求和和计算平方的\n");
    start = get_long();
    printf("upper limit:");
    stop = get_long();
    while (start != 0 || stop != 0)
    {
        if (bad_limits(start, stop, MIN, MAX))
            printf("重试!\n");
        else
        {
            answer = sum_squares(start, stop);
            printf("整数平方和\n");
            printf("%ld 和 %ld 的平方和是 %g", start, stop, answer);
        }
        printf("Enter the limits (enter 0 for both): \n");
        printf("lower limit:");
        start = get_long();
        stop = get_long();
    }

    printf("结束!");

    return 0;
}

long get_long(void)
{
    long intput;
    char ch;

    while (scanf("%ld", &intput) != 1)
    {
        while ((ch = getchar()) != 'n') // 结束条件
            putchar(ch);
        printf("不是整数.\n请输入一个整数");
        printf("整数的值,例如:25 -178 3:");
    }

    return intput;
}

bool bad_limits(long begin, long end, long low, long high)
{
    bool not_good = false;

    if (begin > end)
    {
        printf("%ld不小于%ld", begin, end);
        not_good = true;
    }
    if (begin < low || end < low)
    {
        printf("值必须大于:%ld.\n", low);
        not_good = true;
    }
    if (begin > high || end > high)
    {
        printf("值必须小于:%ld.\n", high);
        not_good = true;
    }

    return not_good;    
}

double sum_squares(long a, long b)
{
    double total = 0;
    long i;

    for (i = a; i < b; i++)
        total += (double) i * (double) i;
    	
    return total;
}

注意:

如果输入是is 28 12.4

  • scanf()函数中使用%c转换--->读取s四个字符,存储在char类型变量中
  • 使用%s转换--->读取字符4和字符2,存储在字符数组中

总之,输入由字符组成,scanf()函数可以把输入转成整数值或者浮点值并存储到对应的变量中

posted @ 2023-05-04 16:28  俊king  阅读(87)  评论(0)    收藏  举报