1

Summary

0)对于所操作数据的具体类型,一定要十分明确!

1)C语言对数据的分类:整数类型、浮点数类型、字符类型(普通字符型、无回显字符型)。各个类型的根本区别在于,所占用的内存大小不同。

2)类型所占的字节数是由编译器决定的,32位和64位的主要区别在于:指针所占字节数分别为4和8;long所占字节数分别为4和8。

3)区分初始化和赋值的关键点:赋值操作是在创建变量时候进行的,还是在创建变量之后进行的。

4) 当遇到以下2种情况时:

  • 当前的值已经溢出了(超过了当前类型所能表示的范围里的数)
  • 大类型向小类型转换
    对于溢出以后的值
    正值:溢出的值 - 当前类型能表示的个数 = 实际值
    负值:溢出的值 + 当前类型能表示的个数 = 实际值

5)sizeof用于获得类型或者变量所占用的内存字节数,sizeof作用于数组名时,可以得到数组占用的内存。

6)C语言中字面量的默认类型:如2为int,0.2为double,'2'为char

1、数据类型与变量

1.1 C语言中的数据类型

初学阶段应掌握的类型:
整形:

  • int:占用4个字节(32位(bit)),表示范围:-2147483648~2147483647(-231 ~ 231-1)。
  • short:占用2个字节(16位(bit)),表示范围:-32678 ~ 32767。

浮点型:

  • float:占用4个字节(32位(bit)),表示范围:-3.4 x 1038 ~ 3.4 x 1038
  • double:占用8个字节(64位(bit)),表示范围:-1.7 x 10-308 ~ 3.4 x 10308

字符型:

  • char:占用1个字节内存(8位(bit)),表示范围:-128~127。字符数据使用单引号括起来。包括普通字符(英文字符类型,如'D','t');无回显字符类型(无回显字符必须以反斜杠'\'开头,是一种打印后在屏幕上看不到的字符,如换行符'\n',制表符'\t',这是一个字符);字符类型实际也是种整型

各个数据类型的根本区别在于,所表示的内存大小不同。

1.2 C语言中变量的命名规则

  • 字母(a-z, A-Z)、数字(0-9)、下划线(_)构成的字符序列
  • 第一个字符必须为字符或者下划线(不能为数字)
  • 大小写敏感(如name和Name是两个不同的变量名字)

// 小测试:以下哪些命名是合法的?()
A.WORD        B.-abc        C.2c    D._1
E.m_test    F.a@b        G.c3    H._

// A、D、E、G、H合法

变量命名的规范:
1)见名知义:变量命名一定要一眼能看出这个变量的用途
2)便于阅读:可以遵循一些规范,如“驼峰规范”,方便自己和他人阅读、维护代码。

1.3 C语言中变量的定义

C语言中创建变量的语法:type name;

如下:
int n1;
double n2;
short n3;

初始化:在创建变量的同时,给变量一个值。
赋值:在创建变量之后,改变变量的值。

int n1;            // 定义变量,名为n1,类型为int
double hello;      // 定义变量,名为hello,类型为double

int n2 = 2;        // 定义变量,名为n2,类型为int,并初始化为2

n1 = 1;            // 赋值操作,改变n1的值,使其表示1

2、深入数据类型与变量

2.1 程序中数值的类型

C语言是类型严格的语言,字面量也有类型,使用字面量时也需要考虑字面量的类型。字面量的类型包括默认类型和指定类型,如:

  • 默认类型:2为int,0.2为double,'c'为char
  • 指定类型:0.2f为float(后缀f表示float)

每种类型都有自己的容量(所占内存的大小),如果将大类型的值赛道小类型的容器内,可能放不进,会溢出。

大类型赋值给小类型时,可能发生溢出:

  • 当数值在小类型范围内 --> 赋值成功
  • 当数值超过小类型的范围 --> 发生溢出

小类型可以安全的赋值给大类型:

  • 浮点型赋值给整形,会发生截断 --> 小数部分丢失
  • 整形赋值给浮点类型 --> 赋值成功
int a = 50000;    // valid:50000是一个字面量,默认类型为int,在int能表示的范围内

short b = 0;    // 0是一个字面量,默认类型为int,int到short类型的转换,可能出问题。
                // 实际上0在b能表示的范围内,所以能正常赋值

b = a;            // oops!赋值操作,改变b的值为int类型的50000,超过了b能表示的范围,坏了

// 输出:b = -15536。为何是该值,见summary

2.2 类型转换

C语言中不同类型的变量之间(变量与字面量之间)进行赋值或运算时,会发生类型转换。类型转换不改变原变量的值,仅仅是被赋值的变量的值发生改变,并且可能会不正常。

开发小知识:

  • 开发环境(编译软件)由编辑器和编译器组成
    • 编辑器:负责程序的编写工作(字处理软件)
    • 编译器:负责程序的编译工作(文本转为二进制)
  • C语言编译器检查类型的同时,可能做默认转换
    • short s = 2; // 字面量2,类型为int,被转换为short
    • double d = 2; // 字面量2,类型为int,被转换为double

默认类型转换:编译器知道字面量2的类型是int,但也明确的知道初始化操作可以成功(因为2在short可以表示的范围内),因此编译器就会悄悄的将2的int转换为short。
强制类型转换:也叫强制类型转换。规则:type name = (type)var;

int i = 40000;
short b = (short)i;

printf("i = %d\n", i);  // i = 40000
printf("b = %d\n", b);  // b = -25536

以上代码也验证了,类型转换不会改变原来变量的值,只是改变被赋值变量的值,且可能会发生异常(如b期望是40000,但实际输出是-25536,原因见summary4))。

3、再论数据类型

3.1 如果值超过了类型所能表示的最大范围该怎么办

代码见2.2。40000超过了short能表示的范围,这时候表示的值是个奇怪的值。结论如下:

*当遇到以下2种情况时:*
1)当前的值已经溢出了(超过了当前类型所能表示的范围里的数)
2)大类型向小类型转换
对于溢出以后的值
正值:溢出的值 - 当前类型能表示的个数 = 实际值
负值:溢出的值 - 当前类型能表示的个数 = 实际值

代码分析:

short b = 40000;    // output: -25536

// 40000是溢出后的值(正值);short类型占用内存16bit,能表示2^16个数;
// 实际值 = 40000 - 2^16 = 40000 - 65536 == -25536

unsigned short s = 0;
s = s - 1;            // output: 65535
// -1是溢出后的值(负值);short类型占用内存16bit,能表示2^16个数;
// 实际值 = -1 + 65536 = 65535

最后:程序运行时如果发生了越界:

  • 大于类型最大值,则:运行结果回转到最小值附近
  • 小于类型最小值,则:运行结果回转到最大值附近

3.2 sizeof关键字

sizeof用于获取类型或者变量所占用的内存大小(字节)
用法:
sizeof(type)
sizeof(variable)
sizeof variable // 此种方式并不为工程中常用

int var = 1;

printf("%d\n", sizeof(var)); // 4
printf("%d\n", sizeof(int)); // 4
printf("%d\n", sizeof var ); // 4

3.3 补充知识

1)整型的扩展知识:
signed和unsigned可以与char、short、int组合使用

常规写法完整写法表示的数据范围
charsigned char-128~127
unsigned charunsigned char0~255
shortsigned short-32768~32767
unsigned shortunsigned short0~65535
intsigned int-2147483648~2147483647
unsigned intunsigned int0~4294967295

2)对于打印输出,不同的类型值,要具体对应使用不同的格式化字符

类型对应的格式化字符占用内存
int%d4
unsigned int%u4,(有无符号不影响占用的内存)
short%d2
char%c, %d1
long%ld4 / 8, 分别对应32位和64位编译器
long long%lld8
float%f4
double%f8

如果使用了不匹配的格式化字符,输出则可能有问题:

// eg.1
unsigned int u = 2147483648;
printf("u = %d\n", u);  // -2147483648

printf("u = %u\n", u);  // 2147483648

//eg.2
unsigned char c = 128;
printf("c = %d\n", c);  // 128

例1中,为什么2147483648在unsigned int表示的范围内,第一次输出还是不对?
原因在于,%d格式化字符是针对有符号整型的,所以此时将u看做一个int,应用summary4)的计算方法,确实输出了-2147483648。如果按照正确的输出方式%u,则输出的是期望值2147483648。

例2中,unsigned char c的值是128,也是以%d的方式进行打印输出,此时128超过了signed char能表示的范围,为什么不像例1中打印出错呢?
原因在于,128这个值太小了,如果小于signed int能表示的最大值(2147483647),以%d方式打印就不会出错;如果大于了2147483647,那么%d打印就会出错了。

所以,数据什么样的类型,就严格用对应的格式化字符去匹配

3)左值和右值
左值:可以出现在赋值符号左边的值,如:变量
右值:出现在赋值符号右边的值,如:变量、字面量、计算结果(为右值)

4)数据的表示(简略,见后续C进阶课程)
浮点类型(float&double)对数据的表示是不准确的
整数类型(char,short,int,long)对数据的表示是准确的
浮点类型与整数类型在内存中对数据的表示法完全不同

本文总结自“狄泰软件学院”唐佐林老师《C语言入门课程》。
如有错漏之处,恳请指正。


bryson
169 声望12 粉丝