初始C语言(操作符详解)

点击查看简单基础版操作符介绍

1.❤️算术操作符

  • 加法(+)、减法(-)、乘法(*):计算和正常的数学运算一样,整数和小数都没有任何问题
  • 除法(/):
    • 两个操作数都是整数,执行整数除法,如果有一个是浮点类型的,就执行浮点数除法
    • 除数是不能为0的
  • 取余(%)两边只能放整数

2.❤️赋值操作符

  • 简单赋值
    • =          a = 3;        把3赋值给a
  • 运算之后再赋值(复合赋值符)
    • 理解:+=       a+=3;        a+3后的值再赋给a,相当于a = a + 3;
    • +=、-=、*= 、/=、%=、>>=、<<=、&=、|=、^=

3.❤️关系操作符

  • 判断大小
    •   < 小于      > 大于      >=大于等于      <=小于等于
  • 判断是否相等
    •   ==相等      !=不等

4.❤️单目操作符

  • ! 反逻辑操作符
    • 会把真的变成假,假的变成真
      • 补充,布尔类型(C99中引入,部分编译器支持,包括VS2019)-----表示真假的类型
#include <stdbool.h>          //头文件
_Bool flag = true;        //赋值,赋值的选项只有true和false两种选择
_Bool flag = false;

return false;         //返回的也只有这两种选项
  • 前后置++/- -
    • 前后置的区别就是,是先使用还是先变化
    • 比如前置++就是先自增1,再使用加过后的这个变量的值
    • 会有副作用:会作用于自身
#include <stdio.h>
int main()
{
	int a = 10;
	int b = ++a;     //b = 11  a = 11
	int c = a + 1;   //c = 11   a  = 10    
	return 0;
}

a+1和++a都可以实现打出这个数+1的效果,但是a+1是不会改变a本身的数值的,也就是所是不会作用于自身的

  • &取地址和*解引用
    • &取地址就是把某一个变量的地址取出来
    • *解引用就是根据地址去找那个变量从而直接修改变量的值
    int a = 3;
	int* pa = &a;
	*pa += 3;       //*pa相当于a
	printf("%d\n", *pa);
	printf("%d\n", a);    //因为是作用在a上的值修改,所以可以直接打印a

    *(int *)地址——————指针是不能强制转换的,,相当于入室盗窃,不可取 

    char* p = "abcdef";     //这个是字符串字面量,传进去的是首个元素的地址
  • sizeof操作数的类型长度(以字节为单位)———可以求变量(类型)所占空间的大小
  • 返回的是无符号的整型(unsigned int)
    【1】数组和一般变量
    😊大小计算以及一些是否可以省略括号的问题:
#include <stdio.h>
int main()
{
	int a = 3;
	int arr[10];
	printf("%d", sizeof(a));       //ok
	printf("%d", sizeof(int));    //ok
	printf("%d", sizeof(arr));    //ok
	printf("%d", sizeof(int [10]));    //ok
	printf("%d", sizeof a);       //ok    //如果是求变量的大小,可以省略括号
	//printf("%d", sizeof int);     //error    //如果是求类型的大小,则不能省略括号
	return 0;
}

😊sizeof的特点

#include <stdio.h>
int main()
{
	int a = 0;
	short s = 5;
	printf("%d\n", sizeof(s = a + 3));    //a+3是整型4个字节,放在短整型2个字节里面会发生截断
	printf("%d\n", sizeof(s));    //sizeof内部的表达式不计算,s未被赋值,依旧是5
	return 0;
}

【2】sizeof和数组
😊大小计算

#include <stdio.h>
void test1(int arr[])
{
	printf("%d\n", sizeof(arr));     //4、8  
}
void test2(char* ch[])
{
	printf("%d\n", sizeof(ch));   //4、8,因为接收的是地址,指针变量的大小要么4要么8,取决是32位还是64位环境
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));   //输出40,计算的是整个数组的大小
	printf("%d\n", sizeof(ch));    //输出10,计算的是整个数组的大小
	test1(arr);
	test2(ch);
	return 0;
}

  • 下标引用操作符[ ]
    • 在一个数组里面要访问某一个元素就要用这个
    • 如arr[10],访问的是在arr数组中,下标为9的元素,操作数是arr和10
  • 函数调用操作符
    • strlen(“abcdef");      操作数是strlen和"abcedf",即第一个是操作数是函数名,剩余的操作数就是传递给函数的参数
    • 函数调用操作符,最少有一个操作符,即函数里面没有参数的时候
  • 结构体访问操作符
    • 结构体变量.成员名
    • 结构体指针->成员名
#include <stdio.h>
struct book
{                               //如何创建一个类型
	char name[10];
	char author[10];
	int price;
};
int main()
{
	struct book b1 = { "《活着》","余华",45 };
	struct book* pb = &b1;
	printf("%s %s %d\n", b1.name, b1.author, b1.price);
	printf("%s %s %d\n", (*pb).name,(*pb).author, (*pb).price);   //用指针
	printf("%s %s %d\n", pb->name, pb->author, pb->price);
	return 0;
}
  • ~ 取反操作符:包括符号位都要取反
  • +正值(基本没什么用)
  • -负值,把正数改成负数,负数改成正数
  • (类型)强制类型转换
#include <stdio.h>
int main()
{
	int a = 3.14;       //3.14是浮点型,放到整型里面会丢失数据,但非要放就需要强制类型转换
	printf("%d",a);    //printf和scanf是以某种格式输出/输入的意思,不需要强制类型转换,已经自身带领隐性的意味了
	return 0;
}

5.❤️条件操作符(三目操作符)

  • 表达式1?表达式2:表达式3

如果表达式1成立,就输出表达式2的结果,如果表达式1不成立,就输入表达式3的结果

6.❤️位操作符(操作数只能是整数)

6.1 前情提要

【1】进制

位操作符,这个究竟是什么?------二进制位

计算机中有许多进制的位,如常见的二进制、八进制、十六进制等,我们看到的数值往往是以十进制的形式展现的,每一个数值可以用不同的进制表示,如

1111——二进制位                  表示的都是一个数。表现形式不同罢了
17——八进制位
15——十进制位
F——十六进制位

【2】2进制三种表现形式解析

而计算机中二进制的表现形式一共有三种:原码、反码、补码

  • 原码就是根据数值的大小和正反直接写出的32位或者64位二进制
    原码的最高位是符号位,如果是0就表示是正数,如果是1就表示是负数
  • 反码就是原码除了符号位,其他位按位取反
  • 补码就是反码+1

正数(包括0)的原码、反码、补码相同,负数的则需要计算

内存中存的是补码,所以移位什么的,移的是补码。

打印是按原码来

【3】unsigned和signed

unsigned:整数在内存中以二进制的补码存储,最高位为符号位,这个可以实现最高位成为计算位,不是符号位——————无符号位

signed:因为是默认数值存储时有符号位的,所以基本省略掉了——————有符号位

6.2 &按位与

对应的二进制位有0,则为0,除非两个数都是1,才为1

6.3 | 按位或

对应的二进制位,有1就为1,除非两个数都是0,才为0

6.4 ^按位异或

对应的二进制位,相同为0,相异为1

7.❤️移位操作符(操作数只能是正整数)

左移操作符:左边抛弃,右边补0
      因为二进制的每一位都是2的指数幂,所以左移1位后,只要没有发生数据溢出,值就会变为原来的两倍。其他进制同理

右移操作符:左边用原该位的符号位填充,右边丢弃
      二进制数右移1位后,值会变为原来的二分之一。其他进制同理

int a = 1<<4;    //把1向左移动4位的数,赋值给a   //左移操作符
int b = 1>>4;    //把1向右移动4位的数,赋值给b   //右移操作符

int num = 10;
int b = num<<1;     //num本身的值没有被改变

8.❤️逻辑操作符

&& 逻辑与     ||逻辑或
区分:& 按位与     |按位或

特点(坑点):
&&操作符:左边为假,右边无须计算
||操作符:左边为真,右边无须计算

逻辑操作符可以产生短路的效果

9.❤️逗号表达式

形式:表达式1,表达式2,表达式3……表达式n

含义:用逗号隔开的多个表达式

特点:从左向右依次执行,整个表达式的结果就是最后一个表达式的结果

#include <stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = 0;
	if (a = b + 1, c = a / 2, b > 0)    //依次执行,前面如果有涉及值的修改,也会影响判断部分,真正起到判断部分的,是最后一个表达式,即b>0
	{
		printf("大悲咒");
	}
	return 0;
}

10.❤️表达式求值

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

10.1 表达式求值的顺序

✨如何判断计算顺序【注意:相邻的概念】

  • 首先确定优先级,相邻操作符按照优先级高低计算
  • 然后优先级相同的情况下,结合性才会起作用
  • 最后看是否控制求值顺序

✨一些问题表达式

虽然通过上述方法可以确定计算顺序,但是这个计算顺序并不是唯一的,下面介绍一些问题表达式

第一种
a* b + c * d + e * f;  优先级只能确定相邻操作符的顺序,无法确定第三个*是否比第一个+早执行

第二种
c + --c; 无法确定c是什么时候准备好的,是在减减前就准备好了
第三种  非法表达式
#include <stdio.h>
int main()
{
	int i = 10;
	i = i-- - --i * (i = -3) * i++ + ++i;
	printf("i = %d\n", i);
	return 0;
}

第四种
#include <stdio.h>
int fun()
{
	static int count = 1;
	return ++count;
}
int main()
{
	int answer;
	answer = fun() - fun() * fun();   //只能确定先算乘法,再算减法,但是函数的调用顺序是无法确定的
	printf("%d\n", answer);
	return 0;
}

😊总结
优先级高并不代表表达式执行顺序优先,就像a+f+bc,它可以是先a+f再加bc,它也可以先a+f再加bc,也可以是bc再加a。

没法确定唯一计算路径的就是问题表达式,我们要通过括号去避免

10.2 类型转换

【1】隐性类型转换

为什么会出现隐性类型转换这种情况?

✨因为表达式的整型运算要在CPU的整型运算器里面进行,而里面运算的操作数的字节长度一般是整型的字节长度。

    即C语言的整数算术运算默认是以整型类型的精度来进行的

✨但是字符和短整型的字节长度是小于int类型的,为了达到上述所提到的要求,就需要进行整型提升,即在执行运算前,要把把字符类型、短整型转化成int类型或者unsigned int类型后,才送去CPU执行运算操作

隐性类型转换是如何进行的

char a = 1;    b和c先被提升为普通整型,然后再执行加法运算
char b = -1;
a = b + c;       执行完加法运算之后,结果将被截断,然后被存储到a中
  • 概况
    • b和c先被提升为普通整型,然后再执行加法运算
    • 执行完加法运算之后,结果将被截断,然后被存储到a中
  • 如何被提升为普通整型
    • a为1,而且是char类型只有8个比特位,写成2进制的补码是00000001,整型提升之后,因为是有符号的char,高位补充符号位0,即000000000000000000000001
    • b为-1,补码是11111111,因为是有符号的char,高位补充符号位1,所以结果是11111111111111111111111111111111

【2】寻常算术转换

使用场景:某个操作符的各个操作数属于不同的类型

解决方法其中一个操作数的转换为另一个操作数的类型,否则操作(运算)无法进行

  • ong double
  • double
  • float
  • unsigned long int
  • long int
  • unsigned int
  • int

具体:排名较低的那个类型要首先转换为另外一个操作数的类型后执行运算

               就高不就低

✨转换要合理,如果你强行给整型类型赋上一个浮点数,会发生精度的丢失

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值