1、标准输入
- 概念:键盘是系统的标准输入设备,从键盘中输入数据被称为标准输入
- 相关函数:
scanf(); // 格式化输入函数
fgets(); // 字符串输入函数
int a;
float f;
scanf("%d", &a); // 从键盘输入一个整型,放入指定的内存地址 &a 中
scanf("%f", &f); // 从键盘输入一个浮点数,放入指定的内存地址 &f 中
scanf("%d%f", &a, &f); // 从键盘依次输入一个整型和一个浮点型数据,用空白符隔开、
// 123 345.4
// 123345.4 会被识别为一个整体
scanf("%f%d", &a, &f);
// 123.456 789
char c;
char s[10];
scanf("%c", &c); // 从键盘输入一个字符,放入指定的内存地址 &f 中
scanf("%s", s ); // 从键盘输入一个单词,放入指定的数组 s 中(注意不是&s)
fgets(s, 10, stdin); // 从键盘输入一行字符串,放入数组 s 中
- 注意1:
- scanf() 与 printf() 不同,scanf() 的格式控制串不可乱写,尤其是结尾处的 \n
- 用户必须完全按照 scanf() 中描述的输入格式控制串来输入数据,否则将出错。
#include <stdio.h>
// 从文件 stream 获取一个字符
int fgetc(FILE *stream);
// 从 stream 获取一行字符串 %s ,并把数据存入到 s 中,size则用于控制获取数据的大小避免越界
char *fgets(char *s, int size, FILE *stream);
// 从文件 stream 获取一个字符
int getc(FILE *stream);
// 默认从标准输入中获取一个字符并返回
int getchar(void);
// 从文件 stream 获取一个字符 ,并该字符不能是 c
int ungetc(int c, FILE *stream);
实例:
char arr [32] ;
// 从标准输入文件stdin 中获取一个行不超过32字节的数据,并存入到 arr 中
fgets( arr , 16 , stdin ); // 当实际输入的数据超过限定16个字节的时候则会自动截断
// 实际获得的长度为 size - 1 并会在数据的末尾补充一个结束符 \0
// 该函数在获取输入数据时,如果空间足够则会把回车符一并获取
// 该函数在获取字符串类型的数据时有两个结束条件:
// 1. 用户按下回车
// 2. 达到 size - 1个字节
printf("arr:%s\n" , arr );
注意:
- scanf() 与 printf() 不同,scanf() 的格式控制串不可乱写,尤其是结尾处的 【\n】 以及 【空格】
- 用户必须完全按照 scanf() 中描述的输入格式控制串来输入数据,否则将出错。
- scanf() 的返回值,代表成功从键盘读取的数据的个数
- 无法匹配 scanf() 指定格式的数据,将被遗留在输入缓冲区中,不会消失(因此有可能会影响下一次从键盘获取数据)
- 因此在使用scanf之后我们应该手动去清理缓冲区 getchar()
// 使用循环不断从标准输入中读取一个字符,直到遇到\n回车符为止
while( getchar() != '\n' );
下面是一个练习小例子,感兴趣得小伙伴可以尝试做做:
操作练习:
- 尝试使用scanf 函数获取各种不同的数据类型(int float char 等)
- 注意体会他的特性(阻塞 、 分隔符 、 格式是否匹配 等)
- 编程实现如下功能:
- 如果用户输入大小写字母,则输出字母对应的ASCII码值。
- 如果用户输入ASCII码值,则输出对应的大小写字母。
- 如果用户输入大小写字母,则输出字母对应的ASCII码值。
2、类型转换
- 概念:不一致但相互兼容的数据类型,在同一表达式中将会发生类型转换。
- 转换模式:
- 隐式转换:系统按照隐式规则自动进行的转换
- 强制转换:用户显式自定义进行的转换
- 隐式规则:从小(低精度)类型向大(高精度)类型转换,目的是保证不丢失表达式中数据的精度
隐式转换示例代码:
char a = 'a';
int b = 12;
float c = 3.14;
float x = a + b - c; // 在该表达式中将发生隐式转换,所有操作数被提升为float
- 强制转换:用户强行将某类型的数据转换为另一种类型,此过程可能丢失精度
char a = 'a';
int b = 12;
float c = 3.14;
float x = a + b - (int)c; // 在该表达式中a隐式自动转换为int,c被强制转为int
不管是隐式转换,还是强制转换,变换的都是操作数在运算过程中的类型,是临时的,操作数本身的类型不会改变,也无法改变。
3、数据类型的本质
- 概念:各种不同的数据类型,本质上是用户与系统对某一块内存数据的解释方式的约定。
- 推论:
- 类型转换,实际上是对先前定义时候的约定,做了一个临时的打破。
- 理论上,可以对任意的数据做任意的类型转换,但转换之后的数据解释不一定有意义。
4、整型数据尺寸
- 概念:整型数据尺寸是指某种整型数据所占用内存空间的大小
- C语言标准并未规定整型数据的具体大小,只规定了相互之间的 “ 相对大小 ” ,比如:
- short 不可比 int 长
- long 不可比 int 短
- long 型数据长度等于系统字长
- 系统字长:CPU 一次处理的数据长度,称为字长。比如32位系统、64位系统。
- 典型尺寸:
- char 占用1个字节
- short 占用2个字节
- int 在16位系统中占用2个字节,在32位和64位系统中一般都占用4个字节
- long 的尺寸等于系统字长
- long long 在32位系统中一般占用8个字节,在64位系统中一般占用8个字节
- 存在问题:
- 同样的代码,放在不同的系统中,可能会由于数据尺寸发生变化而无法正常运行。
- 因此,系统标准整型数据类型,是不可移植的,这个问题在底层代码中尤为突出。
5、可移植性整型
- 概念:不管放到什么系统,尺寸保持不变的整型数据,称为可移植性整型
- 关键:typedef
typedef int int32_t; // 将类型 int 取个别名,称为 int32_t
typedef long int64_t;// 将类型 long 取个别名,称为 int64_t
- 思路:
1.为所有的系统提供一组固定的、能反应数据尺寸的、统一的可移植性整型名称
2.在不同的系统中,为这些可移植性整型提供对应的 typedef 语句
系统中有定义好的可移植的数据类型:
/usr/include/x86_64-linux-gnu/bits/types.h
#include <stdio.h>
int main(int argc, char const *argv[])
{
long Num1 ; // 在不同的系统中他的大小有可能发生变化
__int64_t Num2 ; // 在任何的系统中都可以识别为 64位(8字节)的整型
__int128_t Num3 ; // 老的系统中可能没有对他进行实现 【不可用】
printf("sizeof(Num1):%ld sizeof(Num2):%ld sizeof(Num3):%ld \n" ,
sizeof(Num1) , sizeof(Num2) , sizeof(Num3) );
return 0;
}