C-study(八)

输入输出

I/O函数负责把信息传送给程序

通用标准I/O函数,可移植

部分非标准 I/O函数需要特殊操作系统支持,便于使用特定计算机编写程序

字符函数 getchar() putchar()
每次只处理一个字符

//echo.c 重复输入直到#
#include<stdio.h>//包含getchar和putchar的宏
    int ch;
    while ((ch = getchar()) != '#') // 读一个字符,赋值,判断#停止输入
        putchar(ch);  // 输出一个字符

缓冲

ANSI和后续的C 都规定输入是缓冲的;

无缓冲输入:

echo.c中显示输入的字符后立刻重复打印该字符
正在等待的程序可立即使用输入的字符
字符逐个发送
游戏中按下立刻执行

缓冲输入:

按下enter之前输入的字符被收集并存储在临时存储区(缓冲区);
按下enter之后才可使用输入的字符
若干字符作为一个块传输、节约时间
打错字符可以通过键盘修正错误、只要最后按下enter之前是正确的输入

完全缓冲IO:

当缓冲区被填满时才刷新缓冲区,通常出现在文件输入中;
缓冲区大小取决于系统,常见512字节和4096字节

行缓冲IO:

出现换行符时刷新缓冲区,
键盘输入,按下enter之后刷新缓冲区

如果计算机允许无缓存输入,编译器也可能允许无缓存输入;
eg:IBM PC的编译器都为支持无缓冲输入提供特殊函数,在conio.h;
UNIX 系统中使用ioctl()指定待输入类型 ;
ANSI C中setbuf() setvbuf() 控制缓冲,没有调用无缓冲输入的标准方式;

在这里插入图片描述

文件、流、键盘输入

文件:存储器中储存信息的区域
通常保存在永久存储器中(硬盘、U盘、DVD)
1、程序需要访问指定的文件
eg : 当编译存储在名为echo.h文件中的程序,编译器打开并读取其中的内容,处理完之后关闭该文件
2、程序要打开,读取,写入数据到文件,关闭文件
eg : 文字处理器

底层IO:使用主机操作系统的基本文件工具直接处理文件
标准IO:用于处理文件的标准模型和一套标准IO函数
具体的C实现负责处理不同系统的差异,以便用户使用统一的界面
不同系统存储文件方式不同,处理文件方式不同
使用标准IO不需要考虑系统差异

:实际输入输出映射的理想化数据流
不同属性和不同种类的输入有属性更统一的流表示
打开文件就是把流和文件关联,读写都通过流来完成

stdin流表示键盘输入 stdout流表示屏幕输出
getchar() putchar() printf() scanf() 处理上面两个流
输入函数内置文件结尾检测器,使用文件结尾检测器结束键盘输入

文件结尾

1、在文件末尾放一个特殊字符标记文件结尾(内嵌的ctrl+Z,操作系统设定)
2、储存文件大小的信息
getchar()读取文件检测到文件结尾时返回EOF
scanf()检测到文件结尾也返回EOF

想要输入EOF时,不可以输入字符EOF和-1,要按照当前系统的结尾要求,eg:ctrl+D

输入从一个文件定向到.c,把输出发送到另一个文件,便是查看文件,创建新文件,拷贝文件

//echo_eof.c
#include<stdio.h>
/*在stdio.h文件中: #define EOF -1 
引用头文件之后不需要定义EOF,不需要担心EOF的实际值
EOF 是一个值,标志着检测到文件结尾
*/
    int ch;
    while ((ch = getchar()) != EOF) // getchar返回int,赋值给char类型时可能会报丢失数据警告
        putchar(ch);                // putchar传参整数会打印等价字符

重定向

输入输出涉及函数,数据和设备

echo_eof.c中
输入函数:getchar
输出设备:屏幕
数据流:字符

默认使用标准IO查找标准输入作为输入源,stdin流,stdout流

使用文件的方式
1、显式使用特定的函数打开,关闭,读取,写入文件
2、设计能和键盘屏幕互动的程序,通过不同的渠道重定向输入至文件和从文件输出,eg:stdin流赋給文件,使用getchar从输入流获取数据

重定向和操作系统有关,
大多数C系统可以通过操作系统重定向所有程序,
缺乏重定向的系统 可以用C模拟

UNIX、Linux 和DOS重定向

命令行模式重定向

重定向输入

让程序使用文件而不是键盘

编译echo_eof.c 到echo_eof
正常调用 echo_eof

重定向调用 echo_eof < words 重定向输入words文件

< 是UNIX 和 DOS/windows的重定向运算符,把words文件和stdin流关联,把文件内容导入程序

重定向输出

让程序输出至文件而不是屏幕

重定向调用 echo_eof > words 重定向输出到 words文件

> 是UNIX 和 DOS/windows的重定向运算符,创建新文件,把输出重定向至该文件中,把stdout流赋值给文件,如果是已有文件,会擦除重写

组合重定向

制作一份mywords文件的副本,命名为savewords
echo_eof < mywords > savewords
echo_eof > savewords < mywords
命令和重定向运算符的顺序无关
输入输出文件名不能相同
连接一个可执行程序(包括标准操作系统命令)和一个数据文件,不可链接两个程序或两个文件
不可有多个输入或多个输出
空格可有可无,看系统要求

>>可把数据添加到现有文件末尾
| 把文件的输出连接到另一个文件的输入

其他

命令行输入特殊符号发出重定向指令
集成开发环境提供菜单选项,让用户指定重定向
用程序直接打开文件,待读取的文件和可执行文件放在同目录

//file_eof.c --打开一个文件并显示该文件
#include <errno.h>  //errno 指示在程序运行过程中发生的错误代码
#include <string.h> //char *strerror(int errnum) 从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针
	int ch;
    FILE *fp;
    char fname[50]; // 储存文件名
    printf("Enter the name of the file: ");
    scanf("%s", fname);
    int errNum = 0;
    fp = fopen(fname, "r"); // 打开待读取文件,文件要有权限
    if (fp == NULL)             // 如果失败
    {
        errNum = errno;
        printf("open fail errno = %d reason = %s\n", errNum, strerror(errNum)); 
        printf("Failed to open file. Bye\n");
        exit(1); // 退出程序
    }
    // getc(fp)从打开的文件中获取一个字符
    while ((ch = getc(fp)) != EOF)
        putchar(ch);
    fclose(fp); // 关闭文件

用户输入

缓冲输入

在输入发送给程序之前,用户可以编辑输入
换行符需要处理
事先预料用户可能的输入错误,然后设计程序处理错误输入

 // 猜数字,用户输入y时猜对
 int guess = 1;
 printf("I will guess the num 1,tell me y(right) or n(wrong) \n");

 // while (getchar() != 'y') // getchar会包括换行符,当输入一个n再换行时,会进入两次打印
 //     printf("well,then,it is %d?\n", ++guess);

 char response;
 while ((response = getchar()) != 'y') // response获取当前字符
 {
     if (response == 'n') // 只取y/n
         printf("well,then,it is %d?\n", ++guess);
     else//处理可能出现的其他字符
         printf("sorry,i understand only y or n.\n");
     while (getchar() != '\n')
         continue; // 只取每一行的第一个字符
 }

混合数值和字符输入

getchar读取每个字符,包括空白
scanf读取数字时跳过空白、%c包括空白、%s到空白结束

输入流由字符组成,
scanf可以把输入转换成整数或者浮点数,使用转换说明(%d %f)限制可接受输入的字符类型
getchar和使用%c的scanf接受所有字符

void display(char cr, int lines, int width);
    int ch;         /*待打印字符*/
    int rows, cols; /*行数和列数*/
    printf("Enter a character and two integers : \n");

    // while ( (ch = getchar ()) != '\n')//int
    // {//getchar会读换行符,空格,制表符,会导致输入后的换行使程序退出
    // 	scanf("%d %d",&rows,&cols) ;
    // 	display(ch,rows,cols) ;//int 传参给char 可能会报警告,可以强制类型转换(char)ch
    // 	printf ("Enter another character and two integers; \n" );
    // 	printf ( "Enter a newline to quit. \n" ) ;
    // }

    while ( (ch = getchar()) != '\n' )
	{
        if (scanf("%d %d", &rows, &cols) != 2) // 读入数量正确时继续,否则退出
            break;
        display(ch, rows, cols);
        while (getchar() != '\n') // 避免读入换行符退出程序,本行内正确输入后的所有字符都丢掉
            continue;
        printf("Enter another character and two integers; \n");
        printf("Enter a newline to quit. \n");
	}
    printf("Bye . \n");
    
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'); /*结束一行并开始新的一行*/
    }
}	

输入验证

事先预料可能的输入错误并对其进行检查

不在程序处理范围内的值
错误类型
可以检查输入值是否有效,是否在允许的范围内

// scanf("%ld",&n);//需要非负整数时
// while(n>=0)输入之后检测范围

// while(scanf("%ld",&n)==1 && n>=0)//scanf返回读取成功项的个数,返回值为1可以保证用户输入一个整数,可以在输入错误时提醒用户重新输入
#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);

/*main管理程序流,为其他函数委派任务
使用get_long获取值,while循环处理值、badlimits检查值是否有效,sum_squres处理实际计算*/
    const long MIN = -10000000L; // 范围的下限
    const long MAX = +10000000L; // 范围的上限

    long start; // 用户指定的范围最小值
    long stop;  // 用户指定的范围最大值
    double answer;
    printf("This program computes the sum of the squares of "
           "integers in a range.\nThe lower bound should not "
           "be less than -10000000 and\nthe upper bound "
           "should not be more than +10000000.\nEnter the "
           "limits(enter 0 for both limits to quit):\n"
           "lower limit:");
    start = get_long();
    printf("upper limit:");
    stop = get_long();
    while (start != 0 || stop != 0)
    {
        if (bad_limits(start, stop, MIN, MAX))
            printf("Please try again.\n");
        else
        {
            answer = sum_squares(start, stop);
            printf("The sum of the squares of the integers ");
            printf("from %ld to %ld is %g \n", start, stop, answer);
        }
        printf("Enter the limits(enter 0 for both "
               "limits to quit):\n");
        printf("lower limit:");
        start = get_long();
        printf("upper limit:");
        stop = get_long();
    }
    printf("Done\n");

long get_long()
{ // 获取正确类型值
    long input;
    char ch;
    while (scanf("%ld", &input) != 1) // 获取int类型值,获取成功直接返回,获取失败进循环提示重新输入
    {
        while ((ch = getchar()) != '\n') // 输出提示,并丢该行剩余的其他内容(避免scanf取到)
            putchar(ch);
        printf(" is not integer.\nPlease enter an ");
        printf("integer value .such as 25,-178,or 3: ");
    }
    return input;
}
bool bad_limits(long begin, long end, long low, long high)
{ // 判断上下限 要求 low<begin<end<high
    bool not_good = false;
    if (begin > end)
    {
        printf("%ld isn't smaller than %ld.\n", begin, end);
        not_good = true;
    }
    if (begin < low || end < low)
    {
        printf("values must be %ld or greater.\n", low);
        not_good = true;
    }
    if (begin > high || end > high)
    {
        printf("values must be %ld or less.\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;
}

菜单

1、当用户遵循指令时程序顺利运行
2、当用户没有遵循指令时也需要顺利运行

显示选项
获取用户的响应
当选项不是‘q’时
当响应不合适时
提示用户再次输入
获取用户的响应
当响应合适时
转到相应的选项并执行
获取下一个选项

char get_first(void);
char get_choice(void);
int get_int(void);
void count(void);

    int choice;

    while ((choice = get_choice()) != 'q') // 获取选项
    {
        switch (choice)
        { // 处理选项
        case 'a': printf("Buy low,sell high. \n");
            break;
        case 'b': putchar('\a'); /* ANSI*/
            break;
        case 'c': count();
            break;
        default: printf("Program error !\n");
            break;
        }
    }
    printf("Bye. \n");

char get_first(void)
{ // 只取第一个字符
    int ch;
    ch = getchar(); /*读取下一个字符*/
    while (getchar() != '\n')
        continue; /*跳过该行剩下的内容,避免下一次取出问题*/
    return ch;
}
char get_choice(void)
{ // 显示选项、并获取正确选项
    int ch;
    printf("Enter the letter of your choice : \n");
    printf("a. advice               b. bell\n");
    printf("c. count                q. quit\n"); // 显示选项
    ch = get_first();                        // 获取第一个字符
    while ((ch < 'a' || ch > 'c') && ch != 'q')
    { // 当输入错误时提示重新输入
        printf("Please respond with a, b, c, or q.\n");
        ch = get_first();
    }
    return ch;
}
int get_int(void)
{ // 取一个整数,剩下的丢掉
    int input;
    char ch;
    while (scanf("%d", &input) != 1)
    {
        while ((ch = getchar()) != '\n')
            putchar(ch);
        printf(" is not an integer.\nPlease enter an ");
        printf(" integer value,such as 25,-127,or 3:");
    }
    return input;
}
void count()
{ // 输入n,显示1-n
    int n, i;
    printf("Count how far?Enter an integer:\n");
    n = get_int(); // 保证输入正确,如果直接scanf会导致\n留在缓冲区,被下一个getchar读入
    for (i = 1; i <= n; i++)
    {
        printf("%d\n", i);
    }
    while (getchar() != '\n')
        continue; /*跳过该行剩下的内容*/
}

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值