第五章 C语言操作符(预习笔记)

这篇博客详细介绍了C语言中的十大操作符,包括算术、移位、位、赋值、单目、关系、逻辑、条件、逗号表达式以及下标引用、函数调用和结构成员等。同时,还探讨了表达式的求值过程,如隐式类型转换、算术转换和操作符属性。
摘要由CSDN通过智能技术生成

目录

一.十大操作符详解

(一)算术操作符

(二)移位操作符

(三)位操作符

(五)单目操作符

(六)关系操作符

(七)逻辑操作符

(八)条件操作符

(九)逗号表达式

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

二.表达式求值

(一)隐式类型转换

(二)算术转换

(三)操作符属性 



一.十大操作符详解

(一)算术操作符

        对2个操作数进行算术运算。注:操作符也被为运算符

(1)加法:+
     有2个操作数;9+9;
(2)减法:-
(3)乘法:*
(4)除法:/,两个整数除,得到整数(商);带小数点除,值为小数
(5)取模(取余):%,计算整除后的余数;

1.%只能用于整数取余,且两侧操作数必须是整数,返回值是余数(整数);

2.整数类型和浮点数相互打印输出,会变为0

 3.整数类型赋给浮点数类型,末尾加.0;小数类型赋给整数类型,去小数

 4.除%的4个操作符,两侧操作数都为整数执行整数算术,至少有一个操作数为浮点数,则进行浮点数除法;

         注:操作数:操作符左右两侧的参数

扩展:%f %lf,默认打印小数点后6位

(二)移位操作符

扩展:2进制位知识补充

        数值的表现形式有多种:

  • 数值12

        10进制表示:12

        8进制表示:14

        16进制:c

        2进制:1100

以上本质数值都是12。

        整数的2进制表现形式分为3种:

(1)原码

(2)反码

(3)补码

#include<stdio.h>
int main()
{
	//按照一个数的正负,直接写出它的二进制表示形式得到的就是原码
	//
	//正数
	//正数的原码、反码、补码是相同的
	//负数的原码、反码、补码要经过计算的
	//反码是原码的符号位不变,其他位按位取反,就是反码
	//补码是反码+1
	//整型占4个字节(32bit)
	//00000000000000000000000000001010 - 原码
	//00000000000000000000000000001010 - 反码
	//00000000000000000000000000001010 - 补码
	int a = 10;
	int b = -10;
	//有符号数最高位是0表示正数,最高位是1表示负数;
	//10000000000000000000000000001010 - 原码
	//11111111111111111111111111110101 - 反码
	//11111111111111111111111111110110 - 补码

	//11111111111111111111111111110110 - 补码
	//10000000000000000000000000001001
	//10000000000000000000000000001010 - 原码 


	return 0;
}

注:内存中存储的是补码,因此移位移的是二进制中的补码,打印出来的是原码

补码-原码:

方法一:符号位不变,取反+1(一模一样),得到原码;

方法二:-1,符号位不变,取反,先得反码,再得原码;

1.<<,左移操作符
2.>>,右移操作符

注:移位操作符的操作数只能是整数。移位移的是整数的二进制位(补码);


int num=1;
num<<1;  左移一位
num<<1.5;//error

(1)左移操作符<<

  • 正数左移
#include<stdio.h>
int main()
{
	int a = 10;
	int b = a << 1;
	//00000000000000000000000000001010 -a的补码
	//00000000000000000000000000010100 -表达式a<<1的值,即a左移一位的值
	//移位规则:补码,左边抛弃,右边补0
	printf("%d\n", b);
	printf("%d\n", a);
	//a的值不变,知识表达式a<<1的值变成了20
	return 0;
}

  •  负数左移:
#include<stdio.h>
int main()
{
	int a = -10;
	//10000000000000000000000000001010
	//11111111111111111111111111110101
	//11111111111111111111111111110110 - 补码
	//
	int b = a << 1;
	//
	//11111111111111111111111111101100 - b的补码
	//10000000000000000000000000010011
	//10000000000000000000000000010100 - b的原码
	//
	printf("b=%d\n", b);//-20
	printf("a=%d\n", a);

	return 0;
}

 总结:左移数有乘2的现象;

(2)右移操作符>>

        移位规则:
        首先右移运算分两种:
                1. 逻辑移位
                左边用0填充,右边丢弃
                2. 算术移位(常用)
                左边用原该值的符号位填充,右边丢弃
         取决于编译器,一般是算术右移
扩展:-1的补码全是1
#include<stdio.h>
int main()
{
	int a = -1;
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111  a的补码
	//
	int b = a >> 1;
	//算术右移:11111111111111111111111111111111 -1
	//逻辑右移:
	//01111111111111111111111111111111 b的补码
	//00000000000000000000000000000000
	//00000000000000000000000000000001 b的原码  1
	printf("%d\n", b);
	printf("%d\n", a);

	return 0;
}

注:不能移动负数位, 这个是标准未定义的(编译器识别不了),移位数量应在有效范围内。
int a=1;
a>>-1;  //error

(三)位操作符

1.& //按位与
计算规则:对应的二进制位有0,则为0,两个同时为1,才为1
2.| //按位或
计算规则:对应的二进制位有1则为1,两个同时为0则为0
3.^ //按位异或
计算规则:对应的二进制位相同为0,相异为1

注:他们的操作数必须是整数,也是针对二进制位进行计算的(补码)。

        实例操作:

//五.位操作符的作用演示
//& - 按2进制位与
//对应的二进制位有0,则为0,两个同时为1,才为1
// 
//^ - 按2进制位异或
//对应的二进制位:相同为0,相异为1
// 
//按2进制位或
//对应的二进制位有1则为1,两个同时为0则为0
#include<stdio.h>
int main()
{
	int a = 3;
	//00000000000000000000000000000011
	int b = -5;
	//10000000000000000000000000000101
	//11111111111111111111111111111010
	//11111111111111111111111111111011 -补码
	
	int c = a & b;
	//00000000000000000000000000000011-a的补码
	//11111111111111111111111111111011-b的补码
	//00000000000000000000000000000011-c的补码
	
 	int d = a | b;
	//00000000000000000000000000000011
	//11111111111111111111111111111011
	//11111111111111111111111111111011
	
    int e = a ^ b;
	//00000000000000000000000000000011
	//11111111111111111111111111111011
	//11111111111111111111111111111000
	//11111111111111111111111111110111
	//10000000000000000000000000001000
	//-8
	printf("%d\n", c);  //c=3
	printf("%d\n", d);  //d=-5
	printf("%d\n", e);  //e=-8
 
	return 0;
}

扩展:一道变态的面试题:

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

#include<stdio.h>
int main()  //方法1
{
	int a = 3;
	int b = 5;

	//int tmp = 0;//临时变量方法
	//printf("%d %d\n", a, b);
	//tmp = a;
	//a = b;
	//b = tmp;
	//printf("%d %d\n", a, b);

	//a = a + b;  //算术搞定
	//b = a - b;
	//a = a - b;  //数太大溢出,一个不溢出,2个加起来溢出
	//printf("%d %d\n", a, b);
 
	a = a ^ b;  //位操作符搞定
	b = a ^ b;
	a = a ^ b;
	printf("%d %d\n", a, b);//没有产生进位


	return 0;
}

(四)赋值操作符

赋值操作符
=

复合赋值操作符(对自己进行操作)
1.+=   
//  a+=1等价于 a=a+1;
2.-=
3.*=
4./=
5.%=
....
实现自加1的操作;
a=a+1;
a++;
++a;
a+=1;
以上4个都等价;
#include<stdio.h>
 
int main()
{
	int a = 10;
	a = a + 5;
	a += 5;
	
	int b = 12;
	b = b >> 1;
	b >>= 1;

	return 0;
}

(五)单目操作符

单目操作符
操作数只有一个;
1.!           逻辑反操作
2.-           负值
3.+           正值
4.&           取地址
5.sizeof      操作数的类型长度(以字节为单位)
6.~           对一个数的二进制按位取反
7.--          前置、后置--
8.++          前置、后置++
9.*           间接访问操作符(解引用操作符)
10.(类型)       强制类型转换

1.! 逻辑反操作

//1.!   逻辑反操作
#include<stdio.h>
int main()
{
	//C语言中0表示假,非0表示真
	int flag = 0;
	//if (flag)//flag如果为真,做.....
	//{
	//	printf("hehe\n");
	//}
	if (!flag)
	{
		printf("hehe\n");
	}

	printf("%d\n", flag);
	printf("%d\n", !flag);

	
	return 0;
}

 补充:布尔类型

补充一下:布尔类型
//C99中引入的
//布尔类型就是用来表示真假的类型
//
#include<stdio.h>
#include <stdbool.h>
//实例
//bool is_leap_year(int y)
//{
//	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
//		return true;
//	else
//		return false;
//}
//
int main()
{
	_Bool flag = true;  //类型值只有 true false,本质上和0 1差不多
	if (flag)
	{
		printf("hehe\n");
	}

	return 0;
}

 2.- +操作符

1.-
把正数变负数;
2.+
基本用不上;

作用就是正负数转化;
#include<stdio.h>
 
int main()
{
	int a = -10;
	printf("%d\n", a); //-10
	printf("%d\n", -a); //10
	return 0;
}

扩展:有符号、无符号数

无符号数表示正数,补码最高位不作为符号位

#include<stdio.h>
 
int main()
{
	unsigned int num = -10;
	printf("%u\n", num);//无符号数用%u输出
	//补码最高位不是符号位,输出直接按数值输出
	//4294967286
	return 0;
}


注:
signed int a=10;
int a=10;
两者等价

3.取地址符&和间接访问符*一起使用(一般)

&
取出一个对象的在内存中的地址
*
通过解引用来找到对应的变量
#include<stdio.h>
 
int main()
{
	int a = 10;
	printf("%p\n", &a);
	int* pa = &a;

	char ch = 'w';
	char* pc = &ch;
	
	char arr[10] = { 0 };
	char* p2 = arr;
	char* p3 = &arr[0];

	char* p = "abcdef";//字符串赋给指针变量给的是a的地址
	printf("%p\n", p);
	printf("%c\n", *p);
	*pa = 20;//解引用操作,通过pa找到a
	printf("%d\n", a);
	return 0;
}

 4.sizeof

//5.sizeof
// /函数调用的时候,要写()
//但是sizeof后边的括号可以省略(计算类型时不可以),说明sizeof不是函数
//根据类型报
#include<stdio.h>
int main()
{
	//int a = 10;
	//printf("%d\n", sizeof(a));
	//printf("%d\n", sizeof a);//ok
	//printf("%d\n", sizeof(int));
	//int arr[10] = {0};
	//printf("%d\n", sizeof arr);//ok
	//printf("%d\n", sizeof(arr));//ok
	//printf("%d\n", sizeof(int[10]));//ok,int arr[10]的类型是 int[10]

	int a = 10;
	short s = 5;
	printf("%d\n", sizeof(s = a + 3)); //2,sizeof的表达式不参与计算,只考虑s,是2个字节
	printf("%d\n", s);  //5

	return 0;
}

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

//~ 按位取反,把补码二进制位(包括符号位)都取反,只针对整数
//00000000000000000000000000000000
//11111111111111111111111111111111 - 按位取反,补码是全1
//原码就是-1
#include<stdio.h>
int main()
{
	int a = 0;
	printf("%d\n", ~a);//-1

	return 0;
}
//& | ^ >> << ~
// 对二进制位的操作
#include<stdio.h>

int main()
{
	int a = 9;
	//00000000000000000000000000001001
	//00000000000000000000000000010000      1<<4
	//00000000000000000000000000011001
	//
	//把a的二进制中第5位改成1
	a |= (1<<4);
	printf("%d\n", a);//25

	//把a的二进制中的第5位改回来,变成0
	//00000000000000000000000000011001
	//11111111111111111111111111101111
	//00000000000000000000000000001001

	a &= (~(1 << 4));
	printf("%d\n", a);//9

	return 0;
}

6.

(六)关系操作符

>
>=
<
<=
!=   用于测试“不相等”
==      用于测试“相等”

(七)逻辑操作符

&&     逻辑 与
||     逻辑 或

(八)条件操作符

exp1 ? exp2 : exp3

(九)逗号表达式

        逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
exp1, exp2, exp3, …expN
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?
//代码2
if (a =b + 1, c=a / 2, d > 0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{        
 //业务处理
        a = get_val();
        count_val(a);
}
如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a>0)
{
         //业务处理
}

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

1. [ ] 下标引用操作符
2. ( ) 函数调用操作符
3.访问一个结构的成员
  . 结构体.成员名
  -> 结构体指针->成员名

1. [ ] 下标引用操作符

操作数:一个数组名 + 一个索引值
int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符。
[ ]的两个操作数是arr和9。
2. ( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
#include <stdio.h>
 void test1()
 {
 printf("hehe\n");
 }
 void test2(const char *str)
 {
 printf("%s\n", str);
 }
 int main()
 {
 test1();            //实用()作为函数调用操作符。
 test2("hello bit.");//实用()作为函数调用操作符。
 return 0;
 }
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;
}

二.表达式求值

        表达式求值的顺序一部分是由操作符的优先级和结合性决定。 同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。

(一)隐式类型转换

(二)算术转换

(三)操作符属性 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值