C语言的运算符:
(1)算术运算符 (+ - * / %) // % 只能对int型数据操作
(2)关系运算符 (> < == >= <= !=)
(3)逻辑运算符 (! && ||)
(4)位运算符 (& | ~ ^ << >>)
(5)赋值运算符 (=及其扩展赋值运算符)
(6)条件运算符 (? :)
(7)逗号运算符 (,)
(8)指针运算符 (* &)
(9)求字节数运算符 (sizeof) //sizeof运算符
(10)强制类型转换运算符 ((类型))
(11)分量运算符 (. ->)
(12)下标运算符 ([])
(13)其他 (如函数调用运算符())
一.算术运算符和算术表达式
1 . 算术运算符: + - * / %
2 .算术表达式:用算术运算符和括号将运算对象(也称操作数)连接起来的、符合C语法规则的式子,称C算术表达式。运算对象包括常量、变量、函数等。
例如,下面是一个合法的C算术表达式:
a*b/c-1.5+’a’
3 .
C语言规定了运算符的优先级和结合性:
在表达式求值时,先按运算符的优先级别高低次序执行。
如果在一个运算对象两侧的运算符的优先级别相同,如a-b+c,则按规定的“结合方向”处理。
二.强制类型转换运算符
可以利用强制类型转换运算符将一个表达式转换成所需类型。
例如: (double)a (int)(x+y) (float)(5%3)
其一般形式为: (类型名)(表达式)
注意,表达式应该用括号括起来。如果写成 :(int)x+y,则只将x转换成整型,然后与y相加。
#include <stdio.h>
void main()
{
float x;
int i;
x=3.6;
i=(int)x;
printf(“x=%f, i=%d\n”, x, i);
}
//结果:
// x = 3.6
// i = 3
三.自增、自减运算符
作用是使变量的值增1或减1,例如:
++i,- -i
i++,i- -
粗略地看,++i 和 i++的作用相当于i=i+1。但++i和i++不同之处在于
++i是先执行i=i+1后,再使用i的值;而i++是先使用i的值后,再执行i=i+1。
int i = 3;
int j;
j = i++;
printf("j = %d\n",j);
printf("i = %d\n",i);
printf("i = %d\n",++i); //先执行+1,再使用
//结果: j = 3
i = 4
i = 5
注意:
(1)自增运算符(++)和自减运算符(–)只能用于变量,而不能用于常量或表达式,如5++或(a+b)++都是不合法的。
(2)++和- -的结合性是“自右至左”。
(3)自增(减)运算符常用于循环语句中,使循环变量自动加1;也用于指针变量,使指针指向下一个地址。
例子:
int i = 3;
printf("%d\n",-i++);
printf("%d\n",-++i);
printf("%d\n", i);
//输出结果:-3 分析: - 和 ++ 运算符优先级相同,结核性是“自右至左”
-5
5
有关表达式使用中的问题说明
(1)C运算符和表达式使用灵活,利用这一点可以巧妙地处理许多在其他语言中难以处理的问题。
但是应当注意:ANSI C并没有具体规定表达式中的子表达式的求值顺序,允许各编译系统自己安排。 (函数参数顺序点:变量值发送变化的位置点)
(2)C语言中有的运算符为一个字符,有的运算符由两个字符组成,在表达式中如何组合呢?
(3)在调用函数时,实参数的求值顺序,C标准并无统一规定。
例1-1:
#include <stdio.h>
int main()
{
int i = 3;
printf("(i++)+(i++)+(i++) = %d\n",(i++)+(i++)+(i++));
printf("i = %d\n",i);
return 0;
}
//在Turb C 中: 12 6 (3+4+5)= 12
//在VC中: 9 6 (3+3+3)= 9
例1-2:
int i = 0;
printf(“%d,%d,%d”,i++,i++,i++);
printf(“%d,%d,%d,%d,%d”, ++i, ++i,i++,++i,i++);
//Linux 2.14内核下
//从右往左算(先把输出的值压栈,再出栈)
//2 1 0
//5 5 2 5 0
//分析: 在Linux下, i++的逻辑和和其他环境一样
// 但是 ++i和i的进栈顺序是最后统一写入
例1-3:
#include <stdio.h>
#define MAN(a,b) a>b?a:b
int main()
{
int a = 2;
int b = 2;
printf("the max is %d\n",MAN(++a,b));
return 0;
}
(A)2 (B)3 (C)4 (D)5
//C
例1-4:
printf(“%d,%d,%d,%d,%d”, i++, ++i,i,i++ ,++i);
//3 4 4 1 4
例2:
#include <stdio.h>
int main()
{
int i = 3;
int j = 2;
printf("%d\n",i+++j);
return 0;
}
//在C语言中规定:让从左到右运算符尽量组成一个数目多的运算符
//所以相当于: i++ + j = 2+3 = 5
例3:
#include <stdio.h>
int main()
{
int i = 3;
//究竟是先从右往左还是从左往右,C语言中没有规定
printf("%d,%d\n",i,i++);
return 0;
}
//在Turb C 中: 4 3 从右往左算
//在VC中: 3 3 从左往右算
四.赋值运算符和赋值表达式
1.
赋值符号“=”就是赋值运算符,它的作用是将一个数据赋给一个变量。
如“a=3”的作用是执行一次赋值操作(或称赋值运算)。把常量3赋给变量a。
也可以将一个表达式的值赋给一个变量。
2.
如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时要进行类型转换。
(1)将浮点型数据(包括单、双精度)赋给整型变量时,舍弃实数的小数部分。
(2)将整型数据赋给单、双精度变量时,数值不变,但以浮点数形式存储到变量中。
(3)将一个double型数据赋给float变量时,截取其前面7位有效数字,存放到float变量的存储单元(32位)中。但应注意数值范围不能溢出。将一个float型数据赋给double变量时,数值不变,有效位数扩展到16位,在内存中以64位存储。
(4)字符型数据赋给整型变量时,由于字符只占1个字节,而整型变量为2个字节,因此将字符数据(8位)放到整型变量低8位中。
(5)将一个int、short、long型数据赋给一个char型变量时,只将其低8位原封不动地送到char型变量(即截断)。
(6)将带符号的整型数据(int型)赋给long型变量时,要进行符号扩展,将整型数的16位送到long型低16位中,如果int型数据为正值(符号位为0),则long型变量的高16位补0;如果int型变量为负值(符号位为1),则long型变量的高16位补1,以保持数值不改变。反之,若将一个long型数据赋给一个int型变量,只将long型数据中低16位原封不动地送到整型变量(即截断)
(7)将unsigned int型数据赋给long int型变量时,不存在符号扩展问题,只需将高位补0即可。
(8)将一个unsigned类型数据赋给一个占字节数相同的整型变量(例如:unsigned int->int,unsigned long->long,unsigned short->short),将unsigned型变量的内容原样送到非unsigned型变量中,但如果数据范围超过相应整数的范围,则会出现数据错误。
(8)将非unsigned型数据赋给长度相同的unsigned型变量,也是原样照赋(连原有的符号位也作为数值一起传送)。
例1:
#include <stdio.h>
int main()
{
int i;
i = 3.12; //舍弃实数的小数部分
printf("%d\n",i);
float f;
double d;
f = i;
d = i;
printf("f = %f\n",f);
printf("d = %lf\n",d);
return 0;
}
//结果: 3
f = 3.000000
d = 3.000000
例2:
#include <stdio.h>
int main()
{
float f;
f = 123456789.0123456;
printf("%f\n",f);
return 0;
//输出结果:123456792.000000
//原因:只保留7为有效位
例3: 字符型数据赋给整型变量
//程序:
#include <stdio.h>
int main()
{
unsigned char c1;
signed char c2;
int i1,i2;
c1 = c2 = '\376'; // 八进制376 对应 二进制 1111 1110
i1 = c1;
i2 = c2;
printf("%d\n",i1); //正数的补码即是它所表示的数的真值
printf("%d\n",i2); //负数的补码的数值部份却不是它所表示的数的真值
return 0;
}
//输出:
254
-2
分析:
1、如果所用系统将字符处理为无符号的量或对unsigned char型变量赋值,则将字符的8位放到整型变量低8位,高8位补零。
如下:
2、如果所用系统将字符处理为带符号的(即signed char),若字符最高位为0,则整型变量高8位补0;若字符最高位为1,则高8位全补1。这称为”符号扩展”,这样做的目的是使数值保持不变。
例4: int、short、long型数据赋给一个char型变量
#include <stdio.h>
int main()
{
int i = 289;
char c = i;
printf("%c\n",c);
printf("%d\n",c);
return 0;
}
//输出结果: !
33
分析:
将一个int、short、long型数据赋给一个char型变量时,只将其低8位原封不动地送到char型变量(即截断)。例如:
(这里的int占2个字节)
例5: unsigned int 赋值给 int
#include <stdio.h>
int main()
{
unsigned int a = 65535;
signed int b;
b = a;
printf("%d",b);
return 0;
}
//int型占2字节的机器中
//在Turbo C 中输出: -1
分析:
有符号数b,在计算机中以补码的形式存储,所以其对应的原码为: 1000000000000001(-1)。
这里就是因为unsigned型变量的内容原样送到非unsigned型变量中,但如果数据范围超过相应整数的范围,则会出现数据错误。
例6: signed int 赋值给 unsigned int
#include <stdio.h>
int main()
{
unsigned int a ;
signed int b = -1;
a = b;
printf("%d",a);
printf("%u",a);
return 0;
}
//int型占2字节的机器中
//在Turbo C 中输出: -1 //%d是将a中的16位以有符号的形式输出,即以补码的形式
65535 //%u是将a中的16位以无符号的形式输出,
分析:
b = -1,在内存中以补码的形式存储,如下。
赋值给a 即 a = 1111 1111 1111 1111
符号扩展和截断总结:
符号位扩展:将一个位数低的数据赋值给位数高的数据 (char型 给 int型 )
目的:保持数值的不变
截断:将一个位数高的数据赋值给位数低的数据 (int型 给 char型)
3 . 复合的赋值运算符
在赋值符“=”之前加上其他运算符,可以构成复合的运算符。例如:
+= -= *= /= %= <<= >>= &= ^= |=
4 . 赋值表达式
由赋值运算符将一个变量和一个表达式连接起来的式子称为“赋值表达式”。它的一般形式为:
<变量> = <表达式>
赋值运算符左侧的标识符称为“左值”(left value)。并不是任何对象都可以作为左值的,变量可以作为左值,而表达式a+b就不能作为左值,常变量也不能作为左值,因为常变量不能被赋值。
出现在赋值运算符右侧的表达式称为“右值”(right value)。
显然左值也可以出现在赋值运算符右侧,因而凡是左值都可以作为右值。
a = b =c =3;
//赋值表达式的结合性是:从右往左,即先对C赋值3。
五.逗号运算符和逗号表达式
C语言提供一种特殊的运算符—逗号运算符。用它将两个表达式连接起来。例如:
3+5, 6+8
称为逗号表达式,又称“顺序求值运算符”。逗号表达式的一般形式为:
表达式1, 表达式2
逗号表达式的求解过程是:先求解表达式1,再求解表达式2。整个逗号表达式的值是表达式2的值。
逗号表达式的优先级最低。
#include <stdio.h>
int main()
{
//int i = 3+5,6+8; 这样申明会出现错误,逗号表达式的优先级最低。
int i = (3+5,6+8);
printf("%d",i);
return 0;
}
//输出结果: 14
#include <stdio.h>
int main()
{
printf("%d",(3+5,6+8));
return 0;
}
//输出结果: 14
例题:
#include <stdio.h>
main()
{
int i=99;
char c;
unsigned int ui;
float f;
long int li;
c=i; //c='c'
ui=i; //ui=99
f=i; //f=99.0
li=i; //li=99
printf("c=%c\n", c);
printf("ui=%u\n", ui);
printf("f=%f\n", f);
printf("li=%ld\n", li);
}
#include <stdio.h>
main()
{
int i;
char c = 'd';
unsigned int ui;
float f;
long int li;
i=c; //100
ui=c; //100
f=c; //100.000000
li=c; //100
printf("i=%d\n", i);
printf("ui=%u\n", ui);
printf("f=%f\n", f);
printf("li=%ld\n", li);
}
#include <stdio.h>
main()
{
int i;
char c ;
unsigned int ui;
float f = 53.65;
long int li;
i=f; //53
c=f; //53
ui=f; //53
li=f; //53
printf("i=%d\n", i);
printf("c=%d\n", c);
printf("ui=%u\n", ui);
printf("li=%ld\n", li);
}
main()
{
int a=12;
printf("a+=a %d\n", a+=a); //a=a+a 24
printf("a-=2 %d\n", a-=2); //a=a-2 22
printf("a*=2+3 %d\n", a*=2+3); //a=a*(2+3)=22*5 110
printf("a/=a+a %d\n", a/=a+a); //a=a/(a+a) 0
int n=5;
printf("a%=(n%=2) %d\n", a%=(n%=2)); //a=a%1 0
printf("a+=a-=a*=a %d\n", a+=a-=a*=a); 0
//复合赋值运算符结合性:从右往左
}