前言
C语言中各种各样的操作符使得C语言程序灵活多变,使用好各类操作符更能使程序灵巧轻便,这里记录下自己学习的操作符,也与各位共享
1.算数操作符
算数操作符中有
1
+ - * / %
此处对 / 和 % 做些说明:
/:对于除法来说两个数中有一个是浮点数,则执行的是浮点数除法,两个都是整数,则执行的是整数除法
%:对于取余,符号后一定是整数,不能是浮点数,如:%3.0(错)
1 |
|
运行结果
a=3 b=1
说明:取余看的是余数,除法看的是商
2.移位操作符
左移操作 <<
右移操作 >>
移位移的是数字在内存中存的二进制的补码,移位移的是二进制位
移位操作如果不给自己赋值是不会改变自己的,表达式是移位后的结果1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int a = 10;
int b = a<<1;
int c = a>>1;
//整数的原码,反码,补码都相同
//00000000 00000000 00000000 00001010
printf("a = %d\n",a);
printf("b = %d\n",b);
return 0;
}
运行结果:a = 20 b = 5
左移:左边直接丢弃,右边补零,有x2的效果
右移:①算术右移:右边丢弃,左边补符号位
②逻辑右移:右边丢弃,左边补0
而这两种右移方式执行哪一个,完全取决于你的编译器,但经测试,大部分编译器都采用算术右移,更合理一点
waring: 对于移位运算符,不要移动负数位,这个是标准未定义的
3.位操作符
按位与 & :与:一个是零 则为零,两个为一,才为一
按位或 |:一个为1则为1,两个为0,才为0
按位异或 ^:相同为0,相异为 1
1 |
|
运行结果: c = 10 d = -1 k = -11
4.赋值操作符(=)
1 | int weight = 60; //使用赋值操作符赋值 |
赋值操作符可以连续使用 a = x = y+1
复合赋值符
1 | a = a+10; |
5.单目操作符
正值:+
负值:-
逻辑反操作 !
1 |
|
运行结果: 0
对一个数的二进制位进行取反 ~
取地址: &
取变量地址
1 | printf("%p",&a); //可以打印出a的地址 |
数组取地址:
1 |
|
运行结果:0028FE98
0028FE9C
0028FE98
0028FEC0
数组名加1与数组首元素差4个字节而取地址数组名加1则与取地址数组名差了40个字节,即一整个数组
函数取地址
1 |
|
操作数的类型长度(以字节为单位): sizeof
sizeof的作用:就是返回一个对象或者类型所占的内存字节数。
三个程序说明sizeof
①1
2
3
4
5
6
7
8
9
10
11
int main()
{
int a = 10;
int arr[10] = {0};
printf("%d\n",sizeof(a)); //4字节
printf("%d\n",sizeof(int)); //4
printf("%d\n",sizeof(arr)); //40
printf("%d\n",sizeof(int [10])); //40
return 0;
}
由此可见,sizeof可以求一个变量的内存大小。也可以求数组的内存大小
②1
2
3
4
5
6
7
8
9
int main()
{
int a = 10;
int arr[10] = {0};
printf("%d\n",sizeof a);
// printf("%d\n",sizeof int); 类型一定要带上()否则是无法运行的
return 0;
}
运行结果为4
此程序说明sizeof是个操作符,他并不是个函数
③1
2
3
4
5
6
7
8
9
10
int main()
{
short s = 10;
int a = 6;
printf("%d\n",sizeof(s=a+8)); //2
printf("%d\n",a); //6
printf("%d",s); //10
return 0;
}
此处运行结果为 2 6 10
此处说明,sizeof内的表达式不参与计算,sizeof所计算的变量类型遵从被赋值的变量
对一个数的二进制数取反:~
将一个数的二进制序列取反。0变1,1变01
2
3
4
5
6
7
8
9
10
int main()
{
printf("%d",~10);
//00000000 00000000 00000000 00001010
//11111111 11111111 11111111 11110101 补码
//10000000 00000000 00000000 00001010
//10000000 00000000 00000000 00001011
return 0;
}
运行结果 -11
前置– 后置– : –
前置++ 后置++ : ++
这里只用了解前置的情况下先自增(自减)在使用,后置的情况下先使用在自增(自减)。
值得注意的是指针的++ –1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
int a[10] = {0};
int *p = a;
printf("%d\n",p);
printf("%d\n",++p);
//char c = 'a';
//char *p = &c;
//printf("%p\n",p);
//printf("%p\n",++p);
return 0;
}
运行结果:2686612 2686616
相差了4个字节,由此可见自增自减也不一定任何情况下都是加一或减一,这和他所指向的类型的关系有关,当换成字符类型,又变为加减1字节
间接访问操作符(解引用操作符): *
1 |
|
解引用的作用是拿到某个地址,通过地址找到其内容。
强制类型转换:(类型)
1 |
|
强制类型转换容易丢失精度,一般不建议使用
6.关系操作符
C语言中的关系操作符有 > >= < <= != == 这些关系运算符较为简单,不o做多余赘述,须记住在比较两个字符的时候,是不能用 == 的,而是要用strcmp
7.逻辑操作符
逻辑与:
&&:逻辑与,读作并且
表达式左右两边都为真,那么结果才为真
口诀:一假则假
逻辑或:
||:逻辑或,读作或者
表达式左右两边,有一个为真,那么结果就为真
口诀:一真则真
逻辑运算符的短路问题
tips:非0为真,0为假
短路的情况:
&&:左边如果为假,则右边短路(右边不会被执行)
||:左边如果为真,则右边短路(右边不会执行)1
2
3
4
5
6
7
8
int main()
{
int i = 0,a = 0,b = 2,c = 3,d = 4;
i = a++ && ++b && d++;
printf("a = %d\nb = %d\nc = %d\nd = %d\n",a,b,c,d);
return 0;
}
运行结果 1 2 3 4
原因: a = 0为假导致 a++ && ++b 为假,所以++b短路,不执行, b=2,然后a++ && ++b 整体为假,导致a++ && ++b && d++为假,所以d++不执行,d = 4,整个过程只有a自增了一下,a =1
8.条件操作符(三目操作符)
如果希望获得两个数中最大的一个,可以使用 if 语句,例如:1
2
3
4
5if(a>b){
max = a;
}else{
max = b;
}
不过,C语言提供了一种更加简单的方法,叫做条件运算符,语法格式为:1
2
3
4
5表达式1 ? 表达式2 : 表达式3
条件运算符是C语言中唯一的一个三目运算符,其求值规则为:如果表达式1的值为真,则以表达式2 的值作为整个条件表达式的值,否则以表达式3的值作为整个条件表达式的值。条件表达式通常用于赋值语句之中。
上面的 if else 语句等价于:
```c
max = (a>b) ? a : b;
该语句的语义是:如a>b为真,则把a赋予max,否则把b 赋予max。
三目操作符完全可以用if-else替代
9.逗号表达式
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式1
2
3int a = 1;
int b = 2;
int c = (a>b,a=b+10,a,b=a+1);
运行结果 c = 13
10.下标引用、函数调用和结构成员
下表引用
arr[10]中[]就是下标引用操作符,他有两个操作数 arr和10
①除了优先级之外,下表引用和间接访问完全相同。如下面两个表达式是等同的:1
2arr[4];
*(arr+4);
②4[arr]表达式是合法的
表达的意思与(4+arr)也就是(arr+4)是完全一样的。但是绝对不应该这么写,影响程序的可读性。
附:1
2
3
4
5
6
7
8
9
10
11
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%d\n",arr[4]);
printf("%d\n",*(arr+4));
printf("%d\n",*(4+arr));
printf("%d\n",4[arr]);
return 0;
}
函数调用
1 |
|
访问一个结构的成员
结构体代码的基本结构1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Stu
{
int age;
char name[20] = {0};
float score;
};
int main()
{
struct Stu s;
struct Stu* ps = &s; //结构体指针
strcpy(s.name,"zhang san "); //把一个字符串拷贝到另一个空间
s.age = 20;
s.score = 60.0f;
// printf("%s %d %f",s.name,s.age,s.score);
// printf("%s %d %f",(*ps).name, (*ps).age, (*ps).score); //通过结构体指针输出,但这个过于繁琐,可以改为 ->
printf("%s %d %f",ps->name,ps->score,ps->age);
return 0;
}
注意:
①在定义结构体时大括号后一定有一个分号;
②结构体是一个类型,没有占用空间,只是个模板(地图),等同于int,float等,他是通过s才创建空间的;
③从结构体到主函数的过程叫做实例化;
④获取结构体成员:通过结构体指针可以获取结构体成员,一般形式为:1
(*ps).name
或者:1
ps->name
第一种写法中,.的优先级高于,(name)两边的括号不能少。
第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。
上面的两种写法是等效的,我们通常采用后面的写法,这样更加直观。