详解操作符

算术操作符 + - * / %

/

3/2 结果是整数1(除号两端都是整数执行整数除法)

3.0/2 3/2.0 结果是小数(除号两端至少有一个是小数执行小数除法)

%

9%2 求的是余数(取模操作符两端必须是整型)有范围

移位操作符

操作的是二进制位

<< 左移操作符

>> 右移操作符

注意:不能移动负数位(num>>-1)

左移

int main()
{
    int a= 5;
    int b = a << 1;//左边丢弃,右边补0
    printf("%d\n", a);//5       00000000000000000000000000000101
    printf("%d\n", b);//10      00000000000000000000000000001010
    return 0;
}
int main()
{
    int a= -5;
    int b = a << 1;
    printf("%d\n", a);//-5       11111111111111111111111111111011
    printf("%d\n", b);//-10       11111111111111111111111111110110补码
                              // 11111111111111111111111111110101反码   
                              // 00000000000000000000000000001010原码    
    return 0;
}

计算的是补码,打印出来的是原码

原码 --> 符号位不变其他位按位取反得到反码 --> 反码+1得到补码

符号位不变其他位按位取反得到原码 <-- 补码-1得到反码 <-- 补码

右移

右移操作符(到底用哪个方法取决于编译器):

  1. 算术右移: 右边丢弃,左边补原符号位 (当前编译器在右移采用算术右移)
  2. 逻辑右移: 右边丢弃,左边补0

int mian()
{
    int a = 5;
    int b = a >> 1;
    printf("%d\n", a);//5           00000000000000000000000000000101
    printf("%d\n", b);//2           00000000000000000000000000000010
    return 0;
}

int mian()
{
    int a = -5;
    int b = a >> 1;
    printf("%d\n", a);//-5           
    printf("%d\n", b);//-3   
    return 0;        
}

整数的二进制表示形式有3种:

例: int a = 5

原码 00000000000000000000000000000101

反码 0000000000000000000000000000101

补码 00000000000000000000000000000101

int a = -5

原码: 10000000000000000000000000000101

反码:11111111111111111111111111111010(原码的符号位不变,其他位按取反(0和1反一反)得到的就是反码)(补码-1就是反码)

补码:11111111111111111111111111111011 (反码+1就是补码)

符号位:

0 整数

1 负数

正整数的原码、反码、补码是相同的

负整数的原码、反码、补码是要计算的

整数在内存中存储的是补码的二进制

位操作符:

& - 按(二进制)位与

| - 按(二进制)位或

^ - 按(二进制)位异或

a&b 双目操作符

&a 单目操作符

int main()
{
    int a = 3;//00000000000000000000000000000011补码
    int b = -5;//11111111111111111111111111111011补码
    int c = a & b;//00000000000000000000000000000011补码(两个同时为1时按位与才能是1)
    printf("%d\n", c);//3 正数原反补相同 
    return 0;
}

int main()
{
    int a = 3;
    int b = -5;
    int c = a | b;//(按位或只要有1就是1)
                  //11111111111111111111111111111011补码    
    printf("%d\n", c);//-5 (恰好是-5的补码和原码)
    return 0;
}

int main()
{
    int a = 3;
    int b = -5;
    int c = a ^ b;//(异或:对应的二进制位是相同为0,相异为1)
                  //11111111111111111111111111111000补码
                  //11111111111111111111111111110111反码(补码-1)
    printf("%d\n", c);//-8   10000000000000000000000000001000原码
    return 0;
}

a^a = 0

0^a = a

不能创建临时变量(第三个变量)实现两个变量的交换

int main()
{
	int a = 3;//011
	int b = 5;//101
	printf("a=%d b=%d\n", a, b);

	a = a ^ b;//110
	b = a ^ b;//011
	a = a ^ b;//101

	printf("a=%d b=%d\n", a, b);

	return 0;
}

求一个整数存储在内存中的二进制中1的个数

int main()
{
	int num = 0;
	scanf("%d", &num);
	int i = 0;
	int count = 0;

	for (i = 0; i < 32; i++)
	{
		if ((num >> i) & 1)
		{
			count++;
		}

	}
	printf("%d\n", count);
	return 0;
}

赋值操作符

=

连续赋值:a = x = y+1;(可读性较差)

复合赋值符

a+= a-= ……

单目操作符

! 逻辑反操作

C语言中0表示假,非0表示真

C语言中C99之前没有表示真假的类型

C99中引用了布尔类型 false true

- 负值

+ 正值

& 取地址

* 间接访问操作符(解引用操作符)

struct S
{
    char name[20];
    int age;
};

int main()
{
    int a=10;
    int*pa=&a;
    *pa=20;//解引用操作符
    //*&a ==> a
    
    int arr[10]={0};
    &arr;//取出数组地址,数组的地址应该放到【数组指针】中去
    
    struct S s = {0};
    struct S* ps = &s;
    
    return 0;
}

sizeof 操作数的类型长度(以字节为单位

是操作符,不是函数

用来计算类型创建的变量所占内存的大小

int main()
{
    /*int a = 10;
    printf("%d\n", sizeof(a));//4
    printf("%d\n", sizeof(int));//4*/

    //int arr[10] = { 0 };
    //printf("%d\n", sizeof(arr));//40(前提是数组没有传参)

    int a = 10;
    short s = 0;
    printf("%d\n", sizeof(s = a + 2));//2
    printf("%d\n", a);//10
    //sizeof()中的表达式不参与计算
    //sizeof是在编译期间处理的
    printf("%d\n", s);//0

    return 0;
}

~ 对一个数的二进制按位取反

int main()
{
	/*int a = 0;
	printf("%d\n", ~a);*///-1
	//00000000000000000000000000000000
	//11111111111111111111111111111111 补码
	//11111111111111111111111111111110 反码
	//10000000000000000000000000000001 取反 -1


	int a = 11;
	//00000000000000000000000000001011
	//00000000000000000000000000000100
	a |= (1 << 2);
	printf("%d\n", a);//15  1111

	a &= (~(1 << 2));
	printf("%d\n", a);//11  1011
	return 0;
}

~ (-1) --> 0

为什么while(~scanf("%d",&n))可以终止循环?

scanf()读取失败的时候,返回EOF(-1)

原来写法: while(scanf("%d", &n) !=EOF)

-- 前置、后置--

++ 前置、后置++

++a 前置++ 先++,后使用

a++ 后置++ 先使用,后++

int a=10;
int b=a+1;
int b=++a;//前置++//a=a+1;b=a;
int b=a++;//后置++//int b=a;a=a+1;
#include <stdio.h>
int main()
{
	int a, b, c;
	a = 5;
	c = ++a;// ++a:加给a+1,结果为6,用加完之后的结果给c赋值,因此:a = 6  c = 6
	b = ++c, c++, ++a, a++;
	// 逗号表达式的优先级,最低,这里先算b=++c, b得到的是++c后的结果,b是7
	// b=++c 和后边的构成逗号表达式,依次从左向右计算的。
	// 表达式结束时,c++和,++a,a++会给a+2,给c加1,此时c:8,a:8,b:7
	b += a++ + c; // a先和c加,结果为16,在加上b的值7,比的结果为23,最后给a加1,a的值为9
	printf("a = %d b = %d c = %d\n:", a, b, c); // a:9, b:23, c:8
	return 0;
}

(类型) 强制类型转换

int main()
{
	int a = (int)3.14;
	printf("%d\n", a);//3

	return 0;
}

关系操作符

比大小

> >= < <= != ==

两个字符串是不能比大小的

实际比的是两个字符串中首字母的地址

strcmp-专门用来比较字符串的大小

对应位置上字符的大小,而不是比较长度

逻辑操作符

&& 逻辑与

|| 逻辑或

只在乎真假

区分:

1&2 0

1&&2 1

1|2 3

1||2 1

条件操作符

exp1 ? exp2 : exp3

表达式1为真,表达式2执行,表达式2的结果是整个表达式的结果

表达式1为假,表达式3执行,表达式3的结果是整个表达式的结果

逗号表达式

exp1,exp2,exp3,…expn

从左到右依次执行,整个表达式的结果是最后一个表达式的结果

下标引用、函数调用和结构成员

[ ]下标引用操作符

操作数:一个数组名+一个索引值

int main()
{
    int arr[10]={0};//创建数组
   
     arr[9] = 10;//实用下标引用操作符
}

[ ]的两个操作数是arr和9

等价于:

arr[4]<==>*(arr+4)<==>*(4+arr)<==>a[arr]

( ) 函数调用操作符

接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

int Add(int x,int y)
 {
     return x+y;
 }
 
 int main()
 {
   int ret =  Add(2,3);//()函数调用操作符,操作数就是:Add,2,3
   printf("%d\n",ret);
        return 0;
 }

访问一个结构的成员

. 结构体.成员名

-> 结构体指针->成员名

struct Stu
{
    char name[20];
    int age;
    float score;
};

void print1(struct Stu ss)
{
    printf("%s %d %f\n", ss.name, ss.age, ss.score);
}
//结构体变量.成员名

void print2(struct Stu* ps)
{
    //printf("%s %d %f\n",(*ps).name,(*ps).age,(*ps).score);
    printf("%s %d %f\n", ps->name, ps->age, ps->score);

}
//结构体指针->成员名

int main()
{
    struct Stu s = { "张三",20,90.5f };
    strcpy(s.name, "李四");//修改用strcpy
    //scanf("%s",s.name);

   print1(s);
    print2(&s);
    return 0;
}

表达式求值

表达式求值的顺序一部分是由操作度的优先级和结合性决定

有些表达式操作数在求值过程中可能需要转换为其他类型。

隐式类型转换

C语言的整型算术总是以缺省整型类型的精度来进行的

为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

int main()
{
	char c1 = 3;
	//00000000000000000000000000000011
	//00000011   c1
	char c2 = 127;
	//00000000000000000000000001111111
	//01111111    c2

	char c3= c1 + c2;
	//10000010   c3 补码
	//111111111111111111111111110000010提升
	//111111111111111111111111110000001反码
	//100000000000000000000000001111110补码

	printf("%d\n", c3);//-126
	return 0;
}

char == ? 到底是signed char还是unsigned char取决于编译器

signed char

unsigned char

short == signed short

unsigned short

int == signed int

unsigned int

整型提升

负数补1,正数补0

int main()
{
    char c = 1;
    printf("%u\n",sizeof(c));//1
    printf("%u\n",sizeof(+c));//4
    printf("%u\n",sizeof(-c));//4
    return 0;
}
//c只要参与表达式运算就会发生整型提升

算术转换

long double

double

float

unsigned long int

long int

unsigned int

int

操作符的属性

复杂表达式的求值有三个影响的因素。

1. 操作符的优先级

2. 操作符的结合性(从左到右或者从右到左)

3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hey pear!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值