4.输入与输出

Input & Output --> 标准IO、文件IO

一、函数类型

1.格式化输入输出函数: printf & scanf

(1)printf

定义如下:int printf(const char *format, ...);

format: 是字符串,包含了要被写入到标准输出 stdout 的文本

printf %[修饰符] 格式字符"

format 标签属性是%[flags][width][.precision][length] specifier

  • specifier
    image

  • flags
    image

  • width
    image

  • .precision
    image

  • length
    image

Example1:

#include <stdio.h>
#include <stdlib.h>

#define STRSIZE 32
int main()
{
    int i = 255;
    float f = 123.456;
    double dou = 123.4567;
    char str[STRSIZE] = "hello world!";
    long long ll = 123456;
    
    printf("整形 i = %d\n", i);
    printf("十六进制 i = %#x\n", i);
    printf("八进制 i = %#o\n", i);
    printf("str = %d\n",str);
    printf("f = %e\n", f);
    printf("f = %E\n", f);
    
    exit(0);
}

输出结果:

整形 i = 255
十六进制 i = 0xff
八进制 i = 0377
str = hello world!
f = 1.234560e+02
f = 1.234560E+02

Example2:

//printf 大法判断死循环出现的地方
#include <stdio.h>
#include <stdlib.h>

#define STRSIZE 32
int main()
{
    int i = 255;
    float f = 123.456;
    double dou = 123.4567;
    char str[STRSIZE] = "hello world!";
    long long ll = 123456;
    
    printf("[%s:%d],before while.",__FUNCTION__, __LINE__);
    while(1);  //死循环
    printf("[%s:%d], after while.",__FUNCTION__, __LINE__);
    
    exit(0);
    
}

输出结果:

无输出结果!!!“before while ”并不会打印出来,这是一种缓冲机制。为了正确显示,需要添加“\n”,该转义字符会刷新缓冲区,并能将字符打印出来,否则只能等程序正常结束
之后(这里显然是不可能的)。

修改后效果:

整形 i = 255
十六进制 i = 0xff
八进制 i = 0377
str = hello world!
f = 1.234560e+02
f = 1.234560E+02
[main:21],before while.
···

若将while(1)-->sleep(5):

整形 i = 255
十六进制 i = 0xff
八进制 i = 0377
str = hello world!
f = 1.234560e+02
f = 1.234560E+02
[main:22],before while.
( 5 sec later ··· )
[main:25], after while.

若将\n去除,则有:

整形 i = 255
十六进制 i = 0xff
八进制 i = 0377
str = hello world!
f = 1.234560e+02
f = 1.234560E+02
> ( 5 sec later ··· )  //此时程序已经执行结束,缓冲区此时被刷新。
[main:23],before while.[main:27], after while.  //两者被同时输出。

(2)scanf

int scanf(const char *format, ...(地址表));

Example1:简单打印与输出

#include <stdio.h>
#include <stdlib.h>

#define STRSIZE 32

int main()
{

        int i;  //整形:%d
        float f;  //浮点型:%f
        char str[STRSIZE];
        
        printf("Please Enter :\n");
        //指定输入字符的数据类型要与变量定义相同 这里“%d%f”之间不用加任何字符,否则在输入数值时,需要输入该多余字符,否则无法正确打印输入的值
        scanf("%d%f%s",&i, &f,str);   //最后也不要加"\n" //输出字符串时,不需要进行取址操作,因其本身就是地址常量。  
        printf("i = %d, f = %f\n, str = %s",i,f,str);

        exit(0);
}

输出结果:

Please Enter :   //紧接着输入下一个字符时,需通过输入空格键、TAB、或者回车键均可。
12
2.332
hello world
i = 12, f = 2.332000,str = hello //"hello world"只打印了"hello",原因是输入的时候加入了空格,编译器会认为输出结束,跟上面提到的三种输入方法刚好对应。

Example2: Scanf函数使用的注意事项以及函数返回值

include <stdio.h>
#include <stdlib.h>

#define STRSIZE 32  //表示定义的char型字符的位数

int main()
{

        int i, ret;
        float f;
        
        printf("Please Enter :\n");
        
        while(1)
        {
             //如果输入的值类型与当前定义数据类型相匹配,则当前scanf返回值为1
             ret = scanf("%d",&i); //scanf返回值=与定义类型匹配的输入项数
             if(ret != 1)  //使用scanf函数返回值进行校验,避免进入死循环。
             {
                prinf("Enter Error!\n");
             }
             printf("i = %d\n",i);
        }
        
        exit(0);
}

输出结果:

Please Enter :
1
i = 1
2
i = 2
s
Enter Error!

当进行如下形式多次输入时:

scanf("%d",&i);//输入之后会有一个回车
scanf("%c",&ch);
为避免空格键或者换行对输入输出值产生影响,需要使用scanf函数中的抑制符"*"
scanf("%*c%c",&ch);  //换行符的值被""%*c"吃掉了,不会将其值赋给ch
或者使用:
getchar();  //位于两次输入函数之间,将换行符、空格符"吃掉"。
  • %s的使用比较危险,因为不知道存储空间大小;
  • scanf在循环结构中使用时要注意数值是否被正确接收。

2.字符输入输出函数:getchar & putchar

有关getchar()的描述:

 int getchar(void);  //不传入任何参数,直接从标准输入流中获取数据,然后再以返回值的形式获取数据
 返回值类型:
 fgetc(), getc(), and getchar() return the character read as an unsigned char cast to an int or EOF on end  of  file  or error.
返回值返回一个字符,该字符作为无符号char型读取的,构造成int类型或者在文件的末尾处或出错位置的EOF

Example:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int ch;  //接收返回值,防止出错的情况。
    
    ch = getchar();  //ch负责接收getchar()的返回值,为避免出错将ch定义为整形。
    putchar(ch);    //将传入的值输出到窗口,表示默认标准输出,并且没有换行的功能
}

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./getchar_putchar 
h   
hjxs@jxs-ubuntu:~/Desktop/c  language/io$

3.字符串输入输出函数:(Dangerious)gets & puts

gets 描述:

SYNOPSIS
#include <stdio.h>
char *gets(char *s);
DESCRIPTION
Never use this function. //永远不要使用这个函数
gets() 从stdin中读取一行数据,并将其读入s指针指向的缓冲区,直到要么遇到换行符要么遇到Error of File才算输入完成。,并在其尾部追加占用一个字节的”\0“,不建议使用的原因是该函数不会对缓冲区是否溢出做检查。会出现:已指定内存空间大小,但输入的数据大小在大于空间大小时,并不会报错,造成缓冲区溢出。因此使用该函数很危险!

Example:

#include <stdio.h>
#include <stdlib.h>

#define STRSIZE 3  //指定字符串长度
int main()
{
    char str[STRSIZE];
    gets(str);
    puts(str);
    
    exit(0);
}

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./gets_puts 
1
1
jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./gets_puts 
abc
abc
jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./gets_puts 
ahhshfhsfh
ahhshfhsfh

不管输入的字符串长度有多长,gets均会输出,即使缓冲区溢出,因此使用该函数很危险,常用fgets()代替,但治标不治本,可以使用“getline()”(实现动态内存分配)来解决这个问题

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

二、练习

Examples1:

#include <std   io.h>
#include <stdlib.h>
#include <math.h>
/*
#define WEIGHT 950
#define QUART 3.0e-23
static void water(void)
{
        float n_quart;
        double n_h2o;

        printf("Please input number of quart:");
        scanf("%f",&n_quart);
        n_h2o = n_quart * WEIGHT / QUART;
        printf("n_h20 = %e\n",n_h2o);
}*/
static void aera(void)
{
        float a, b, c;
        float s, aera;

        printf("Please input the length of edges:");
        scanf("%f%f%f",&a, &b, &c);
        //Is this a triangle? use array!
        s = 1 / 2 * (a + b + c); 
        aera = sqrt(s * (s - a) * (s - b ) * (s - c));
        printf("aera = %f\n", aera);
}

int main()
{
       //water();
        aera();

        exit(0);
}

输出结果:

Please input the length of edges:4 5 3
aera = -0.000000

问题:面积输出值为0?
s = 1 / 2 * (a + b + c); 问题出现在这
原因:s,a,b,c均为float类型数据而1,2,为整形数据,计算时1 / 2 = 0而不是0.5;
原始修改为:1 --> 1.0,2 --> 2.0.
正确输出:

Please input the length of edges:4 5 3
aera = 6.000000

上面的程序需要考虑三角形边长之间的关系“两边之和大于第三边,两边之差小于第三边”。

加入语句:

if(a + b <= c || a + c <= b || b + c <= a || a - b >= c || a - c >= b || b - c >= a)
{
    fprintf(stderr,"Input Error!");
    exit(1);  //程序中断
}

Examples2:

#include <std   io.h>
#include <stdlib.h>
#include <math.h>

static void root()
{
        float a, b ,c, x1, x2, delta;
        printf("Please enter the equation coefficients:");
        scanf("%f%f%f",&a,&b,&c);

        //if delta >= 0?
        delta = pow(b,2) - 4 * a * c;
        if(delta <= 0)
        {

                printf("Parameter Error!\n");
                exit(1);
        }

        x1 = (-b + sqrt(delta)) / 2 * a;
        x2 = (-b - sqrt(delta)) / 2 * a;

        printf("x_1 = %f, x_2 = %f \n",x1,x2);
}
int main()
{
        root();
        
        exit(0);
}

输出结果:

jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./root 
Please enter the equation coefficients:1 5 6
x_1 = -2.000000, x_2 = -3.000000 
jxs@jxs-ubuntu:~/Desktop/c  language/io$ ./root 
Please enter the equation coefficients:1 -5 6
x_1 = 3.000000, x_2 = 2.000000 

设计方程的代码块,尽量将方程拆分,以便调试。

posted @ 2023-06-29 17:05  假行僧me  阅读(5)  评论(0编辑  收藏  举报