第3章 数据和C
3.1 变量与常量数据
- 常量(constant)
- 数据类型在程序使用前已经预先设定好,整个程序运行过程不会改变。
- 变量(variable)
-
数据类型在程序运行期间可能改变或数据内容会修改、赋值。
-
变量的声明和使用:
(1)计算机记住变量地址-
变量:用来标识一块内存区域,这块区域的值一般是可以更改的,所以称之为“变”。
-
变量名:是一个标识符,用来指代一块内存区域。变量名本身不占空间。
-
计算机从机器代码中,不会出现变量名。也就是计算机是不需要记住变量名的;变量名只是用来给程序员(人类)来看的,便于人类理解。
-
声明一个变量的时候,内存就确定好了变量的地址、存储空间大小。那么知道了变量的地址其实就是知道变量名,变量名只是变量地址的符号化。编译器转换成机器代码时,汇编语言中没有变量名,计算机只认识地址和指令,变量名其实就是一串串的地址,只是符号化给我们人类看。
(2)根据变量的数据类型,创造存储空间
(3)变量的初值是任意的,等待赋值后修改变量的值,例如:
int num; num = 10;
(4)变量的声明,例如:
int num; char name; float x;
-
-
变量的命名方法
- 下划线命名法:使用下划线分割多个单词,好处是字母全部小写,看起来简洁,例如,
int books_num = 100; //书本数量 void add_book(...); //增加书本的函数 void print_books_name(...); //显示图书名称的函数
- 小驼峰命名法:第一个单词首字母小写,后面的每个单词的首字母大写。例如,
int booksNum = 100; //书本数量 void addBook(...); //增加书本的函数 void printBooksName(...); //显示图书名称的函数
- 大驼峰命名法:帕斯卡命名法(Pascal命名法),每个单词首字母大写。例如,
int BooksNum = 100; //书本数量 void AddBook(...); //增加书本的函数 void PrintBooksName(...); //显示图书名称的函数
- 匈牙利命名法:匈牙利命名法通过在变量名前面加上相应的小写字母的符号标识作为前缀,标识出变量的作用域、类型等。这些符号可以多个同时使用,顺序是先m_(成员变量)、再指针、再简单数据类型、再其它。这样做的好处在于能增加程序的可读性,便于对程序的理解和维护。例如,
int iBooksNum = 100; /*iBooksNum中,i表示整型int缩写*/ static char *s_psBookName; /*s_psBookName中s_表示静态变量,p表示指针,s表示字符串*/
3.2 数据类型关键字
-
c数据类型的关键字种类
int long short unsigned char float double
signed void
_Bool _Complex _Imaginary -
数据的存储单元
- 位:bit,存储0、1。虽然1位存储的信息量有限,位是计算机内存的基本构建块。
- 字节:byte,1个byte是8bits。
- 字:word,设计计算机时给定的自然存储单元。随着计算机字长越大,数据转移越快,允许访问的内存更多。
- 不同的数据类型所需要的存储空间是根据当前计算机的系统所决定的,根据内存的位数决定。
-
整数和浮点数
-
整数
(1)数据类型:int long short unsigned signed(2)存储方式:整型数据是按数据类型所占空间的位数以二进制形式存储的,负数以补码形式存储。
补码:负数的原值-取反-+1所得的数即补码形式,取反过程中符号位不变。
-
浮点数
(1)数据类型:float double long double
(2)表示方法:-
小数表示方法:3.14、7.00
-
指数表示方法:3.16E7、2e-8
-
16进制表示方法:0xa.1fp10,0x表示16进制,a表示10进制10,.1f表示1/16+15/256,p10表示2^10(1024)。0xa.1fp10 = (10+1/16+15/256)×1024(十进制10364.0)。
(3)存储方式:
+ .314159 1 符号 小数部分 指数部分 -
3.3 基本数据类型
- 基本整型int
- 存储空间:int一般占用一个机器字长,目前32位的系统,int占据4个字节32位。
- int是有符号的整数,可以表示正、负。
- 数据格式:
- 八进制:数据以0开头,例如011,是十进制9。
- 十六进制:以0x、0X开头,例如0x11,是十进制17。
- 显示八进制:%o,显示前缀:%#o
- 显示十六进制:%x、%X,显示前缀:%#x、%#X
- 其他整型
- short,有符号的整数,占用存储空间可能比int少
- long,有符号的整数,占用存储空间可能比int多
- long long,有符号的整数,至少占用64位,占用的存储空间可能比long多
- unsigned int,无符号的整数
- signed int
- 整型数据的显示:%d、%u、%ld、%lld、%lu对应int、short、long、long long、unsigned long……
- 整型数据常量后缀表示具体的数据类型:65u、65、65L、65UL、65LL、65ULL……
- 整型数据的取值范围和数据溢出
- 取值范围:short、int、long、long long等范围,主要还是根据计算机的硬件决定,硬件是8位、16位、32位、64位系统决定了数据的存储空间,所谓的硬件的位数,是指计算机默认的机器字长。
- 字长的判断:*sizeof()*可以求出当前系统的机器字长
- 数据溢出(溢出后的数值计算):
- 有符号位的数据溢出:2n-N或者2n+N,n指机器字长的位数,N指溢出的整型数据
- 无符号位的数据溢出:2^n-N
- C99 标准只规定了数据类型的最小长度,使用多种数据类型的目的是为了节约存储空间
- 字符型char
- 存储空间:char占用1个字节长度
- char类型存储的是整数,而不是字符,计算机使用数字编码来处理字符,用特定的整数表示特定的字符
- 常用的编码方式是ASCII编码
- 字符常量
- 字符常量必须用单引号
''
括起来,例如'A''#'
- 因为字符是以数值形式存储,可以用数值对字符变量赋值,例如:
char grade = 65; //语法正确,但编程风格并不好,容易误解
- C语言将字符常量视为int类型而非char类型,假设int占32位,char占8位,将int赋值给char时,只有最后8位有效。例如:
- 字符常量必须用单引号
char grade = 'FATE';
/* 字符常量占32位,是int类型,因此可以定义'FATE'的字符常量,但char只占8位,赋值给char时,只有最后8位有效 */
- 转义字符 :要以\开始,例如\n、\b、\t、\r等等
- 格式输入输出:%c
-
_Bool 类型 :C99标准添加,表示布尔值:逻辑值ture(1)、false(0),占1位存储空间
-
可移植类型:stdint.h、inttypes.h
- stdint.h:精确宽度整数类型(exact-width integar type),使用int32_t表示32位有符号整型,在int为16、long为32位的系统中,则会将int32_t作为long的别名处理。最小宽度类型(minimum width type),使用int_least8_t表示可容纳8位有符号整数类型宽度最小的类型。最快最小宽度类型(fastst minimum width type),使用int_fast8_t表示8位有符号位运算最快的整数类型。
- inttypes.h:printf函数输出时,要求与相应的转换相匹配,例如使用了int32_t,有的对应%d,有的对应%ld,那么使用PRId32字符串宏,用"PRId32"替代d
- 浮点型数据类型float、double、long double
- 有效数字:float至少表示6位有效数字,double至少13位有效数字,long double的精度比double精度高。
- 浮点型常量:使用后缀可覆盖默认数据类型,例如4.32f/4.32F表示float类型,4.32L表示long double类型。
- 格式输入输出:%f、%e、%Lf、%Le、%La
- 数据溢出:上溢、下溢
- 十进制与二进制的浮点型数据转换:详见浮点型数据存储、维基百科
- 复数和虚数
- 复数类型:float_Complex、double_Complex、long double_Complex,例如
float_Complex x;
x包含两个float类型的值,分别是复数x的实部和虚部 - 虚数类型:float_Imaginary、dobule_Imaginary、long double_Imaginary
3.4 使用数据类型
如果数据与声明的类型不一致,会导致数据丢失,例如,
int cost = 12.99; //double类型给int变量,会将小数部分直接丢弃
float pi = 3.1415926536; //double类型给float变量,会将小数的精度损失,只保留前6位精度
3.5 参数和陷阱
- printf()函数和scanf()函数的参数个数是可变的,双引号
""
就代表1个参数。 - printf()函数的作用是将内容输出发送到输出缓冲区,当输出缓冲区满、遇到换行字符、需要输入的时候,函数会将缓冲区的内容发送到屏幕,称为刷新缓冲区。
- scanf()函数是从输入缓冲区逐个读取数据、字符等信息,与scanf()的参数对比,看是否符合条件。键盘等输入设备输入的信息,实际上是存入到输入缓冲区的。
3.6 复习题
a.long long
b. float、int
c. char
d. int
-
数据较大,超过了int的范围
-
stdint.h、inttypes.h,理由是不同的系统中原有的数据类型可能代表不同的含义,特别反映在位数上的不同。
-
删格、整数1066、99.44,16进制0xAA,小数2.0×10^30
-
#include、int main()、float g,h; g = 1e21
-
int,%d int,%x, char,%c float %f int %o float %f int %ld float %lf double %p
-
int %o float %Lf char,%c int,%d char,%c float,%Lf int,%x int,%d
-
%d %ld %f %c
-
ch = '\n';ch = 10;ch = 012;ch = 0x0A;
void main(void) /*this program is perfect*/
{
int cows,legs;
printf("How many cow legs did you count?\n");
scanf_s("%d",&legs);
cows = legs/4;
printf("That implies there are %d cows.\n",cows);
return 0;
}