dedecms 网站安全设置,专业做网站建设公司有哪些,沈阳网站优化怎么做,北京网站名称注册证书目录
1.操作符的分类
2.原码、反码和补码
3.移位操作符
3.1 左移操作符
3.2 右移操作符
4.位操作符
4.1 按位与
4.2 按位或|
4.3 按位异或^
编辑 4.4 按位取反~
4.5 应用题
4.5.1 题目#xff1a;不能创建临时变量#xff0c;实现两个整数的交换
4.5.2 …目录
1.操作符的分类
2.原码、反码和补码
3.移位操作符
3.1 左移操作符
3.2 右移操作符
4.位操作符
4.1 按位与
4.2 按位或|
4.3 按位异或^
编辑 4.4 按位取反~
4.5 应用题
4.5.1 题目不能创建临时变量实现两个整数的交换
4.5.2 题目求一个整数存储在内存中的二进制中1的个数
4.5.3 题目写一个代码判断n是否为2的次方数
4.5.4 二进制位置0或者置1
5.单目操作符
6.逗号表达式
7.下标访问[ ]、函数调用( )
7.1 [ ] 下标引用操作符
7.2 函数调用操作符
8.结构成员访问操作符
8.1 结构体
8.1.1 结构体的声明
8.1.2 结构体的定义和初始化
9.操作符的属性优先级和结合性
9.1 优先级
9.2 结合性
10.表达式求值
10.1 整型提升
10.2 算数转换
10.3 问题表达式解析
10.3.1 表达式1
10.3.2 表达式2
10.3.3 表达式3
10.3.4 表达式4
10.3.5 表达式5 1.操作符的分类
操作符可以分为很多类
2.原码、反码和补码
整数的二进制表示方法有三种原码、反码和补码
有符号整数的三种表示方法均有符号位和数值位两部分二进制序列中最高位的一位是被当做符号位剩余的都是数值位符号位都是用0表示“正”用1来表示“负”。
正整数的三码均相同
负整数的三种表示方法不同。
原码直接翻译成二进制的就是原码
反码符号位不变其他位次依次取反
补码反码加1就得到补码
补码得到原码可以用——取反1的操作
对于整数来说数据存放内存中其实存放的是补码
3.移位操作符
移动的是存储在内存中二进制位即补码
为左移操作符
为右移操作符
3.1 左移操作符
规则左边遗弃右边补0
例如
#includestdio.h
int main()
{int a 10;int b a 1;printf(a%d\n, a);printf(b%d\n, b);return 0;
}
运行结果为 分析根据规则a不变其二进制表示为1010而b为a的基础上在最后加了一个0则b为10100
3.2 右移操作符
运算分为两种
1.逻辑右移左边用0填充右边丢弃
2.算数右移左边用原该值的符号位填充右边丢弃
右移到底采用哪一种方法取决于编译器通常是采用算数右移
4.位操作符
位操作符有四种:
1. 按位与
2.| 按位或
3.^ 按位异或
4.~ 按位取反
注意他们的操作数必须为整数
4.1 按位与
运算规则有0为0全1为1
例如
int main()
{int a 6;//00000000000000000000000000000110 -6的补码int b -7;//10000000000000000000000000000111 --7的原码//11111111111111111111111111111000 --7的反码//11111111111111111111111111111001 --7的补码//00000000000000000000000000000110 -6的补码//00000000000000000000000000000000 -之后因此为0int c a b;printf(c %d\n, c);return 0;
}
根据推算我们可以得到c为0则运行结果为 则可以知道推算结果正确。
4.2 按位或|
运算规则:有1为1全0为0
例如
int main()
{int a 6;//00000000000000000000000000000110 -6的补码int b -7;//10000000000000000000000000000111 --7的原码//11111111111111111111111111111000 --7的反码//11111111111111111111111111111001 --7的补码//00000000000000000000000000000110 -6的补码//11111111111111111111111111111111 -|之后//10000000000000000000000000000000//10000000000000000000000000000001 -因此为-1int c a | b;printf(c %d\n, c);return 0;
}
运行结果为 因此我们可以知道推算结果是正确的。
4.3 按位异或^
运算规则相同为0相异为1
例如
int main()
{int a 6;//00000000000000000000000000000110 -6的补码int b -7;//10000000000000000000000000000111 --7的原码//11111111111111111111111111111000 --7的反码//11111111111111111111111111111001 --7的补码//00000000000000000000000000000110 -6的补码//11111111111111111111111111111111 -^之后//10000000000000000000000000000000//10000000000000000000000000000001 -因此为-1int c a ^ b;printf(c %d\n, c);return 0;
}
运行结果为 4.4 按位取反~
与前三个不同的是~操作符是单目操作符
例如
int main()
{int a 0;printf(%d\n, ~a);//00000000000000000000000000000000//11111111111111111111111111111111//10000000000000000000000000000000//10000000000000000000000000000001//所以最终结果为-1return 0;
}
运行结果为 4.5 应用题
4.5.1 题目不能创建临时变量实现两个整数的交换
方法一
int main()
{int a 3;int b 5;//实现过程printf(交换前a %d, b %d, a, b);a a b;b a - b;a a - b;printf(交换后a %d, b %d, a, b);return 0;
}
运行结果为 这样看似是正确的但是我们需要注意的是int 类型是有范围的当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 b ^ b ^ a即b ^ b 0 0 ^ a a
4.5.2 题目求一个整数存储在内存中的二进制中1的个数
方法一结合原先分别列出一个数据的方法来进行求解
int count_bit_one(unsigned int n)
{int count 0;while (n){if ((n % 2) 1)count;n / 2;}return count;
}int main()
{int num 0;scanf(%d, num);int ret count_bit_one(num);printf(%d\n, ret);return 0;
} 需要注意的是我们要注意负数的情况因此在函数定义的时候应该为unsigned int
方法二运用操作符来进行解决
分析当n 1 1时 我们可以得出32位二进位中最后一个为1
int count_bit_one(unsigned int n)
{int i 0;int count 0;for (i 0; i 32; i){if ((n i) 1 1)count;}return count;
}int main()
{int num 0;scanf(%d, num);int ret count_bit_one(num);printf(%d\n, ret);return 0;
}
运行结果为 所以我们学习了操作符的知识后要学会把它们运用到常见的问题中 方法三
对第二种方法进行改进——
用n n (n - 1)来进行循环循环了多少次那么n中就有几个1此处省略证明过程有兴趣的可以举例进行验证
int count_bit_one(int n)
{int i 0;int count 0;while (n){n n (n - 1);count;}return count;
}int main()
{int num 0;scanf(%d, num);int ret count_bit_one(num);printf(%d\n, ret);return 0;
}
运行结果为 4.5.3 题目写一个代码判断n是否为2的次方数
分析2的次方数中只含有一个1
因为 n (n - 1) 是去掉一个1因此当 n (n - 1) 0 时此时满足题意。
该题省略代码过程。
4.5.4 二进制位置0或者置1
例题编写代码将13二进制序列的第五位修改为1然后再改回0 int main()
{int a 13;//00000000000000000000000000001101//00000000000000000000000000010000 -借助这个数来得到改为1的数//00000000000000000000000000011101 -改为1int n 5;a a | (1 (n - 1));printf(%d\n, a);//00000000000000000000000000011101//11111111111111111111111111101111 -之后就可以得到原来的数//00000000000000000000000000001101 -改为0a a ~(a (n - 1));printf(%d\n, a);return 0;
}
运行结果为 5.单目操作符
单目操作符常见的有| -- * - sizeof 类型
单目操作符的特点是只有一个操作数。
其中单目操作符时为取地址操作符在指针中运用广泛。
6.逗号表达式
逗号表达式从左到右依次执行整个表达式的结果是最后一个表达式的结果
为了比较好理解我们给出一个例子
int main()
{int a 1;int b 2;int c (a b, a b 10, a, b a 1);printf(%d\n, c);return 0;
}
算c的值的时候首先执行a b 的语句这里没有任何值的改变接着执行 a b 10此时a的值发生改变a的值变为12然后执行a的语句最后执行b a 1 的语句此时b 13因此最终c的值为13我们运行一下来进行检验—— 7.下标访问[ ]、函数调用( )
7.1 [ ] 下标引用操作符
操作数 一个数组名 一个索引值下标
int arr[10];//创建数组
arr[9] 10;//使用下标引用操作符
[ ]的两个操作数是arr和9
7.2 函数调用操作符
例如
int main()
{printf(hello\n);//就是函数调用操作符printf(%d \n, 1000);return 0;
}
操作数就是函数名和中的内容那么我们可以得出函数调用操作符最少有一个操作数函数名。
8.结构成员访问操作符
8.1 结构体
结构是一些值的集合这些值称为成员变量。结构的每个成员可以是不同类型的变量如标量、数组、指针甚至是其他结构体。
8.1.1 结构体的声明
struct 名字
{结构体内容
};
例如描述一个学生可以为
struct student
{char name[20];//名字int age;//年龄double score;//成绩
};
8.1.2 结构体的定义和初始化
通过以下的代码示例我们来了解一下结构体的定义和初始化
struct student
{char name[20];//名字int age;//年龄double score;//成绩
}s4, s5, s6;//第一种定义方式struct student s3;//第二种定义方式int main()
{int a;struct student s1 { zhangsan, 20, 98.50 };//第三种定义方式struct student s2 { lisi, 35, 91.98 };//初始化方式return 0;
}
其中第一种和第二种方法定义的变量为全局变量。 结构体方面的知识点在后续会有专门的补充今天我们先简单了解一下~ 9.操作符的属性优先级和结合性
这两个属性决定了表达式求值的计算顺序。
9.1 优先级
各种运算符的优先级是不一样的相邻操作符中优先级高的先进行计算。
例如
int main()
{int r 3 4 * 5;printf(%d\n, r);return 0;
}
在上述的操作符中‘*’的优先级大于‘’所以应该先计算4 * 5 这一部分。
关于优先级我们可以在网上搜索相应的规则和知识这里就不再赘述。
9.2 结合性
相邻的操作符的优先级相同的情况下由结合性来决定。
10.表达式求值
10.1 整型提升
C语言中整型算数运算总是至少以默认整型类型的精度进行的为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型这种转换称为整型提升。
例如
int main()
{char a 20;char b 130;char c a b;printf(%d\n, c);return 0;
}
此时就把a和b转换为了普通整型来进行运算。
意义CPU内的整型运算器ALU的操作数的字节长度和int相同也是CPU的通用寄存器长度。表达式中各种长度可能小于Int长度的整型值都必须先转换为unsigned int 或者Int才能送入CPU进行运算。
如何进行整型提升呢
1.有符号的整数提升是按照变量的数据类型的符号位来提升的
2.无符号整数提升高位补0
10.2 算数转换
算数转换讨论的就是类型大于等于整型类型的类型如long double、double、float、long int、int等类型的数据。
下面的层次为寻常算数转换
1 long double
2 double
3 float
4 unsigned long int
5 long int
6 unsigned int
7 int
为从下到上进行转换。
10.3 问题表达式解析
10.3.1 表达式1
a * b c * d e * f
在这个表达式中只能确定 * 的计算比 的早但是优先级并不能决定第三个 * 比第一个 早执行。
10.3.2 表达式2
c --c;
这时前一个c中存的数不确定是原来的还是--之后的。
10.3.3 表达式3
表达式过于复杂影响可读性。
例如
i i-- - --i * (i -3) * i i
经过运行我们可以发现在不同的编译器中所得到的结果不同这样代码本身就存在问题。
10.3.4 表达式4
int fun()
{static int count 1;return count;
}int main()
{int answer;answer fun() - fun() * fun();printf(%d\n, answer);return 0;
}
这时存在的问题是我们不知道fun( )所调用出来的数赋值在哪里。
10.3.5 表达式5
int main()
{int i 1;int ret (i) (i) (i);printf(%d\n, ret);printf(%d\n, i);return 0;
}
这时代码也存在问题我们不知道 ret 中 i 进行了几次自增。
在不同的编译器中所得到的结果也是不一样的。所以这个代码是存在问题的。 所以——即使我们知道了操作符的优先级和结合性我们写出的代码也是存在风险的因此我们最好不要写过于复杂的表达式既影响了可读性也容易出错。 今天就到这里我们下个知识点见~