第二章 类型、运算符与表达式
2.1 变量名
规则:变量名由下划线 + 字母 + 数字组成;第一个必须是字母;大小写区别;不能与关键字相同
通用:
1. 变量名小写,符号常量名大写(c语言);
2. 望文知意,直观可拼读,最好使用英文
3. 长度符合“min-length && max-information”
4. 命名尽量与所采用的操作系统或开发工具风格一致
5. 不要出现仅仅依靠大小写区分的标识符
6. 最好不要出现标识符完全一样的局部变量或者全局变量
7. 变量名字:“名词”或者“形容词+名词” eg:oldValue
8. 函数的名字:“动词”或者“动词+名词”eg:DrawBox
9. 用正确的反义词命名具有互斥意义的变量 eg:int minValue; int maxValue;
10. 尽量避免名字中出现数字编号
11. 类名和函数名大写字母开头的单词组合 eg:class Node; void SetValue(int value);
12. 变量和参数用小写字母开头的单词组合 eg:int drawModel;
13. 常量全大写,下划线分割单词 eg:#define MAX_SIZE 100
14. 静态变量加前缀s_ static eg: static int s_initValue;
15. 全局变量加前缀 g_ global eg: int g_numPeople;
16. 类的数据成员加前缀m_ member eg: int m_width;
2.2 数据类型和长度
c语言的几种基本数据类型:
u char 字符型,一个字节,存放本地字符集中的一个字符
u int 整型,机器中整数的最自然长度
u float 单精度浮点型
u double 双精度浮点型
在类型前面加限定符,short 与long
short int si;
long int li;
习惯上省略int,直接 short s;
short 通常16位,long通常32位,int可以为16位或者32位;
限定符signed和unsigned限定char类型或任何整型,unsigned类型总是正值或者0,遵守算术模2n 定律(n是占用的位数);
如果char 占用8位,则unsigned char取值范围0到255(0 ~ 28-1),sign char取值范围-128到127(-27 ~ 27-1)
long double 表示高精度浮点数,同整型一样,长度取决于具体机器
2.3 常量
1234 -- int类型
123456789L -- long类型,后面添加L或者l
如果一个整数太大无法用int类型时候,也被当作long
无符号常量 -- u或者U结尾 12U
ul或者UL表示unsigned long类型
123.4 或者1e-2 -- 浮点数
无后缀也就是默认为double类型,123.4f表示float类型
整型八进制 -- 前缀0 eg:045
整型十六进制 -- 前缀0x或者0X eg:0x1f
一个字符通常是一个整数,单引号括住字符,eg:’A’ ,值对应于ASCII值
转义字符:’\n’表示换行
‘\ooo’ ooo为1~3到八进制数字
‘\xhh’ hh为一个或者多个十六进制数字
‘\0’表示值为0的字符,空字符null
常量表达式仅仅只包含常量的表达式,编译时候求值
#define MAXLINE 1000
char line[MAXLINE+1]
字符串常量:字符串字面值,双引号括起来
“ I am a string”
“” // 空字符串
字符串常量 == 字符数组,字符串内部表示使用了一个空字符’\n’作为串的结尾。因此,存储字符串的物理存储单元数比在双引号中的字符多一个字符数,标准库strlen(s)返回字符串s的长度,不包括末尾的\0空字符
‘x’ 和”x” 是不同的:前者是一个整数,ASCII值;后者是一个字符+一个结束符\0的字符数组。
枚举常量:另一种类型的常量,枚举是一个常量整型值的列表
eg:enum boolean {NO, YES} ;//无显式说明情况下,第一个枚举名值为0,第二个1
enum escapes {BELL = ‘\a’ , BACKSPACE = ‘\b’ };
enum months {JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT,NOV, DEC};
2.4 声明
变量:先声明后使用,声明 -- 指定一种变量类型
eg:int lower, upper, step;
在声明中同时对变量进行初始化;eg:int i = 0;
如果变量不是auto则只能进行一次初始化操作;初始化表达式必须为常量表达式
默认下,外部变量和静态变量被初始化为0;未经显式初始化的自动变量为未定义
任何变量的声明都可以const限定符修饰。修饰的变量值不能改变。const修饰的数组所有元素的值不能被修改。
eg:const double e = 2.718;
const char msg[] = “warning”;
配合数组参数使用,表明函数不能修改数组元素的值
eg:int strlen(const char[]);
2.5 算术运算符
二元:+ - * /(整型会截断小数部分) %(取模、取余数,不能用在浮点数)
2.6 关系、逻辑运算符
> >= < <= 优先级相同,仅次于相等性运算符
== !=
关系的优先级比算术低 i < lim-1 等价于 i <(lim-1)
逻辑:&& 和|| 具有短路特点,从左到右求值,&&比||优先级高,两个都比关系运算符和相等运算符低
关系表达式或逻辑表达式中,如果关系为真则表达式结果1,若假结果0
逻辑运算符!的作用的将非0的操作数转为0,将0转为1
if(! valid) === if(valid == 0)
2.7 类型转换
一般来说,自动转换是把比较窄的数转换为比较宽的数。并且不丢失信息的转换。
eg:f+i 将整型变量i的值自动转换成float
//eg: 将数字字符数组转化为整型
int atoi(char s[]) { int i, num = 0; for(i=0;s[i] >= '0' && s[i] <= '9';i++) { num = num * 10 + (s[i] - '0'); } return num; }
//大写字母转成小写
int lower(int c) { if(c >= 'A' && c <= 'Z') return c + ('a' - 'A'); else return c; }
注意:标准头文件<ctype.h>中定义了一组与字符集无关的测试和转换函数。
eg:判断是否为数字isdigit() 与 c >= ‘0’ && c <= ‘9’
c保证了机器的标准打印字符集中的字符不会是负值,因此表达式中的字符总是正的。
如果没有unsigned类型操作数,按照以下规则:
n 如果一个是long double 则另一个转为long double
n 如果一个是double,则另一个转为double
n 如果一个是float,则另一个转为float
n 将char与short转为int
n 如果其中一个为long,则另一个转为long
使用float为了节省空间或者节省时间,表达式中的float类型的操作数不会自动转为double。
当表达式中有unsigned类型,带符号与无符号之间的比较运算不一样,取决于机器整数类型的大小。
字符类型转化为int
把较长的整数类型转为较短或者char时候,超出的高位舍弃
函数调用:参数传递给函数时候,char与short转为int,float转为double,所以调用函数的参数类型为char或者float时候,也把函数参数声明为int和double
强类型转换进行显式转换:(类型名)表达式,只是生成一个指定类型n的值,n本身的值并不改变( sqrt((double) n ) )
2.8 自增运算符与自减运算符
++:变量+1
--:变量-1
++n:先将n+1,然后再使用n的值
n++:先使用n的值,再n+1
两个运算符只能作用于变量。
eg:删除字符串s中出现的所有c字符
void squeeze(char s[], int c) { int i, j; for(i = j = 0;s[i] != '\0';i++) { if(s[i] != c) s[j++] = s[i]; } s[j] = '\0'; }
eg:字符串拼接strcat(char s[], char t[]) 将t字符串拼接到s的尾部
void strcat(char s[], char t[]) { int i,j; i = j =0; while(s[i] != '\0') //find end of s { i++; } while((s[i++] = t[j++]) != '\0') //copy t { ; } }
2.9 按位运算符
c语言提供6个位操作运算符,只能作用于整型,即带符号或无符号的char,short,int,long。
& 按位与and
| 按位或or
^ 按位异或xor
<< 左移
>> 右移
~ 按位求反
&:屏蔽某些二进制位 置0
| :置1
^:相同为0 相异为1
a << b :将a的值左移b个单位,b为整型非负,右边空出的用0填补,等价于对做操作数乘以2的b次方
a >> b : 将a的值右移b个单位
如果a是unsigned,左边空出的部分用0填补
如果a是signed, 算术移位:左边空出的部分用符号位填补,逻辑移位则用0填补
eg: 把x的最后六位设置为0 x = x & ~077
2.10 赋值运算符与表达式
i = i + 2 等价于 i += 2;
op= : + - * / % << >> & ^ |
注意:x *= y+1 ; === x = x * (y+1);
赋值表达式的类型是它的左操作数的类型,值是赋值操作完成后的值
eg: 统计参数值为1的二进制位的个数:比较值最后的那位是否为1,然后右移数
int bitcount(int i) { int count = 0; while(i) { if(i & 1) count++; i = i >> 1; } return count; }
eg: 统计参数值为1的二进制位的个数:i & (i-1)结果为去掉i的最后那个1
int bitcount2(int i) { int count = 0; while(i) { count++; i = i & (i-1); } return count; }
2.11 条件表达式
expr1 ? expr2 : expr3
//首先计算expr1,若值不等于0的(为真),计算expr2值,并把该值作为条件表达式的值;否则(为假),计算expr3的值,把值作为表达式的值。
eg:z = (a > b) ? a :b; // z =max(a,b);
注意:如果f是浮点类型,n为int
那么 (n >0) ? f : n 是浮点类型,与n的值是否为正无关。
2.12 运算符优先级和求值次序
同行中优先级相同,各行从上往下逐行降低。