Ø 变量和常量是程序处理的两种基本数据对象
Ø 声明语句说明变量的名字和类型,也可以指定变量的初值
Ø 对象的类型决定该对象可取值的集合以及可以对该对象执行的操作
Ø 运算符指定将要进行的操作
Ø 表达式把变量与常量组合起来生成新的值
1. 变量
变量的命名与符号常量的命名
Ø 由字母和数字组成的序列,但其第一个字符必须为字母。下划线”_”被看作是字母,通常用于命名较长的变量名,以提高其可读性
Ø 库例程(C语言库函数)的名字通常以下划线开头,因此变量名不要以下划线开头
Ø 变量名使用小写字母,符号常量名全部使用大写字母
交换两个变量的值,不使用第三个变量
Ø 算术算法,一种用
a = a + b;
b = a - b;
a = a - b;
Ø ^(异或)
a = a^b;//只能对int,char..
b = a^b;
a = a^b;
or
Ø a ^= b ^= a;
2. 数据类型及长度
char 字符型 占用一个字节,可以存放本地字符集中的一个字符
int 整型 通常反映了所用机器中整数的最自然长度
float 单精度浮点型
double 双精度浮点型
限定符short与long
Ø 用于限定整型
Ø 遵循: short与int类型至少为16位,long类型至少为32位,并且short类 型不得长于int类型,int类型不得长于long类型
类型限定符signed与unsigned
Ø 用于限定char类型或任何整型
Ø unsigned类型的数总是正值或0,并遵守算数模2n定律,其中n是该类型占用的位数
char对象占用8位,unsigned char类型变量的取值范围为0~255,signed char类型变量的取值范围为-128~127
3. 常量
Ø 浮点数常量中包含一个小数点或一个指数,也可以两者都有。没有后缀的浮点数常量为double类型,后缀f或F表示float类型,后缀l或L则表示long double类型
Ø 整型数除了用十进制表示外,还可以用八进制或十六进制表示。带前缀0的整型常量表示它为八进制形式;前缀为0x或0X,则表示它为十六进制形式
Ø 一个字符常量是一个整数,书写时将一个字符括在单引号中,如’x’。字符在机器字符集中的数值就是字符常量的值。
ANSI C语言中的全部转义字符序列:
\a 7 八进制:\007 十六进制:\x7 响铃符
\b 8 回退符 \v 11 垂直制表符
\f 12 换页符 \\ 92 反斜杠
\n 10 换行符 \? 63 问号
\r 13 回车符 \’ 27 单引号
\t 9 水平制表符 \” 22 双引号
\ooo ooo代表1~3个八进制数字(0...7)
\xhh hh是一个或多个十六进制数字(0...9, a...f, A...F)
\0 表示值为0的字符,也就是空字符(null)
Ø 常量表达式是仅仅只包含常量的表达式。表达式在编译时求值,而不在运行时求值
#define LEAP 1 /* 闰年 */
int days[31+28+LEAP+31+30+31+30+31+31+30+31+30+31];
Ø 字符串常量是用双引号括起来的0个或多个字符组成的字符序列
“I am a string” 或 “” /*空字符串*/
字符串常量就是字符数组。字符串的内部表示使用一个空字符’\0’作为串的结尾,因此,存储字符串的物理存储单元数比括在双引号中的字符数多一个
C语言对字符串的长度没有限制,但程序必须扫描完整个字符串后才能确定字符串的长度
标准库函数strlen(s)可以返回字符串参数s的长度,但长度不包括末尾的’\0’
int strlen(char s[])
{
int i = 0;
while (s[i] != ‘\0’)
++i;
return i;
}
Ø 字符常量与仅包含一个字符的字符串之间的区别:
‘x’是一个整数,其值是字母x在机器字符集中对应的数值(内部表示值)120
“x”是一个包含一个字符(即字母x)以及一个结束符’\0’的字符数组
Ø 枚举常量:一个常量整型值的列表
enum boolean {NO, YES};
在没有显式说明的情况下,enum类型中第一个枚举名的值为0,第二个为1,第三个为2,以此类推。如果只指定了部分枚举名的值,那么未指定值的枚举名的值将依着最后一个指定值向后递增
enum months {JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC} /*FEB的值为2, MAR的值为3,依此类推 */
相对于#define语句来说,它的常量值可以自动生成
调试程序可以以符号形式打印出枚举变量的值
4. 声明
所有变量都必须先声明后使用
Ø 默认情况下,外部变量与静态变量将被初始化为0。未经显式初始化的局部变量的值为未定义值(即无效值)
Ø 任何变量的声明都可以使用const限定符限定。该限定符指定变量的值不能被修改。
const double e = 2.71828;
对数组而言,const限定符指定数组所有元素的值都不能被修改
const char msg[] = “warning:”;
const限定符也配合数组参数使用,它表明函数不能修改数组元素的值
int strlen (const char[]);
5. 类型转换
Ø 自动转换是把“比较窄的”操作数转换为“比较宽的”操作数,并且不丢失信息的转换。
/* lower函数:把字符c转换为小写形式;只对ASCII字符集有效 */
int lower(int c)
{
if(c >= ‘A’ && c <= ‘Z’)
return c + ‘a’ - ‘A’;
else
return c;
}
Ø 若二元运算符(具有两个操作数的运算符称为二元运算符)的两个操作数具有不同的类型,那么在进行运算之前先要把”较低”的类型提升为”较高”的类型。运算结果为较高的类型。
Ø 赋值时也要进行类型转换。赋值运算符右边的值需要转换为左边变量的类型,左边变量的类型即赋值表达式结果的类型
Ø 在任何表达式中都可以使用一个称为强制类型转换的一元运算符进行显式类型转换.表达式将按照上述转换规则被转换为类型名指定的类型:
(类型名)表达式
int rand(void);
Ø 从srand (seed)中指定的seed开始,返回一个[seed, RAND_MAX)间的随机整数。
Ø RAND_MAX是VC中stdlib.h中宏定义的一个字符常量:
#define RAND_MAX 0x7FFF
根据系统环境的不同,其值最小可为32767,最大可为2147483647
这个常量指出当前rand()函数可以产生的最大随机数为多少。
void srand(unsigned seed);
Ø 参数seed是rand()的种子,用来初始化rand()的起始值。
Ø strand()函数用来给rand()函数提供种子,如果种子相同的话,产生的随机数序列就会相同。
Ø 一般来说,会用srand((int)time(0));这样的调用来提供种子。
其中time(0)返回的是系统的时间(从1970.1.1午夜算起);单位:秒。
这样,只要不在同一秒内,就可产生不同序列的随机数了。
unsigned long int next =1;
int rand (void)
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void srand (unsigned int seed)
{
next = seed;
}
产生范围[minvalue maxvalue]的随机数
srand( (unsigned) time (0) );
double randomValue
= ((double)rand() / RNAD_MAX) * (MaxValue – MinValue + 1) + MinValue ;
6. 自增运算符与自减运算符
自增运算符++使其操作数递增1
自减运算符--使其操作数递减1
表达式n++即是返回 i的值,然后变量 i加 1,返回需要产生一个临时变量类似于
{ int temp = i; i=i+1; return temp; //返回右值 }
表达式++n则为:
{ i=i+1; return &i; //返回左值 }
显然,前增量不需要中间变量,效率更高。
自增与自减运算符只能作用于变量,即(i+j)++是非法的
/* squeeze函数:从字符串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’;
}
每当出现一个不是c的字符时,该函数把它拷贝到数组中下标为j的位置,随后才将j 的值增加1,以准备处理下一个字符
/* strcat函数:将字符串t连接到字符串s的尾部;s必须有足够大的空间 */
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != ‘\0’) //判断是否为字符串s的尾部
i++;
while ((s[i++] = t[j++]) != ‘\0’) //拷贝t
;
}
7. 按位运算符
& 按位与 (AND)
| 按位或 (OR)
^ 按位异或(XOR)
<< 左移
>> 右移
~ 按位求反(一元运算符)
Ø 按位与运算符& 用于屏蔽某些二进制位
n = n & 0177 (0177:001111111)
语句将n中除7个低二进制位外的其他各位均置为0
Ø 按位或运算符| 用于将某些二进制位置为1
x = x | SET_ON
该语句将x中对应于SET_ON中为1的那些二进制位置为1
位运算符&,| 逻辑运算符&&,||
x = 1, y = 2 x & y = 0 x && y = 1
Ø 按位异或运算符^ 当两个操作数的对应位不同时将该位设置为1,否则该位设置为0
Ø 移位运算符<<与>> 用于将运算的左操作数左移与右移,移动的位数则由右操作数指定(右操作数的值必须为非负值)
Ø 左移<<运算符高位左移后溢出舍弃;低位的空位补零
Ø 右移>>运算符低位移出(舍弃),对unsigned类型的无符号值:高位的空位补0。对signed类型的带符号值:高位的空位补符号位,即正数补零,负数补1(算术移位);高位的空位补0(逻辑移位)。
a * b a的b进制形式左移1位
a / b a的b进制形式右移1位
Ø 一元运算符~用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1
/* getbits函数:返回x中从第p位开始的n位 */
假定最右边一位是第0位,n和p都是合理的正值
unsigned getbits(unsigned x, int p, int n)
{
return (x >> (p+1-n)) & ~(~0 << n);
}
Ø x >> (p+1-n)将期望获得的字段移位到字的最右端
Ø ~0的所有位都为1,~0 << n将~0左移n位,并将最右边的n位用0填补,再使用~按位取反,这就建立了最右边n位全为1的屏蔽码
8. 赋值运算符与表达式
大多二元运算符都有一个相应的赋值运算符op=,其中op可以是下面这些运算符之一
+ - * / % << >> & ^ |
Ø 如果expr1和 expr2是表达式,那么
expr1 op = expr2 等价于 expr1 = (expr1) op (expr2)括号必不可少
x *= y + 1 => x = x * ( y + 1)
/* bitcount函数:统计x中值为1的二进制位数 */
int bitcount(unsigned x)
{
int b;
for (b = 0; x != 0; x >>= 1)
if (x & 01)
b++;
return b;
}
Ø 赋值语句具有值,且可以用在表达式中。赋值表达式的类型是它的左操作数的类型,其值是赋值操作完成后的值
while ((c = getchar()) != EOF)
9. 条件表达式
条件表达式(使用三元运算符”?:”)
expr1 ? expr2 : expr3
计算expr1,若其值为真,则计算expr2的值,并以该值作为条件表达式的值。否则 计算expr3的值。expr2与expr3中只能有一个表达式被计算
if (a > b)
z = a;
else z = (a > b) ? a : b; /* z = max(a,b) */
z = b;
Ø 打印一个数组的n个元素,每行打印10个元素,每列之间用一个空格隔开,每行用一个换行符结束(包括最后一行)
for (i = 0; i < n; i++)
{
printf(“%6d%c”, a[i], (i%10 == 9 || i == n-1) ? ‘\n’ : ‘ ’);
}