一、操作符分类
1.算术操作符:
(1)+:加
使用规则:可以用于两个整数、浮点数、字符之间进行相加
注意事项:用于相加的两个数可以是不同类型的,如果是两个不同类型对象做加法那么最后的结果的类型会自动转化为较大的类型。特别的对于字符与整型进行运算时,实际参加运算的是字符的ASCII码。
eg:
#include<stdio.h>
#include<stdlib.h>
int main() {
int a = 10;
char b = 'a';
printf("%d", (a + b));
system("pause");
return 0;
}
(2) -:减
使用规则:可以用于两个整数、浮点数、字符之间进行相减
注意事项:用于相减的两个数可以是不同类型的,如果是两个不同类型对象做减法那么最后的结果的类型会自动转化为较大的类型。特别的对于字符与整型进行运算时,实际参加运算的是字符的ASCII码。
(3) *:乘
使用规则:可以用于两个整数、浮点数、字符之间进行相乘
注意事项:用于相乘的两个数可以是不同类型的,如果是两个不同类型对象做乘法那么最后的结果的类型会自动转化为较大的类型。特别的对于字符与整型进行运算时,实际参加运算的是字符的ASCII码``。
eg:
#include<stdio.h>
#include<stdlib.h>
int main() {
int a = 10;
char b = 'a';
printf("%d", (a * b));
system("pause");
return 0;
}
(4)/:除
使用规则: 可以用于两个整数、浮点数、字符之间进行相除
注意事项:用于相除的两个数可以是不同类型的,如果是两个不同类型对象做除法那么最后的结果的类型会自动转化为较大的类型。特别的对于字符与整型进行运算时,实际参加运算的是字符的ASCII码。
(5)%:求模
使用规则:对于参与求模的两个对象要求必须是整型。
2.移位操作符
(1)<<:左移(使用左移操作符相当于是乘2)
使用规则:进行左移的操作数要求必须是整型或者字符型。其实质相当于是对输入的整型或者字符型转化为二进制数,然后对二进制数进行左移。
eg:
int x=4D ===> 0000 0000 0000 0000 0000 0000 0000 0100B(32位)
x<<1 ===>0000 0000 0000 0000 0000 0000 0000 1000B ===>x=8D
(1)>>:右移(使用右移操作符相当于是乘2)
使用规则:进行右移的操作数要求必须是整型或者字符型。其实质相当于是对输入的整型或者字符型转化为二进制数,然后对二进制数进行右移。
eg:
int x=4D ===> 0000 0000 0000 0000 0000 0000 0000 0100B(32位)
x>>1 ===>0000 0000 0000 0000 0000 0000 0000 0010B ===>x=2D
3.位操作符
(1)&:按位与
使用规则:是对二进制数进行按位与,位操作符也要求参与操作的对象必须是整型或字符型。
eg:
#include<stdio.h>
#include<stdlib.h>
int main() {
//int a = 3;
double a = 1.0; (错误)
double b = 2.1; (错误)
a = a & b;
printf("%d", (a));
system("pause");
return 0;
}
eg:
int x=3 ==>0000 0000 0000 0000 0000 0000 0000 0011
int y=5 ==>0000 0000 0000 0000 0000 0000 0000 0101
x&y=0000 0000 0000 0000 0000 0000 0000 0000 0001 ==>1
4.赋值操作符
赋值操作符可以让你修改一个变量的值,可以对于变量初始化。对于赋值操作符我们可以进行连续赋值,如:x=y=1;但是最好不要采用这样的做法,不便于计算机编译。
eg:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main() {
int a = 0;
printf("请输入一个数:\n");
scanf("%d", &a);
a = 45;
printf("a的值被修改为:%d\n", a);
system("pause");
return 0;
}
运行结果:
(1)复合赋值符
(a)+=:对于一个变量进行加再赋值
使用规则:用于整型、浮点型、字符型、字符型与浮点型之间变量进行加等。
注意事项:使用加等的时候注意变量操作的一致性。
eg:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main() {
int a = 0;
printf("请输入一个数:\n");
scanf("%d", &a);
a += 45;
printf("a+=45==>%d\n", a);
system("pause");
return 0;
}
(b) *=:对于一个变量进行乘再赋值
使用规则:用于整型、浮点型、字符型、字符型与浮点型之间变量进行乘等。
注意事项:使用乘等的时候注意变量操作的一致性。
eg:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main() {
int a = 0;
printf("请输入一个数:\n");
scanf("%d", &a);
a += 45;
printf("a*=45==>%d\n", a);
system("pause");
return 0;
}
(c)/=:除等(与加等、乘等类似)
(d)%=:求模等
使用规则:用于整型、浮点型、字符型、字符型与浮点型之间变量进行求模等。
注意事项:求模等的符号只能用于两个整型数之间进行运算。
(e)>>=:右移等
使用规则:用于整型、字符型变量进行右移等。
注意事项:进行右移的变量不能是浮点型变量。
eg:
x=3===>0000 0000 0000 0000 0000 0000 0000 0011
x>>=1===>0000 0000 0000 0000 0000 0000 0000 0001===>x=1
(f)<<=:左移等
使用规则:用于整型、字符型变量进行右移等。
注意事项:进行左移的变量不能是浮点型变量。
(g)&=:按位与等
使用规则:用于整型、字符型变量进行按位与等。
注意事项:进行按位与的变量不能是浮点型变量。
(h)|=:按位或等
使用规则:用于整型、字符型变量进行按位与等。
注意事项:进行按位与的变量不能是浮点型变量。
(i)^=:按位异或等
使用规则:用于整型、字符型变量进行按位与等。
注意事项:进行按位与的变量不能是浮点型变量。
5.单目操作符
! | 逻辑取反操作 |
---|---|
- | 负值 |
+ | 正值 |
– | – |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位):单个字符 |
– | – |
~ | 对一个数的二进制位取反 |
- - | 前置、后置- - |
– | – |
+ + | 前置、后置+ + |
* | 间接访问操作符(解引用) |
– | – |
(类型) | 强制转换 |
6.sizeof和数组
eg:
#include<stdio.h>
#include<stdlib.h>
void test1(int arr[]) {
printf("%d\n", sizeof(arr));
}
void test2(char ch[]) {
printf("%d\n", sizeof(ch));
}
int main() {
int arr[10] = { 0 };
char ch[10] = { '0' };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(ch));
test1(arr);
test2(ch);
system("pause");
return 0;
}
运行结果:
从这个运行结果可以看出sizeof()是以字节为单位求解操作数长度的。当数组作为参数进行传递的时候,会被退化成指针,当再次在函数内部进行调用的时候求解的是指针的字节数,对于32位操作系统,指针的大小永远是4个字节,所以当调用函数以后的输出结果都是4。
7.关系操作符
对于关系操作符一般用于条件判断中。
(1)>:大于
(2)>=:大于等于
(3)<:小于
(4)<=:小于等于
(5)!=:不等于
(6)==:等于
注意:两个等于符号才是判断相等,一个等于符号之进行赋值
8.逻辑操作符
(1)&&:逻辑与
(2)||:逻辑或
注意:对于逻辑与逻辑或,最后返回的只有真(非0)、假(0);区分逻辑与、或和按位与、或。
一道有陷阱的题:
#include<stdio.h>
#include<stdlib.h>
int mian() {
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
//i=a++ || ++b || d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
system("pause");
return 0;
}
运行结果:
从运行结果可以看出,当有多个逻辑与操作符时,遇到第一个为0了,结果已经不可能为真了,所以最后就不再进行下去了,直接退出,所以得到如上结果。
9.条件操作符
C预压中唯一的一个三目操作符:
exp1 ? exp2 : exp3
eg:
int a=1;
int b=2;
int c=0;
c=a>b?a:b;
10.逗号表达式
exp1,exp2,exp3……expn
注意:在逗号表示式中,都是从左向右执行,不会像逻辑表达式那样终止,会顺次执行到最右边,然后结果为最后右边的值。
11.下标引用、函数调用和结构体成员
(1)下标引用
操作数:一个数组名+一个索引值
int arr[10];
arr[9]=3;//下标引用第十个元素
(2)访问一个结构体成员
结构体名.成员名
结构体指针->成员名
struct Stu{
char name[104];
int age;
}
void set_age(struct Stu stu){
stu.age=18;//直接通过对象访问
}
void set_age(struct Stu* pstu){
pstu->age=18;//指针访问
}
二、表达式求值
对于表达式求值的顺序,如果没有特别的符号进行限制,那么它的求值顺序是按照优先级进行的。同样在求值过程中,有可能会有数据的类型自动从小转变为大。
1.隐式类型转换
在C语言中为了提高精度,它会自己进行整型提升。
整形提升:
//负数的整型提升
char c1=-1;
//补码(对于char型只有一个字节,8个bit位):1111 1111
//进行整型提升以后,将补码补齐为4个字节(32个bit为位)
//补码:1111 1111 1111 1111 1111 1111 1111 1111
//正数的整型提升
char c1=1;
//补码(对于char型只有一个字节,8个bit位):0000 0001
//进行整型提升以后,将补码补齐为4个字节(32个bit为位)
//补码:0000 0000 0000 0000 0000 0000 0000 0001
2.算术转换
将小类型的数据在参与运算的时候自动转换为较大类型的数据
注意:算术操作符要合理,不然回引起潜在的问题
3.操作符的属性
复杂表达式的求值有三个影响的因素。
(1)操作符的优先级
(2)操作符的结合性
(3)是否控制求值顺序
对于两个相邻的操作符哪个先进性:取决于他们的优先级,如果优先级相同取决他们的结合性,操作符有优先级