#C02L06P01. C02.L06.实型变量与格式化输入输出.语法知识1.格式化输入输出函数

C02.L06.实型变量与格式化输入输出.语法知识1.格式化输入输出函数

1. 从 cin/cout 到 scanf/printf

我们学习过的 cin、cout,一般情况下,用来输入、输出数据已经足够了。但这种方法电脑的运行效率比较低,尤其是数据量达到 10 万个以上时会非常明显,很容易就会超时。

为了能够更快输入、输出较多的数据,需要使用格式化输入(scanf)和输出函数(printf)。

格式化输入(scanf)和输出函数(printf)的格式如下:

scanf(格式控制符,地址列表);
printf(格式控制符,输出列表);

例如:输入一个整数并将这个数输出。

scanf("%d",&a);
printf("%d",a);

说明:

(1)使用scanf 和printf,需要调用头文件。

(2)“%d”叫做格式控制符,格式控制符代表了输入或输出的“格式说明”,%d表示输入的数据是整数。scanf和printf的使用方法是一样的,只不过前者比后者在变量前多了个“&”号,这些变量跟前面的格式控制符是一一顺序对应的。

一些常用格式控制符说明见下表:

格式控制符 说明
%d 整型(-2147483648 ~2147483647)
%lld 长整型(-9223372036854775808 ~ 9223372036854775807)
%f 单精度浮点数
%lf 双精度浮点数
%c 单字符

程序改进:

#include<bits/stdc++.h>
using namespace std;
int n,r,a,s;
int main()
{
    cin>>n>>r;
    for (int i=1; i<=n; i++)
    {
       scanf("%d",&a);//cin>>a;
       if (a<=r) s++;
    }
          
    cout<<s;
    return 0;
}

2. 提升和拔高

scanf 命令的第二个参数是变量的地址,这个地址讲的是 内存地址。变量其实就是存储单元,变量的值是以某种格式存放到计算机的内存当中的。物理上的内存条其实由很多很多更细更小的单元组成。

在上一节课讲计算 空间复杂度 的时候讲过变量的存储空间的时候讲过:一个 int 变量对应是 4 个 byte, 一个 long long 变量对应的是 8 个 byte......讲的就是变量在内存中占用的空间。内存都是有地址的,类似我们各人的家,都是有门牌号一样。我们定义一个变量的时候,就会给这个变量分配一个地址,这个地址对应的内存空间就是属于这个变量的,以后我们要给这个变量赋值,就是去到这个变量对应的内存地址去修改里面的数值。

上面讲到的 & 运算符,如果它是单目运算符(就是 & 前面没有参数),那么它表示的就是获得内存地址的意思,例如 &a 就是获得变量 a 的内存地址的开始位置。

int a;
scanf("%d",&a); //&a 就是获得变量 a 的内存地址

对于数组来说,单单引用数组名称而不带下标,得到就是这个数组第一个元素的内存地址

int a[100];
scanf("%d",a);  // a 就是数组第一个元素的地址,所以写 a 相当于写 &a[0];
scanf("%d",a+1);  // a+1 是数组元素的第二个元素的地址,所以写 a+1 相当于写 &a[1];  

因此,对一个数组赋值,可以这样写:

int a[100];
for(int i=0;i<n;i++)
	scanf("%d",a+i);  //相当于 scanf("%d",&a[i])

3. 常见错误

3.1 漏了写&,会出现 runtime 错误

错误代码例子

int a;
scanf("%d",a);

上面这段代码,会出现内存越界的错误(一般会提示 runtime error)。因为执行 scanf 的时候,输入的数据会送到 a 这个值所指向的内存那里去,注意,不是变量 a 所分配的地址

例如,如果 a 在执行scanf之前的值是 0 。那么 scanf 的执行效果是接收一个输入值,把值存放到内存地址为 0 的内存单元那里去。而存放 a 变量的地址可能是 12349876 。 所以,相当于是吧数据写到了错误的地方去了,导致内存越界。

3.2 写错了格式提示符,没有正常赋值

错误代码例子

long long a;
scanf("%d",&a);

变量是 long long 类型,但是 scanf 的第一个参数格式说明说的是 int 类型。scanf 并不会检查这个声明是否正确,它只会傻傻的去按照你提供的格式说明去做。它会从接受一个整数,存放到 a 变量对应的地址那里去,而且是当做 int 来处理。

而我们知道,一个 int 是 4 个 byte,一个 long long 是 8 个 byte,所以上面的 scanf 执行的时候只会改写 a 变量的 4 个 byte,而另外 4 个 byte 是完全没动过。这会出现什么结果呢?如果 a 是一个局部变量,内存里面本身有内容的,那么在 scanf 的时候并没有抹掉之前旧的数据(有 4 个 byte 保持不变,原来是什么就什么),所以你可能输入的是 100 ,但是因为那 4 个 byte 有内容,a 的值最终是 10000000000004 都是有可能的,所以,整个程序的运行结果是错的,而且是不可控的(每次运行的结果都可以不一样,结果飘忽不定)。