C语言基础级——标准输入和输出

输入和输出

转载请标明出处!

说一下题外话,最近在出差,所以没什么精力,导致更新进度滞后。也是兴致来朝,索性更新一篇。

那本节内容主要讲解,C语言的标准输入与输出的定义、使用以及内容缓冲区的原理,让你能够对C语言的printf和scanf有更加深刻地理解。

1 标准输出

C语言标准输出是一个接口库函数,已经写好了实现,我们只需要去调用它,就可以实现从终端中打印出信息。标准输出函数格式:

// [返回值] [函数名]([格式化字符串], [可变参数列表]);
int printf(const char* fromat, ...);
  • 参数:
    • fromat 为格式化字符串,包含两部分。第一部分是正常字符,原样输出。第二部分是格式占位符。
    • ... 为可变参数列表,可变参数个数与格式占位符数量一致。
  • 返回值
    • 作用是打印出字符的个数。(包括空白字符)

1.1 格式占位符

含义 格式占位符
用于有符号整型 %d or %i
用于字符 %c
用于无符号整型 %u
用于单浮点数 %f or %F
用于双精度浮点数 %lf
用于科学计算法表示浮点数 %e or %E
用于实数(不显示无意义0) %g or %G
用于内存地址 %p
用于字符串 %s

1.2 输出方式

第一种,无格式占位符。

注:这里的字符 \n 是一个字符,代表着换行,ASCI码为13。

printf("Hello Home!\n");

第二种,一个格式占位符。

int param = 10;
printf("param = %d", param);

第三种,多个占位符。

int param_a = 100;
int param_b = 200;
printf("param_a = %d, param_b = %d\n", param_a, param_b);

1.3 头文件

在真正的使用过程中,如果我们只调用 printfscanf 往往还是不够的,还需要先调用系统的库文件。

#include <stdio.h>

因为在 stdio.h 文件当中包含 printfscanf 两个函数的声明,Linux 系统提供给外部的接口函数,用户可以直接拿来使用。

1.4 扩展

第一种,有 个占位符,无可变参数。

printf("hello %s");

我们会发现在Linux系统下编译,并没有报 error, 而是 warning ,且最后输出结果除了 Hello boys 以外,后面都是乱码, 原因是我们并没有相应加上需要输出的参数。

第二种,无占位符,由于输出格式字符串较长,有些人习惯把字符串分为多行。

printf("Hello boys 
       		and
       		girls!");

这种方式是错误的,固定字符串不能够直接进行换行,否则在编译期间将会报错。那我们怎么解决这个问题呢?是的,要引入换行符(\)。

printf("Hello boys	\
       		and		\
       		girls!");

2. 标准输入

printf 这个函数大多数人都可以使用好,虽然 printfscanf 两个函数原型相同,但是 scanf 在用起来,还是有些让人抓狂的错误,那我们先来看下,C语言标准输入函数格式:

// [返回值] [函数名]([格式化字符串], [可变参数列表]);
int scanf(const char *format, ...);
  • 参数:
    • fromat 为格式化字符串,包含两部分。第一部分是正常字符,原样输出。第二部分是格式占位符。
    • ... 为可变参数列表,可变参数个数与格式占位符数量一致。
  • 返回值
    • 成功返回读入的数据项数。
    • 遇到错误或遇到 end of line,返回 EOF(按Ctrl+Z)。
int n;
scanf("%d", &n);

变量有它的基础数据特性,还有一个是地址(address),怎么理解地址?从生活上,可以理解为是”商品盒子“上的数字标签,如果把这个地址给到你的朋友,他就能通过这个地址来找到对应数字标签的盒子。”数字标签“就是地址,”盒子“就是变量,盒子里”物品“是变量存储的值。

& 就是取 n 变量的地址,那我们为什么要取变量地址呢?因为用户从终端输入信息后存放到输入缓冲区,scanf函数 要通过地址找到变量存储区域,然后缓冲区里的信息传送给变量这块地址。

2.1 扩展

2.1.1 %d%d

scanf函数的使用要严格按照规定的格式输入。例如格式化字符串为 %d+%d ,那么在终端输入就要加上中间的 +,否则可能得不到你想要的结果。

int n;
int m;
scanf("%d+%d", &n, &m);

在这里插入图片描述

如果想要在终端连接输入两个元素。

#include<stdio.h>

int main()
{
    
    
    int n;
    int m;

    scanf("%d%d", &n, &m);

    printf("n = %d\n", n);
    printf("m = %d\n", m);
    return 0;
}

在这里插入图片描述

大家仔细可以看到,输入的是 20 30,中间是有一个空格把两个元素分开,而 scanf 里是 %d%d 并没有空格把两者分隔开,为什么我们可以这么做?这是因为 scanf 在处理输入时,如果格式占位符不是用于读入单个字符%c, 它就会将空白字符(空格符、制表符和换行符)都视为一次输入的终止标记。

2.1.2 %c%c

#include<stdio.h>

int main()
{
    
    
    char n;
    char m;

    scanf("%c%c", &n, &m);

    printf("n = %c\n", n);
    printf("m = %c\n", m);
    return 0;
}

在这里插入图片描述
在这里插入图片描述

输入 ab 之间如果加了空格空白字符也会被读入,所以大家一定要注意,不能够加入空格,如果要加入空格的话,应这么写输入:

scanf("%c %c", &n, &m);

3. 缓冲区

我们来看下曾经困扰很多人的问题,先看下代码。

#include <stdio.h>

int main()
{
    
    
    int n;
    
    scanf("%d\n", &n);
    printf("n = %d\n", n);
}

如果我们正常输入一个整型,然后按下回车(\n),输出结果是:

2\n

在这里插入图片描述

无论输入了多少个回车(\n),运行处于阻塞状态。然后我们再输入任意的数,看看结果。

在这里插入图片描述

发现当我们输入任意的数时候,再去敲回车(\n),程序继续执行打印,运行结果结束且最终打印结果是我们第一次输入的结果,也就是 2

这样的现象,其实是和缓冲区是有关的,怎么去解释呢?

首先,输入的是 2\n\n\n\n ,这一串数据是存放在缓冲区内。

在这里插入图片描述

然后,我们再输入 3\n ,这个时候,退出阻塞,输出 2 ,程序结束,那么缓冲区数据为:

在这里插入图片描述

根本上造成这个现象是因为,缓冲区里最先输入的 2\n 是满足 scanf 输入的格式,但是接下来的三个 \n 在它相邻左边并没检测到有效的字符(它们的左边一个都是空白字符),导致了程序阻塞,直到 3\n 的出现,最后一个 \n 检测到它相邻左边有一个非空白字符,阻塞就退出了。

那输出为 2 而不是 3 的原因是,缓冲区是单向的,有点像队列(先进先出),所以我们会输出第一个非空白字符,也就是 2

猜你喜欢

转载自blog.csdn.net/qq_43125185/article/details/111255008