变量和常量是程序处理的两种基本数据对象。声明语句说明变量的名字及类型,也可以指定变量的初值。运算符指定将要进行的操作。表达式则把变量与常量组合起来生成新的值。对象的类型决定该对象可取值的集合以及可以对该对象执行的操作。本章将详细讲述这些内容。
ANSI标准对语言的基本类型与表达式做了许多小的修改与增补。所有整型都包括signed(带符号)和unsigned(无符号)两种形式,且可以表示无符号常量与十六进制字符常量。浮点运算可以以单精度进行,还可以使用更高精度的long double类型。字符串常量可以在编译时连接。ANSI C还支持枚举类型,该语言特性经过了长期的发展才形成。对象可以声明为const(常量)类型,表明其值不能修改。该标准还对算术类型之间的自动强制转换规则进行了扩充,以适合于更多的数据类型。
2.1 变量名
C语言变量名
在C语言中,变量名的命名规则如下:
变量名必须以字母或下划线(_)开头,后面可以跟任意数量的字母、数字或下划线。
变量名不能使用C语言的关键字,如int、for、if等。
变量名应具有描述性,便于理解。
变量名区分大小写,如age和Age是不同的变量。
2.2 数据类型及长度
整型数据类型:
int:通常为4个字节,但在64位系统上可能为8字节。
short:通常为2个字节。
long:通常为4个字节,但在64位系统上可能为8字节。
long long:通常为8个字节。
字符型数据类型:
char:通常为1个字节,用于存储单个字符。
浮点型数据类型:
float:通常为4个字节,用于单精度浮点数。
double:通常为8个字节,用于双精度浮点数。
无符号整型数据类型:
unsigned int、unsigned char、unsigned short、unsigned long、unsigned long long:这些类型的存储单元长度与对应的有符号整型相同。
布尔类型:
在C99之前,布尔值通常使用整数0表示假,非零值表示真。C99引入了专门的布尔类型_Bool,需要包含头文件<stdbool.h>,其取值可以是true或false。
数据类型的长度和存储单元:
数据类型的长度和存储单元大小取决于编译器的实现和系统的位数。例如,在32位系统上,int通常是4字节,而在64位系统上可能是8字节。
使用sizeof操作符可以测量不同类型数据在内存中的占用长度。例如,sizeof(int)将返回int类型在内存中的字节数。
使用场景和示例:
整型数据类型用于存储整数。
字符型数据类型用于存储单个字符。
浮点型数据类型用于存储小数。
无符号整型数据类型用于存储非负整数。
布尔类型用于表示真或假。
2.3 常量
在C语言中,常量是一个固定值,在程序执行过程中不可以改变的。常量可以是任何基本数据类型,比如整数,浮点数,字符等。
常量的定义主要有两种方式:
(1)直接在代码中定义常量,只需要直接给出常量的值即可。例如:
(2)使用#define预处理命令定义
#define预处理命令可以用来定义常量,它的基本语法如下:
其中,identifier是常量名,value是常量的值。例如:
在上述代码中,我们使用#define预处理命令定义了一个名为MAX的常量,它的值为100。在main函数中,我们使用MAX定义了一个数组的大小,并且使用printf函数输出了MAX的值。
注意:#define定义的常量在预处理阶段就已经完成了替换,因此不能在代码中改变其值。
此外,C语言还提供了一种新的常量定义方式,即使用const关键字定义常量。例如:
在上述代码中,我们使用const关键字定义了一个名为num的常量,它的值为10。const关键字定义的常量可以在代码中被改变,但必须在定义时初始化。
注意:使用const定义的常量可以被修改,只是修改的方式需要遵守C语言的规则,通常情况下,我们应该尽量遵循C语言的规范,不在代码中修改常量的值。
2.4 声明
在C语言中,声明是一个非常重要的概念,它是指在程序中创建变量或者函数的方式。声明可以包括数据类型的声明,也可以包括标识符的声明。
数据类型的声明:
函数的声明:
函数的声明通常在函数的定义前,以便在程序的其他部分调用该函数。函数的声明也可以在头文件中,然后被多个源文件包含。
外部变量的声明:
如果在一个源文件中使用另一个源文件定义的全局变量,需要在使用前声明该变量。
类型定义:
类型定义允许用户定义新的数据类型名称。
数组的声明:
结构体的声明:
枚举的声明:
联合的声明:
2.5 运算符优先级与求值次序
在C语言中,运算符的优先级决定了运算符执行的优先顺序,而求值次序仅在涉及到多个运算符的复合表达式中才有意义,它指定了各子表达式的执行顺序。
运算符的优先级:
C语言中的运算符优先级可以概括为以下几种:
小括号:如果表达式中有小括号,则先解决小括号内的内容。
一元运算符:如!、~、++、--、*、&等。
算术运算符:先乘除后加减,同级运算符从左向右结合。
关系运算符:如>、<、>=、<=。
相等运算符:如==、!=。
位运算符:如<<、>>、&、^、|。
逻辑运算符:如&&、||。
条件运算符:? :。
赋值运算符:如=、+=、-=、*=、/=、%=、>>=、<<=、&=, ^=。
逗号运算符:如果有多个表达式,则从左向右进行。
表2-1总结了所有运算符的优先级与结合性,同一行中的各运算符具有相同的优先级,各行间从上往下优先级逐行降低。例如,*、/与$三者具有相同的优先级,它们的优先级都比二元运算符+、-的高。运算符()表示函数调用。运算符->和.用于访问结构成员。
注意,位运算符&、^与!的优先级比运算符==与!=的低。在任何一种编程语言中,如果代码的执行结果与求值顺序相关,则都是不好的程序设计风格。很自然,有必要了解哪些问题需要避免,但是,如果不知道这些问题在各种机器上是如何解决的,就最好不要尝试运用某种特殊的实现方式。
2.6 类型转换
在C语言中,类型转换主要分为两类:隐式转换和显式转换。
隐式转换:这种转换是编译器自动进行的,不需要用户干预。隐式转换规则比较简单,主要包括以下几种情况:
(1)整数提升:在赋值表达式中,小于int的整数类型(如char, short)会自动提升到int类型。
(2)浮点数提升:在赋值表达式中,float类型会自动提升到double类型。
(3)算术转换:在赋值表达式中,低级别的算术类型(如char, short)会先转换到int类型,如果int类型的大小不足以容纳结果,则直接转换到unsigned int类型。
显式转换:这种转换是由程序员显式指定的,可以使用以下几种方式进行显式转换:
类型转换函数,如(double)a将a转换为double类型。
使用函数式的类型转换,如(double)a。
使用if else进行类型转换,适用于有限的几种类型。
使用共用体(union)进行类型转换,适用于类型大小一样的转换。
示例代码:
2.7 条件表达式
条件表达式由条件运算符构成,并常用条件表达式构成一个赋值语句。条件表达式内可以嵌套,通常用于程序开发中,特别是在需要基于条件选择不同执行路径时使用。
条件表达式的格式和用法
条件表达式的格式为:表达式1 ? 表达式2 : 表达式3。首先求解表达式1,如果其值为真(非0),则将表达式2的值作为整个表达式的值;否则,将表达式3的值作为整个表达式的值。例如,max = (a > b) ? a : b 将a和b中较大的值赋给max。
与if-else结构的对比
条件表达式和if-else结构都可以用于根据条件选择执行不同的代码块,但它们在使用上有一些区别:
凡是可以使用条件运算符的,都可以改写为if-else结构,反之不成立。
条件表达式的效率通常高于if-else结构,因此在可能的情况下优先使用条件表达式。
示例代码
以下是一个使用条件表达式的示例,用于获取三个数中的最大值: