- 算数操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号操作符
- 下标引用,函数调用和结构体成员
1算数操作符(+ - * / %)
整型除法 :1/2=0
浮点型除法 :1.0/2=0.5
取模操作符两边为整数
2移位操作符(移动的是二进制位)
操作对象是整数,整数在内存存储补码
左移<<,
左边丢弃,右边补零
右移>>
分 1算数右移 :右边丢弃,左边 补原符号位( 大多的编译器都是算数)
2逻辑右移 :右边丢弃,左边补零
3位操作符
按位与 &
同一为一
按位或 |
同零为零
按位异或^
相同为零
不创建临时变量实现两数交换
#include<stdio.h>
int main()
{
int a = 3, b = 5;
a = a + b;//8
b = a - b;//3
a = a - b;//5
//可以实现交换,但是可能会溢出;
return 0;
}
该方法只适合整数,且速度不如一
a=a^b;
b = a ^ b;
a = a ^ b;
置0与置1操作
#include<stdio.h>
int main()
{
int a = 13;//1101
//置1操作
a = a | (1 << 1);//1101|0010
//(1<<)0010,可以对二进制位数+1
//置0操作
int b = 13;
b = b & ~(1 << 3);
printf("%d", b);
return 0;
}
4赋值操作符
5单目运算符
只有一个操作数
正数+ 负数- 逻辑反! 取地址& 二进制取反~ ++或-- 解引用* sizeof操作数的类型长度
()类型转换
sizeof计算1 类型创建的变量占空间的大小·
2 计算变量占内存空间的大小
int arr[10] = { 0 };
char arr1[10] = { 0 };
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr1));
test1(arr);//40
test2(arr1);//10
return 0;
}
void test1(int arr[])
{
printf("%d\n", sizeof(arr));//4
}
void test2(char arr1[])
{
printf("%d\n", sizeof(arr1));//4该处是指针的大小
}
6关系操作符
<
>
== :浮点数与字符串
abc==asd比较的是字符首地址
strcmp
!=
7逻辑操作符
&&逻辑与(左边假右边不计算)
int a = 1;
int b = 2;
int c = a && b;//1
int d = 1;
int e= 0;
int f = d && e;//0
||逻辑或(左边真右边不计算)
int d = 1;
int e= 0;
int f = d || e;//1
小练习
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("%d %d %d %d\n", a, b, c, d);
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;//只有a++,剩下不计算
printf("%d %d %d %d\n", a, b, c, d);//1234
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ ||++b ||d++;//只有a++,剩下不计算
printf("%d %d %d %d\n", a, b, c, d);//2234
8条件操作符(三目操作符)
表达式1?表达式2:表达式3
9逗号表达式
表达式1,表达式2,表达式3//依次执行,表达式的结果是最后一个表达式的结果
10 下标引用,函数调用与结构体成员
10.1下标引用操作符【】( 访问时8[arr] = 9;)
//下标引用
int arr[10] = { 0 };
arr[8] = 8;//操作的是arr与8
10.2函数调用操作符()
10.3结构体成员struct
10.3-1结构体成员名 。 (形参改变实参是使用指针与取地址
#include<stdio.h>
#include<string.h>
void print_stu(struct Stu ss);
void set_stu(struct Stu* ss);
struct Stu
{
char name[20];
int age ;
double score;
};
int main()
{
// 表达式1,表达式2,表达式3//依次执行,表达式的结果是最后一个表达式的结果//
// 下标引用
// int arr[10] = { 0 };
// //arr[8] = 8;操作的是arr与8
// 8[arr] = 9;
struct Stu s = { 0 };
set_stu(&s);
print_stu(s);
return 0;
}
void set_stu(struct Stu* ss)
{/*
strcpy(ss.name ,"zhangsan");
ss.age = 15;
ss.score = 100.0;*/
strcpy((*ss).name, "zhangsan");
(*ss).age = 15;
(*ss).score = 100.0;
}
void print_stu(struct Stu ss)
{
printf("%s %d %lf\n", ss.name, ss.age, ss.score);
}
.10.3-2结构体指针->成员
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void print_stu(struct Stu ss);
void set_stu(struct Stu* ss);
struct Stu
{
char name[20];
int age ;
double score;
};
int main()
{
// 表达式1,表达式2,表达式3//依次执行,表达式的结果是最后一个表达式的结果//
// 下标引用
// int arr[10] = { 0 };
// //arr[8] = 8;操作的是arr与8
// 8[arr] = 9;
struct Stu s = { 0 };
set_stu(&s);
print_stu(s);
return 0;
}
void set_stu(struct Stu* ss)
{/*
strcpy(ss.name ,"zhangsan");
ss.age = 15;
ss.score = 100.0;*/
/*strcpy((*ss).name, "zhangsan");
(*ss).age = 15;
(*ss).score = 100.0;*/
strcpy(ss->name, "zhnagsan");
ss->age = 15;
ss->score = 100.0;
}
void print_stu(struct Stu ss)
{
printf("%s %d %lf\n", ss.name, ss.age, ss.score);
}
11表达式求值
表达式求值顺序一部分是由操作符优先级和结合性决定,
有些表达式的操作数可能变成其他类型
11.1隐式类型转化
c的整型算数结束总是至少以缺省(默认)整型类型精度来进行的
为了获得这个精度,表达式中的字符与短整型操作数在使用i前转化为普通整型,称为整型的提升
整型提升的意义
表达式的整型运算要在cpu的相应器件内执行,cpu内的整型运算器的操作数的字节长度一般是int类型的字节长度,同时也是cpu通用寄存器长度
即使两个char类型相加,在cpu执行时也是先转化为cou内整型操作数的标准长度
通过cpu时难以直接实现8比特字节相加运算(虽然机械指令可能有这种字节相加的指令)所以表达式中各种长度计算可能小于int类型长度的整型值,都先转换为int或unsighed int 再去cou中计算
如何进行提升
按照变量的数据类型的符号位来提升
char a = -1;
//-1:1000000000000000000000000001源码
//11111111111111111111111111111110反码
//1111111111111111111111111111补码
//char是一个字节11111111
//按符号位来提升,该处是1
//所以提升为
//1111111111111111111111111111
//如果是零就全补零
//无符号也是补零
char a = 5;
//00000000 0000000 00000000 00000101
//000000101cahr
char b = 126;
//00000000 0000000 00000000 01111110
//cahr:01111110
char c = a + b;
//a:000000101
//b:01111110
//先提升
//a:00000000 0000000 00000000 00000101
//b:00000000 0000000 00000000 01111110
//相加
//00000000 0000000 00000000 10000011
//存入c
//10000011
printf("%d\n",c);/-125
//输出
//源码:10000011
//提升(补码):1111111 1111111 11111111 10000011
//反码:1111111 1111111 11111111 10000010
//原码:1000000 0000000 00000000 01111101
验证整型提升
(结果只有c)
char a = 0xb6;
//改为unsigned即可以,unsigned是高位补零
//或者a实际存入负数
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
{
printf("a");
}
if (b == 0xb600)
{
printf("b");
}
if (c == 0xb6000000)
{
printf("c");
}
char a = 1;
printf("%u\n",sizeof(a));//1
printf("%u\n", sizeof(-a));//4
printf("%u\n", sizeof(+a));//4
11.2算数转化
先上转化
long double
double
float
unsigned long int
long int
unsigned int
int
11.3操作符的属性
复杂表达式求值三个影响因素
1操作符的优先级
当两个不同操作符在一起比较优先级
2操作符的结合性
相同操作符
3是否控制求值顺序
如&&左边为假右边不计算
还有一些问题表达式
跟编译器有关,a*b+c*d+e*f
只能确定*优先与+不能确定第一个*优先与第三个*
比如int c=2;
c+ --c;
可能是三也可能是二
非法表达式
在不同的编辑器结果不一样
int i = 1;
i = i-- - --i * (i - -3) * i++ + +i;