除法注意点: / 除法 得到的是商
1.除法操作符的两个操作数都是整数的话,执行的是整数除法.用%d打印
2.除法操作符的两个操作数只要有一个浮点点数,执行的是小数除法.用%lf打印
% 取模(取余) 得到的是余数:
1.取模操作符的两个操作数必须是整数,返回的是整除之后的余数.
2.除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main() {
//printf("%lf\n", 10 / 3); //不能这么写,因为两个操作数都是整数,应该用%d
printf("%lf\n", 10 / 3.0);
printf("%d\n", 10 / 3);
}
移位操作符移动的是二进制的位
左移操作符: 左边丢弃,右边补0
数值的表示形式:
2进制,8进制,10进制,16进制
10进制的数据中,都是0-9的数字组成的
2进制的数据中,0-1的数字组成的
8进制的数据中,0-7的数字组成的
16进制的每一位是:
0~15
0 1 2 3 4 5 6 7 8 9 a b c d e f
比如:
表示数值10
1010----2进制
12-------8进制
10-------10进制
a---------16进制
数据的二进制表示:
整数的二进制表示形式有三种: 原码反,码,补码
原码:
把一个数按照正负直接翻译成二进制就是原码
最高位表示符号位,0表示正数,1表示负数
正整数的原码反码补码相同,
负整数的原码反码补码是要计算的
反码:
原码的符号位不变,其他位按位取反就是反码
补码:
反码+1
举例说明:
5,-5是整数,整数是存放在整型变量中的
一个整型变量是4个字节~32比特位
5:
原码 00000000000000000000000000000101
反码 00000000000000000000000000000101
补码 00000000000000000000000000000101
-5:
原码10000000000000000000000000000101
反码 11111111 11111111 11111111 11111010
补码 11111111 11111111 11111111 11111011
整数在内存中存储的是:二进制补码
4个比特位可以作为一个16进制数
例如:-5
补码 11111111 11111111 11111111 11111011
4个一组表示成16进制:
FF FF FF FB
正整数左移操作符举例说明:
3的二进制位:
00000000 00000000 00000000 00000011
向左移动一位,左边丢弃,右边补0
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
int a = 3;
//3的二进制位:(正数的原码反码补码相同)
//00000000 00000000 00000000 00000011
int b=a << 1;
//向左移动一位,左边丢弃,右边补0
//b是正数,原码反码补码相同
//00000000 00000000 00000000 00000110
//b也就是6
printf("%d\n", b);
printf("%d\n", a);
return 0;
}
负整数左移操作符举例说明:
原码------>补码:取反+1
补码------>原码:-1,取反 或者 取反+1
-3的二进制位左移一位:
由于整数在内存中存储的是补码,左移的时候实际上是将补码左移一位,右边补0.
首先求出-3的补码,左移补0之后得到的是结果的补码,还需要转换成原码,最后通过原码得出结果是多少
int main() {
int a =-3;
/*-3的二进制位:
10000000 00000000 00000000 00000011 -3的原码
11111111 11111111 11111111 11111100 -3的反码
11111111 11111111 11111111 11111101 -3的补码*/
//
int b=a << 1;
//-3的补码向左移动一位,左边丢弃,右边补0得到结果的补码
//11111111 11111111 11111111 11111010 b的补码
//11111111 11111111 11111111 11111001 b的反码
//10000000 00000000 00000000 00000110 b的原码 -6
printf("%d\n", b);
printf("%d\n", a);
return 0;
}
右移操作符:
1.>> 算术右移:
右边丢弃,左边用原来的符号来填充
2.>> 逻辑右移:
右边丢弃,左边直接用0来填充
右移的时候,到底采用的是算术右移还是逻辑右移,是取决于编译器的!!
由下面的代码可以看出,vs2019编译器采用的是算术右移.
int main() {
int a = -5;
int b = a >> 1;
//10000000 00000000 00000000 00000101
//11111111 11111111 11111111 11111010
//11111111 11111111 11111111 11111011
printf("b=%d\n", b);
//算术右移
//11111111 11111111 11111111 11111101
//10000000 00000000 00000000 00000010
//10000000 00000000 00000000 00000011 -3
printf("a=%d\n", a);
return 0;
}
int main() {
int a = 3;
int b = -5;
int c = a & b;
//00000000 00000000 00000000 00000011 3的补码
//10000000 00000000 00000000 00000101 -5的原码
//11111111 11111111 11111111 11111010 -5的反码
//11111111 11111111 11111111 11111011 -5的补码
//00000000 00000000 00000000 00000011 3的补码
//11111111 11111111 11111111 11111011 -5的补码
//00000000 00000000 00000000 00000011 a&b的补码,由于是正整数,原码也是这个
printf("%d\n", c); //3
int d = a | b; //按位或
//00000000 00000000 00000000 00000011 3的补码
//11111111 11111111 11111111 11111011 -5的补码
//11111111 11111111 11111111 11111011 a|b的补码,可以发现与-5的补码一样,所以他的原码数值等于-5
printf("%d\n", d);
int e = a ^ b; //按位异或--对应的二进制位相同为0,相异为1
//00000000 00000000 00000000 00000011 3的补码
//11111111 11111111 11111111 11111011 -5的补码
//11111111 11111111 11111111 11111000 a^b的补码
//11111111 11111111 11111111 11110111 补码-1
//00000000 00000000 00000000 00001000 取反得到原码,结果为-8
printf("%d\n", e);
}
交换a和b的值:
方法一:创建临时变量
int main() {
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
int tmp = 0;
tmp = 0;
tmp = a;
a = b;
b = tmp;
printf("交换后:a=%d b=%d\n", a, b);
}
方法二:不创建临时变量
存在潜在风险,当数字过大时,加和之后可能超出整数的最大范围,有一定局限性
int main() {
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
方法三:使用异或操作符,不创建临时变量
注意两个公式:
a^a=0
0^a=a
3^ 3^5=5
011 3
011 3
000 3^3
101 5
101 3^ 3^5结果5
353=5
异或支持交换律的
异或只能用于整数操作
异或只会产生0和1,不会进位出现2,所以永远不会溢出
int main() {
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b; //b=a^b^b=a^0=a
a = a ^ b; //a=a^a^b=0^b=b
printf("交换后:a=%d b=%d\n", a, b);
}
编写代码实现:求一个整数存储在内存中的二进制中1的个数
思路点拨:
int main() {
int a = 11;
a & 1;
//一个整数存储在内存中的二进制中1的个数
//只要每次右移,每次和1按位与得到最后一位看一下是不是1
a = a >> 1;
//00000000 00000000 00000000 00001011
//00000000 00000000 00000000 00000001
//发现:最低位和1按位与,还是原来的数字
//如果想要得到这个数的最低位是几,只要和1按位与就可以了
//结果
//00000000 00000000 00000000 00000001
}
int main() {
int a = 3;
a = a + 3;
a += 3;
a = a ^ 5;
a ^= 5;
a = a >> 3;
a >>= 3;
}
区分赋值和初始化:
int main() {
int a = 3;//创建并初始化
a = 5;//赋值
return 0;
}
int main() {
int flag = 5;
if (flag) { //flag为真做什么
}
if (!flag) { //flag为假做什么
}
return 0;
}
&取地址操作符
int main() {
int a = 10;
&a;//&取地址操作符
int arr[10];
&arr;//取出数组的地址
}
解引用操作符(间接访问操作符)
*
int main() {
int a = 10;
int* p=&a; //取地址操作符 p里面存的是a的地址
*p = 20; //解引用操作符(间接访问操作符)
int arr[10];
&arr; //取出数组的地址
return 0;
}
sizeof
int main() {
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a); //变量求长度时的小括号可以不写,但是int必须写
printf("%d\n", sizeof(int));
int arr[10] = { 0 };
printf("%d\n", sizeof(arr)); //数组的长度
printf("%d\n", sizeof(arr[0])); //数组元素的长度
int sz = sizeof(arr) / sizeof(arr[0]); //数组元素的个数
printf("%d\n", sz);
return 0;
}
int main() {
int a = 0;
//00000000 00000000 00000000 00000000
//~a:按位取反
//11111111 11111111 11111111 11111111 补码(内存里面的字都是补码)
//11111111 11111111 11111111 11111110 反码
//00000000 00000000 00000000 00000001 原码 -1
printf("%d\n", ~a); //-1
}
int main() {
int b = 3;
//00000000 00000000 00000000 00000011 b
//如何把上面的数字倒数第四位变成1?
//00000000 00000000 00000000 00000011 b
//用b|
//00000000 00000000 00000000 00001000 (1 << 3)
b |= (1 << 3);
//00000000 00000000 00000000 00001011 b=11
printf("%d\n", b); //11
//如何将下面的数字
//00000000 00000000 00000000 00001011
//倒数第四位还原成0??
//
// 0&1=0 1&1=1
// 所以将原数字与下面的数字按位与,就可以将倒数第四位还原成0
//11111111 11111111 11111111 11110111 这个数字怎么表示呢?
//我们发现它刚好是00000000 00000000 00000000 00001000 (1 << 3)取反可以得到
//
b &= (~(1 << 3));
printf("%d\n", b); //3
return 0;
}
小知识点:
scanf读取失败的时候返回-1
原码
10000000 00000000 00000000 00000001
反码
11111111 11111111 11111111 11111110
补码
11111111 11111111 11111111 11111111
~按位取反之后:全0
00000000 00000000 00000000 00000000
此时就变成:
while(0)不进入循环,scanf读取失败
前置++ --:在使用之前++ - -
后置++ --:在使用之后++ - -
int main() {
int a = 10;
int b = a++;
printf("%d\n", a);
printf("%d\n", b); //后置++,先使用,再++
//相当于int b=a;a=a+1;
}
int main() {
int a = 10;
printf("%d\n", a++);//先使用,后++
printf("%d\n", a);
}
int main() {
int a = 10;
printf("%d\n", ++a); //先++,再使用
printf("%d\n", a);
}
(类型) 强制类型转换
仅仅是临时改变数据类型的一个状态
int main() {
float a = 3.14f;
int b = (int)a; //强制性类型转换
return 0;
}
sizeof()和数组
1.sizeof()内部单独放一个数组名,表示整个数组,所以(1)(3)处的值为40,10
2.注意:数组在传参的时候,实际上是传过去首元素的地址
void test1(int arr[]) //整形的地址放到整形的指针里面,int本质是int*,存放地址,指针变量的大小都是四个字节或者八个字节
{
printf("%d\n", sizeof(arr));//(2)X86环境下指针的大小是4,X64环境下指针的大小是8
}
void test2(char ch[]) //char本质是char*,存放地址
{
printf("%d\n", sizeof(ch));//(4)X86环境下指针的大小是4,X64环境下指针的大小是8
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));//(1) 计算的是整个数组的大小:40
printf("%d\n", sizeof(ch));//(3) 计算char类型的数组大小:10
test1(arr);
test2(ch);
return 0;
}
&& 逻辑与 并且的意思 只关注真假
| | 逻辑或 或者的意思 只关注真假
& 按位与 二进制位进行计算
| 按位或 二进制位进行计算
int main() {
int a = 3 && 5;
int b = 3 && 0;
printf("%d\n", a);
printf("%d\n", b);
int c = 1 || 0;
int d = 0 || 0;
printf("%d\n", c);
printf("%d\n", d);
return 0;
}
&& 操作符左边为假,右边不再计算
| | 操作符左边为真,右边不再计算
举例说明:
int main() {
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++; //0&&...a=0,后面不用计算
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
return 0;
}
int main() {
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ && ++b && d++; //1&&3&&4
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//2 3 3 5
return 0;
}
int main() {
int i = 0, a = 1, b = 2, c = 3, d = 4;
i = a++ || ++b || d++; //1||...或运算,左边有一个1,右边不用计算
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//2 2 3 4
return 0;
}
int main() {
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ || ++b || d++; //0||2...右边不用计算
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);//1 3 3 4
return 0;
}
这篇文章的内容你是否有所收获呢?小伙伴们,记得点赞收藏博客,关注后续的C语言操作符(下)内容哦~