Bootstrap

[一篇读懂]C语言一讲:数据的类型、数据的输入输出


1. 数据类型-常量-变量(整型-浮点-字符)

1 数据类型

数据类型分类:
数据类型
关键字:

autoconstdoublefloatintshortstructunsigned
breakcontinueelseforlongsignedswitchvoid
casedefaultenumgotoregistersizeoftypedefvolatile
chardoexternifreturnstaticunionwhile

2 常量

  • 常量指在程序运行过程中,值不发生变化的量。
  • 可分为整型、实型(也称浮点型)、字符型和字符串型。
  • 整型 - 100,125,-100,0
  • 实型 - 3.14,0.125,-3.789
  • 字符型 - ‘a’,‘b’,‘2’
  • 字符串型 - “a”,“ab”,“1c34”

3 变量

变量名、变量值和存储单元的关系:
变量

  • 变量指内存中具有特定属性的一个存储单元,它用来存放数据,即变量的值。
  • 这些值在程序的执行过程中是可以改变的。
  • 每个变量名分配对应的内存地址(空间)。
  • 变量命名规定如下:只能由字母、数字和下划线三种字符组成,并且第一个字符必须为字母或下划线。

例如:
sum,_total,month,Student_name,lotus_1_2_3,BASIC,li_ling
是正确的。
 
而M.D.John,¥123,3D64,a>b
是错误的。

  • 先定义,后使用
  • 尽量做到“见名知意”,注意,变量名不能与关键字同名!

4 整型数据

4.1 符号常量

定义整型变量时要使用关键字int:

#include <stdio.h>

#define PI 3+2
int main()
{
	int i = PI * 2;
	printf("i = %d\n",i);
}

最终输出的结果是7,原因是符号常量PI是直接替换的效果,即3+2*2=7,而不是8。

4.2 整型变量

  • 通过int i来定义整型变量,i占用4个字节空间

5 浮点型数据

5.1 浮点型常量

  • 表示浮点型常量的方式有两种,如下所示,其中e代表10的幂次,幂次可正可负。
小数形式指数形式
0.1233e-3(为 3 × 1 0 − 3 3×10^{-3} 3×103,即0.003)
  • 注意,字母e(或E)之前必须有数字,且e后面的指数必须为整数。

正确示例:1e3、1.8e-3、-123e-6、-.1e-3。
错误实例:e3、2.1e3.5、.e3、e。

5.2 浮点型变量

  • 通过float f来定义浮点变量,f占用4个字节空间

6 字符型数据

6.1 字符型变量

  • 用单引号括起来的一个字符是字符型常量,且只能包含一个字符! 例如, ‘a’、‘A’、‘1’。
  • ’ '是正确的字符型常量。

‘abc’、“a”、" "是错误的字符型常量。

  • 转义字符:以“\”开头的特殊字符,转义字符可用来表示回车、退格等功能键。
转义字符作用
\n换行
\b退格
\\反斜杠

6.2 字符数据在内存中的存储形式及使用方法

  • 字符型变量使用关键字char进行定义,一个字符型变量占用1字节大小的空间。
  • 一个字符常量把该字符的ASCII码值放到存储单元中。
  • 字符型数据和整型数据之间可以通用。
  • 字符型数据既可以以字符形式输出,又可以以整数形式输出,还可以通过运算获取想要的各种字符:
#include <stdio.h>
int main()
{
	char c = 'A';
	printf("%c\n",c+32);
	printf("%d\n",c);
}
  • 对于字符型变量,无论是赋ASCII码值还是赋字符,使用%c打印输出时得到的都是字符,使用%d打印输出时得到的都是ASCII码值。
  • 将小写字母转换为大写字母时,由ASCII码表发现小写字母与大写字母的差值为32,因此将a减去32就可以得到大写字母A。

7 字符串型常量

  • 字符串型常量是由一对双引号括起来的字符序列。
  • 例如,“How do you do.”、“CHINA”、“a”和“$123.45”。
  • 注意,'a’是字符型常量,而“a”是字符串型常量,二者是不同的。
  • 在字符串型常量的结尾加一个字符串结束标志’\0’,以便判断字符串是否结束。

例如,字符串型常量“CHINA”在内存中占用的内存单元不是5个字符,而是6字符,即大小为6个字节,最后一个字符为’\0’。
 
在内存中的存储结果:
图

8 ASCII码表

1234在这里插入图片描述


2. 混合运算 - printf讲解

1 混合运算

类型强制转换场景

  • 整型数进行除法运算时,如果运算结果为小数,那么存储浮点数时一定要进行强制类型转换:
#include <stdio.h>
//强制类型转换
int main()
{
	int i = 5;
	float f = i / 2;//2.0 - 左右操作数都是整型,这里做整型运算,商为2余数1
	//类型强制转换
	float k = (float)i / 2;//2.5 - 表达式的类型为浮点型
	printf("%f\n", f);//2.0
	printf("%f\n", k);//2.5

	return 0;

}

j得到的值为2,k得到的值是2.5,因为当我们整数做除法时,默认进行整除,要得到小数,需要首先进行强制类型转换操作。

2 printf函数介绍

  • printf函数可以输出各种类型的数据,是printf函数将这些类型的数据格式化为字符串后,放入标准输出缓冲区,然后将结果显示到屏幕上。
#include <stdio.h>
int printf(const char *format, ...);
  • 字符串格式(format)由两部分组成:显示到屏幕上的字符和定义printf函数显示的其他参数。
int age = 21;
printf("Hello %s, you are %d years old\n","Bob",age);

输出:Hello Bob, you are 21 years old

printf函数的具体代码格式:

代码格式
%c字符
%d带符号整数
%f浮点数
%s一串字符
%u无符号整数
%x无符号十六进制数,用小写字母
%X无符号十六进制数,用大写字母
%p一个指针
%%一个’%'符号

位于%和格式化命令之间的一个整数被称为最小字段宽度说明符,通常会加上空格来控制格式。

  • 用%f精度修饰符指定想要的小数位数。例如,%5.2f会至少显示5位数字并带有2位小数的浮点数。
  • 用%s精度修饰符简单地表示一个最大的长度,以补充句点前的最小字段长度。
  • printf函数的所有输出都是右对齐的,除非在%符号后放置了负号。例如,%-5.2f 会显示5位字符、2位小数位的浮点数并且左对齐
#include <stdio.h>
//练习printf
//int main()
//{
//	int age = 21;
//	printf("Hello %s, you are %d years old\n", "Bob", age);
//	return 0;
//}

int main()
{
	int i = 10;
	float f = 96.3;
	printf("student number =%d score=%f\n", i, f);

	printf("student number =%3d score=%5.2f\n",i,f);//%3d 占三个位置 - 对齐 //%5.2f 5 - 整体占五个位置 2 - 小数点后保留两位

	printf("student number =%-3d score=%-5.2f\n",i,f);//默认是右对齐,加一个负号 - %-3d - 左对齐
	i = 100;//第一次是定义,再次使用不需要定义
	f = 98.21;
	printf("student number =%d score=%f\n", i, f);//上下不对齐

	return 0;
}

运行结果:
结果


3. 整型进制转换

1 整型常量的不同进制表示

  • 计算机中只能存储二进制数,即0和1,而在对应的物理硬件上则是高、低电平。
  • 除我们正常使用的十进制数外,计算机还提供了十六进制数和八进制数。
进制基数
二进制0和1
十进制(%d)0-9
八进制(%o)0-7
十六进制(%x)0-9和a-f
  • 1字节(byte)为8位(bit),1位即二进制的1位,它存储0或1。

int型常量的大小为4字节,即32位。

  • 二进制数0100 1100 0011 0001 0101 0110 1111 1110
    最高位0是符号位。
    对应的是2的幂次
  • 十六进制在观察内存时需要频繁使用。
  • 例i的值是7b(十六进制),其十进制值为7×16+11=123,i的值是0x0000007b。
     
    地址显示结果为7b 00 00 00,
    原因是CPU采用了小端方式进行数据存储,因此低位在前、高位在后。
#include <stdio.h>

int main()
{
	int i = 123;
	//二进制 0000 0000 0000 0000 0000 0000 0111 1011
	printf("%d\n", i);//123
	printf("%o\n", i);//173
	printf("%x\n", i);//7b
	return 0;
}

十进制数转换为二进制的方法:

1
小技巧

  • 可在Windows操作系统下选择“开始”→“计算器”,打开“计算器”。
  • 选择菜单项“查看”→“程序员”可以得到对应进制的转换结果。

1


4. scanf读取标准输入

1 常用的数据输入/输出函数

  • C语言可通过函数库读取标准输入。
    1

1 scanf函数的原理

  • C语言通过scanf函数读取键盘输入,键盘输入又称为标准输入。
  • 当scanf函数读取标准输入时,如果没有输入任何内容,那么scanf函数会被阻塞。
#include<stdio.h>

//scanf用来读取标准输入,scanf把标准输入内的内容,需要放到某个变量空间里,因此变量必须取地址
//scanf会阻塞,是因为标准输入缓冲区是空的

//scanf %d %f 发现里边有\n空格,忽略
//scanf %c 不忽略内容
int main()
{
	int i = 10;
	char c;
	float f;
	scanf("%d", &i);//注意一定要取地址
	printf("i = %d\n", i);//把标准缓冲区中的整型数读走了

	//rewind(stdin);//清空标准输入缓冲区

	//scanf("%c", &c);//读取走了转义字符\n!!!
	//printf("c = %c\n", c);//没有等待输入c - 输出了换行!!!

	scanf("%f", &f);//忽略转义字符\n
	printf("f = %f\n", f);

	//fflush(stdin);//清空标准输入缓冲区
	return 0;
}//直接运行程序卡住 - 阻塞

为什么第二个scanf函数不会被阻塞呢?

  • 其实是因为第二个scanf 函数读取了缓冲区中的’\n’,即 scanf(“%c”,&c)实现了读取,打印其实输出了换行,所以不会阻塞。

但是如果将注释的 fflush(stdin)打开,就会发现第二个scanf(“%c”,&c)会阻塞,这是什么原因呢?

  • 行缓冲:在这种情况下,当在输入和输出中遇到换行符时,将执行真正的IO处理操作。
     
    scanf 函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符。
     
    忽略指scanf函数执行时会首先删除这些字符,然后再阻塞。
     
    在执行scanf(“%c”,&c)语句时,不会忽略任何字符,所以其读取了还在缓冲区中残留的’\n’。

2 多种数据类型混合输入

  • 为了避免字符型数据读取时,并不会忽略空格和’\n’(回车符)。
  • 如下,编写时,在%d与%c之间加入一个空格。
#include<stdio.h>

int main()
{
	int i,ret;//ret是scanf匹配成功的个数
	char c;
	float f;

	//输入100 a 98.2
	//ret = scanf("%d%c%f", &i, &c, &f);//"%d%c%f"之间不加空格 i=100,c= ,f=0.00
	//ret = 2 只匹配成功了两个,因为&c不会忽略任何字符 - %d读走100后,%c读走空格,%f读a时报错返回,所以只匹配成功两个。

	ret = scanf("%d %c%f", &i, &c, &f);//要在%c之前加个空格
	printf("i=%d,c=%c,f=%f\n", i, c, f);
	return 0;
}

格式字符串中的空白字符的含义(来自http://www.cplusplus.com/reference/cstdio/scanf/?kw=scanf):
 
空白字符:该函数将读取并忽略在下一个非空白字符之前遇到的任何空格字符(空格字符包括空格,换行符和制表符 -
请参阅isspace).格式字符串中的单个空格验证从流中提取的任何数量的空白字符(包括无).
 
当您的代码是:

scanf("%d%c", &x, &ch)

然后你进入

10 

在你的控制台:

  1. 10被读取并存储在x.
  2. 读取并存储换行符ch.

 
如果你使用

scanf("%d %c", &x, &ch) 

然后你进入

10
  1. 10被读取并存储在x.
  2. 消费换行符和其他空白字符.程序等待非空白字符.输入一行输入并且该行中至少存在一个非空白字符后,将读入该行的第一个非白色字符ch.这是因为stdin通常是行缓冲的.

总结

1.2

  • 常量指在程序运行过程中,值不发生变化的量。
  • 可分为整型、实型(也称浮点型)、字符型和字符串型。

1.3

  • 变量指内存中具有特定属性的一个存储单元,它用来存放数据,即变量的值。
  • 这些值在程序的执行过程中是可以改变的。
  • 每个变量名分配对应的内存地址(空间)。
  • 变量命名规定如下:只能由字母、数字和下划线三种字符组成,并且第一个字符必须为字母或下划线。

1.4

  • 通过int i来定义整型变量,i占用4个字节空间

1.5

  • 表示浮点型常量的方式有两种,如下所示,其中e代表10的幂次,幂次可正可负。
  • 注意,字母e(或E)之前必须有数字,且e后面的指数必须为整数。
  • 通过float f来定义浮点变量,f占用4个字节空间

1.6

  • 用单引号括起来的一个字符是字符型常量,且只能包含一个字符! 例如, ‘a’、‘A’、‘1’。

  • 转义字符:以“\”开头的特殊字符,转义字符可用来表示回车、退格等功能键。

  • 字符型变量使用关键字char进行定义,一个字符型变量占用1字节大小的空间。

  • 一个字符常量把该字符的ASCII码值放到存储单元中。

  • 字符型数据和整型数据之间可以通用。

  • 字符型数据既可以以字符形式输出,又可以以整数形式输出,还可以通过运算获取想要的各种字符:

  • 字符型变量,用%c打印输出时得到字符,用%d打印输出时得到ASCII码值。

  • 将小写字母转换为大写字母时,由ASCII码表发现小写字母与大写字母的差值为32,因此将a减去32就可以得到大写字母A。

1.7

  • 字符串型常量是由一对双引号括起来的字符序列。
  • 注意,'a’是字符型常量,而“a”是字符串型常量,二者是不同的。
  • 在字符串型常量的结尾加一个字符串结束标志’\0’,以便判断字符串是否结束。

1.8

1234在这里插入图片描述

2.1

  • 整型数进行除法运算时,如果运算结果为小数,那么存储浮点数时一定要进行强制类型转换。

2.2

位于%和格式化命令之间的一个整数被称为最小字段宽度说明符,通常会加上空格来控制格式。

  • 用%f精度修饰符指定想要的小数位数。例如,%5.2f会至少显示5位数字并带有2位小数的浮点数。
  • 用%s精度修饰符简单地表示一个最大的长度,以补充句点前的最小字段长度。
  • printf函数的所有输出都是右对齐的,除非在%符号后放置了负号。例如,%-5.2f 会显示5位字符、2位小数位的浮点数并且左对齐

3.1

  • 计算机中只能存储二进制数,即0和1,而在对应的物理硬件上则是高、低电平。
  • 除我们正常使用的十进制数外,计算机还提供了十六进制数和八进制数。
进制基数
二进制0和1
十进制(%d)0-9
八进制(%o)0-7
十六进制(%x)0-9和a-f
  • 1字节(byte)为8位(bit),1位即二进制的1位,它存储0或1。

int型常量的大小为4字节,即32位。

  • 二进制数0100 1100 0011 0001 0101 0110 1111 1110
    最高位0是符号位。
    对应的是2的幂次
  • 十六进制在观察内存时需要频繁使用。
  • 例i的值是7b(十六进制),其十进制值为7×16+11=123,i的值是0x0000007b。
     
    地址显示结果为7b 00 00 00,
    原因是CPU采用了小端方式进行数据存储,因此低位在前、高位在后。

十进制数转换为二进制的方法:
1
小技巧

  • 可在Windows操作系统下选择“开始”→“计算器”,打开“计算器”。
  • 选择菜单项“查看”→“程序员”可以得到对应进制的转换结果。

3.2

  • 数组名作为实参传递给子函数是,是弱化为指针的。

4.1

  • C语言通过scanf函数读取键盘输入,键盘输入又称为标准输入。
  • 当scanf函数读取标准输入时,如果没有输入任何内容,那么scanf函数会被阻塞。

4.2

  • 为了避免字符型数据读取时,并不会忽略空格和’\n’(回车符)。
  • 如下,编写时,在%d与%c之间加入一个空格。
;