(除了自增自减操作符以外,只能通过赋值操作符更改被操作数的值)
**一、算数操作符:**加 + 、减 - 、乘 * 、除 / 、取余 %
(注:
1、除了%操作符只能作用于整数以外,其他的操作符可以作用于整数和浮点数。
2、对于/操作符,如果两个数都是整数,执行整数除法,只要有浮点数就执行浮点数除法。)
**二、移位操作符:**左移操作符 << 、右移操作符>>。(以二进制位)
(注:
右移操作符:
1、无符号数执行逻辑移位,左边用零填充,右边舍弃;
2、有符号数执行算术移位,左边填充符号位,右边舍弃。
左移操作符:
1、右边补零。)
例如:
int num=-1;
num>>1;//意思为将num右移一位。
例如:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 4;//1的二进制码在32位平台上为0000 0000 0000 0000 0000 0000 0000 0100=4
int m = 6;//1的二进制码在32位平台上为0000 0000 0000 0000 0000 0000 0000 0110=6
printf("n>>1=%d\t",n>>1);//结果为 0000 0000 0000 0000 0000 0000 0000 0010=2
printf("m<<2=%d\t",m<<2);//结果为 0000 0000 0000 0000 0000 0000 0000 1100=12
printf("n<<m=%d\t",n<<m);//结果为 0000 0000 0000 0000 0000 0001 0000 0000=256
printf("\n");
int i= -1;//-1的二进制码为原码为 1000 0000 0000 0000 0000 0001 0000 0000=-1;
//反码为11111 1111 1111 1111 1111 1111 1111 1110;
//补码为11111 1111 1111 1111 1111 1111 1111 1111;
printf("i>>3=%d\t",i >> 3);//结果补码为1111 1111 1111 1111 1111 1111 1111 1111,
//反码为1000 0000 0000 0000 0000 0000 0000 0000,
//原码为1000 0000 0000 0000 0000 0000 0000 0001=-1
printf("i<<3=%d\t",i << 3);//结果补码为1111 1111 1111 1111 1111 1111 1111 1000,
//反码为1000 0000 0000 0000 0000 0000 0000 0111,
//原码为1000 0000 0000 0000 0000 0000 0000 1000=-8
return 0;
}
**三、位操作符:**按位与&、按位或|、按位异或^、按位取反~(操作数必须是整数,对操作数的二进制位进行操作)
例如:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 1;//1的二进制码在32位平台上为0000 0000 0000 0000 0000 0000 0000 0001=1
int m = 2;//1的二进制码在32位平台上为0000 0000 0000 0000 0000 0000 0000 0010=2
printf("n&m=%d\t", n&m);//结果为 0000 0000 0000 0000 0000 0000 0000 0000=0
printf("n|m=%d\t",n|m);//结果为 0000 0000 0000 0000 0000 0000 0000 0011=3
printf("n^m%d\t", n^m);//结果为 0000 0000 0000 0000 0000 0000 0000 0011=3
return 0;
}
不建立临时变量交换两个整数
#include<stdio.h>
int main()
{
int n = 1;
int m = 2;
scanf("%d%d", &n, &m);
printf("before:n=%d m=%d", n, m);
//任何数 ^ 0结果都是其本身,任何数 ^ 其本身都是0
n = n^m;
m = n^m;//m=(n^m)^m=n^(m^m)=n^0=n
n = n^m;//n=(n^m)^((n^m)^m)=(n^n)^(m^m^m)=0^m=m
return 0;
}
实现求一个整数存储在内存中的二进制数中1的个数
方法一:
#include<stdio.h>
int main()
{
int n = 0;
int count = 0;
scanf("%d", &n);
while (n)
{
if ( 1==n % 2)
{
count++;
}
n /= 2;
}
printf("count=%d", count);
return 0;
}
方法二:
#include<stdio.h>
int main()
{
int n = 0;
int count = 0;
int num = 1;
int i = 0;
scanf("%d", &n);
/*例如:n=13;---0000 0000 0000 0000 0000 0000 0000 1101;
n&num----- & 0000 0000 0000 0000 0000 0000 0000 0001;----count++;
num<<1---- 0000 0000 0000 0000 0000 0000 0000 1101;
n&num---& 0000 0000 0000 0000 0000 0000 0000 0010;
i ++,num<<2
.....*/
for (i = 0; i < 32;i++)//32位平台的二进制数只有32位,逐位的进行对照.
{
if ((num<<i)&n)//只有 num<<1的二进制位对应的1与n的二进制位同为1时,才能得到非0的结果,才能使count++;
{
count++;
}
}
printf("count=%d", count);
return 0;
}
方法三:最佳方案
#include<stdio.h>
int main()
{
int n = 0;
int count = 0;
int num = 1;
int i = 0;
scanf("%d", &n);
/*例如:num=13;
num = 0000 0000 0000 0000 0000 0000 0000 1101;
num-1= & 0000 0000 0000 0000 0000 0000 0000 1100;count++;
num=num&(num-1)= = 0000 0000 0000 0000 0000 0000 0000 1100;count++
num-1 & 0000 0000 0000 0000 0000 0000 0000 1011;
num=num&(num-1)= = 0000 0000 0000 0000 0000 0000 0000 1000;count++
num-1 & 0000 0000 0000 0000 0000 0000 0000 0111;
num=num&(num-1)= = 0000 0000 0000 0000 0000 0000 0000 0000;
*/
while (n)
{
count++;
num = num&(num - 1);
}
printf("count=%d", count);
return 0;
}
四、赋值操作符:=
复合赋值操作符:+=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=、
**五、单目操作符:*自增++、自减–、正+、负-,逻辑反!、
对操作数按位取反~、取地址操作符&、
间接访问操作符、(类型)强制类型转换操作符,
sizeof操作符的类型长度,单位为字节(不是函数)
例如:
#include<stdio.h>
int main()
{
int*p = NULL;
int a = 10;
printf("!a=%d\n", !a);//a!=0;!a=0;
printf("!0=%d\n", !0);//!0=1;
p = &a;
printf("%d\n", sizeof(a));//a是int 型,在32位的平台上占4个字节
printf("%d\n", sizeof(int));//int 型,在32位的平台上占4个字节
//printf("%d/n", sizeof int);//此处不可以不带()
printf("%d\n", sizeof a);//此处可以不带(),说明sizeof是操作符
printf("%d\n", sizeof(p));//指针中存的是地址,在32位平台上占4个字节,在64位平台上占8个字节
return 0;
}
例如:
int a=10;
char b=(char)a;//并不改变原始a,的类型,原始a依旧为int 型
**六、关系操作符:**逻辑与&&、逻辑或||、>、>=、<、<=、!=、==
按位与:1&2=0
逻辑与:1&&2=1
按位或:1|3=3;
逻辑或:1||3=1
例如:
#include<stdio.h>
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++&&++b&&d++;
printf("a=%d\tb=%d\tc=%d\td=%d\n",a,b,c,d);
//在逻辑与条件中,只要有一个条件不满足,则整个条件都不满足,所以在逻辑与条件中一旦出现了不满足条件的就会立刻停止对条件的判断
/*i = a++||++b||d++;
printf("a=%d\tb=%d\tc=%d\td=%d\n", a, b, c, d);*/
//在逻辑或条件中,只要有一个条件满足,则整个条件都满足,所以在逻辑或条件中一旦出现了满足条件的就会立刻停止对条件的判断
return 0;
}
七、条件操作符:exp1?exp2:exp3;
#include<stdio.h>
int main()
{
int x = 10;
int y = 20;
int b=x > y ? x : y;
printf("max=%d", b);
return 0;
}
八、逗号表达式
exp1,exp2,exp3;
用逗号隔开的多个表达式,从左向右执行,最后的结果由最后一个表达式决定
例如:
#include<stdio.h>
int main()
{
int x = 10;
int y = 20;
int b = (x = y,y=30,x+y);//x=y=20,y=30,x+y=50------->b=x+y=50
printf("b=%d", b);
return 0;
}
九、下标引用、函数调用和结构体成员
1、[ ]下标引用操作符
操作数:一个数组名+一个索引值
例如:
int arr[10];//创建数组
arr[9]=10;//使用下标引用,arr和9是两个操作数
2、()函数调用操作符
接受一个或者多个操作数,第一个操作数是函数名,其他的操作数就是函数的参数
例如:
int fib(int n)
{
}
int main()
{
int n=10;
fib(10);
}
3、访问一个结构的成员
.结构体.成员名
->结构体指针->成员名
例如:
#include<stdio.h>
struct Stu
{
char name[10];
int age;
char sex[5];
double score;
};
void set_age1(struct Stu stu)
{
stu.age = 18;
}
void set_age2(struct Stu* pStu)
{
pStu->age = 18;
}
int main()
{
struct Stu stu;
struct Stu* pStu=&stu;
stu.age = 20;
set_age1(stu);
pStu->age = 20;
set_age2(pStu);
return 0;
}
十、表达式求值
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整形提升
例如:
char a,b,c;
…
a=b+c;//在计算时,会先将b,c从char型转换为int型,计算完了之后再转换为char型,这是因为在计算机中,计算过程在cpu中完成,而电脑中的内容都是以二进制数字形式存储的。
整形提升是根据变量自身的数据类型的符号位来提升的:
1、有符号类型的整形提升:高位补充符号位
2、无符号类型的整形提升:高位补充0;
例如1:
#include<stdio.h>
int main()
{
char a = 0xb6;//一个字节,8个bit位
short b = 0xb600;//两个字节,16个bit位
int c = 0xb6000000;//四个字节,32个bit位
if (0xb6 == a)//0xb6是整十六进制型,a是char型,会发生整型提升,提升后是负数所以不相等
{
printf("a=%d\n", a);
}
if (0xb600 == b)//0xb600是整十六进制型,b是char型,会发生整型提升,提升为后为负数,所以不相等
{
printf("b=%d\n", b);
}
if (0xb6000000 == c)//只会输出c
{
printf("c=%d\n", c);
}
return 0;
}
例如2:
#include<stdio.h>
int main()
{
char c = 1;
//只要c参与了表达式运算就会发生整形提升,
printf("%u\n", sizeof(c));//1
printf("%u\n", sizeof(+c));//4
printf("%u\n", sizeof(!c));//1
return 0;
}
十一、算术转换
如果某个操作符的各个操作数不是同一类型,则会将其中一个转换为另一个操作数的类型
如果某个操作数的类型在以下列表中排名较低,那么首先将这个操作数转换为另一个操作数的类型
long double
double
float
unsigned long int
long int
unsigned int
int
short
char
十二、操作符的属性
1、操作符的优先级
2、操作符的结合性
3、是否控制求值顺序