C语言学习过程总结(11)——操作符详解

本文介绍了二进制、八进制、十进制和十六进制的概念,展示了它们之间的转换方法,并详细讲解了有符号整型的原码、反码和补码,以及操作符分类、移位、位操作、单目操作、结构体和数组的使用。后续将讨论操作符使用注意事项和指针知识。
摘要由CSDN通过智能技术生成

一、二进制和进制转换

在开始操作符的学习之前我们先学习一下进制的知识,因为操作符中会涉及到位移操作符(移动二进制的位)

我们常听到二进制、八进制、十进制、十六进制,这些都是什么意思呢?

例15为例

二进制:1111

八进制:17

十进制:15

十六进制:F

生活最常见的就是十进制,满十进一就是十进制的规则,同理二进制就是满二进一,八进制就是满八进一以此类推

1.进制的相互转换 

1111和17两个表达在某种意义上就是表达一样的数字,分别用二进制和八进制去表示了十进制中的15,这样转换的前提是两者表达的数字大小一样,那在不同进制下的数字是怎么体现出其大小的呢?

权重

百位十位个位
十进制的位23
权重10^210^110^0
权重值100101
求值                    1*100  +  2*10  +  3*1    =123

同理在二进制下 

二进制的位101
权重2^32^22^12^0
权重值8421
求值                    1*8  +  1*4  +  0*2  +  1*1    =13

1.十进制转二进制

例:十进制125转化为二进制是多少

125 / 2 = 62 余1

62 / 2 = 31 余0

31 / 2 = 15 余1

15 / 2 = 7 余1

7 / 2 = 3 余1

3 / 2 = 1 余1

1 / 2 = 0 余1

由下而上所得的余数就是10进制转换为2进制

所以十进制下125转换为二进制就是1111 1101

2.二进制转八进制和十六进制

二转八:

八进制数由0~7组成,我们知道7用二进制表示是111,也就是说,八进制中的每一位数最多只需要3位的二进制数来表示

八进制数0153转换为二进制数:

八进制数可分解成

0          1             5           3

对应的二进制就是

000       001        100      011

2进制001101011
8进制153

二转十六

和二转八一样的道理,十六进制数由0~9,a~f组成,最大的数为F也就是15,二进制表达为1111

也就是说十六进制中的一位数最多需要四位数的二进制数来表示

十六进制0x6b用二进制表示

十六进制数可分解成

6              b

对应的二进制就是

0110         1011

2进制1101011
16进制6b

插入:   %d打印十进制   %o打印八进制  %x打印十六进制 


二、原码、反码、补码

一个整型数据在计算机中的二进制表达有三种方式

符号整型(signed int)三种方式都有符号位和数值位,二进制中,最高位为符号位

1为正数、0为负数

*正整数的原码、反码、补码都一样

*负整数则三种均不同

原码:直接将数值按照正负数的形式翻译成⼆进制

反码:将原码的符号位不变,其他位依次按位取反

补码:反码+1

补码得到原码:取反,+1

 

注意:对于整型来说, 数据内存中存放的其实是补码  

原因:

 官方解释:

在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

如果看不懂也没事,下面的例子可以帮助大家

总的来说,补码和原码的计算得出结果并不一样

1-1
1+(-1)
00000000000000000000000000000001   ---> 1的原码
10000000000000000000000000000001   ---> -1的原码
10000000000000000000000000000010   -> -2

使用补码就可以
00000000000000000000000000000001   ---> 1的补码
10000000000000000000000000000001
11111111111111111111111111111110
11111111111111111111111111111111 ----> -1的补码
00000000000000000000000000000001 ---->  1的补码
相加:
00000000000000000000000000000000 ---> 0

 三、操作符详解

1. 操作符的分类

• 算术操作符: + 、- 、* 、/ 、%

• 移位操作符: <<   >>

• 位操作符: &  |  ^  ~

• 赋值操作符: = 、+= 、  -= 、  *= 、  /= 、%= 、<<= 、>>= 、&= 、|= 、^=

• 单⽬操作符: !、++、--、&、*、+、-、~ 、sizeof、(类型)

• 关系操作符: > 、>= 、< 、<= 、  == 、 !=

• 逻辑操作符: && 、||

• 条件操作符: ? :

• 逗号表达式: ,

• 下标引⽤: [ ]

• 函数调⽤: ( )

• 结构成员访问: .  、 ->

上诉有一部分想必大家已经很熟悉了,这次博主注意讲解之前没有涉及和遇见的内容

2.移位操作符: <<   >>

分为左移和右移

注意:操作数只能是整数

左移:左边抛弃,右边补0

#include<stdio.h>
int main() {
	int num = 10;
	int n = num << 1;
	printf("%d\n",num);//二进制0000 0000 0000 0000 0000 0000 0000 1010
	                     //0 (0)000 0000 0000 0000 0000 0000 0001 0100(左边舍去,右边补0 )
	printf("%d\n", n);//0000 0000 0000 0000 0000 0000 0001 0100 ---->20
	return 0;
}

 输出

10

20

右移则有两种情况:

1.左边补0,右边丢弃

过于暴力,简单一想,先不说数字的变化过大,甚至连正负都被改变了

2.左边用原本是符号位补充,右边丢弃

#include<stdio.h>
int main() {
	int num = 10;
	int n = num >> 1;
	printf("%d\n", num);//二进制0000 0000 0000 0000 0000 0000 0000 1010
	                    //   0  0000 0000 0000 0000 0000 0000 0000 101(0)(左边用原本是符号位补充,右边丢弃)
	printf("%d\n", n);//        0000 0000 0000 0000 0000 0000 0000 0101 ---->5
	return 0;
}

警告:一定不要移到负数位,这个操作在C语言中是没被定义的

3.位操作符: &  |  ^  ~

1  &        //按位与    有0则0,全1则1

2  |         //按位或    有1则1,全0则0

3  ^        //按位异或 相同是1,不同是0

4  ~       //按位取反 符号位不变其他取反

注意:操作数只能是整数 

#include<Stdio.h>
int main() {
	int n = -1;
	int m = 5;
	printf("%d\n", n & m);
	printf("%d\n", n | m);
	printf("%d\n", n ^ m);
	printf("%d\n", ~n);
	return 0;
}
 变态的面试题

不用第三个变量完成两个数的交换

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	a = a ^ b;
	b = a ^ b;//b = a
	a = a ^ b;//a= b
	printf("%d %d", a, b);
	return 0;
}

 将a的值赋成a^b的值

这样

b = a ^ b ^ b = a

a = a ^ b ^ b(a) = b

异或运算:

a^a = 0

a^0 = a

 

求一个整型存储在内存中的二进制中1的个数 
#define _CRT_SECURE_NO_WARNINGS 1
#define N 10
#include<stdio.h>
int main() {
	int num = N;
	int count = 0;
	while (num) {
		if (num % 2 == 1) {
			count++;
		}
			num = num / 2;
	}
	printf("%d\n", count);
	return 0;
}

//10---->1010

//法2
int main() {
	int num = N;
	int count = 0;
	for (int i = 0; i < 32; i++) {
		if (num & (1 << i))
			count++;
		}
	printf("%d\n", count);
		return 0;
}
//00001010
//00000001     1
//1 << i
//00000010
//依次对比尾位


//法3
int main() {
	int num = N;
	int count = 0;
	while (num) {
		count++;
		num = num & (num - 1);
	}
	printf("%d\n", count);
	return 0;
}

//00001010         10
//00001001          10-1=9
//两者&变成 
//00001000         10二进制表达中最右侧的1就被删除了,这时count+1

这边给大家介绍三种方法,思维层度是一步步晋升的

大家在学习的过程中,可能会遇见很多无从下手的问题,看到别人的解法也是一脸惊讶,还能这么写代码

要见过才能知道,不能空想要一步一步去学,学的多了见得多了,才能想出来自己的方法

方法一:

以123为例

123%10=3

123/10=12

12%10=2

12/10=1

1%10=1 --->count++

按照这样的方法,对于二进制数来说,就是循环的模2和除以2

方法二:

这个方法的思维和简单,就是一位一位的去比较

二进制在系统中一般有32为,这样我们就需要循环32次

 //00001010
//00000001     1
//1 << i
//00000010
//依次对比尾位

方法三:

这是博主之前完全没见过的方法,博主第一次遇见的时候也吃了一惊

//00001010         10
//00001001          10-1=9
//两者&变成 
//00001000         10二进制表达中最右侧的1就被删除了,这时count+1

 直到现在博主依旧无法想象这是怎么想出来的,只能说无处无高人,我们所见识的东西还是太少了。

4. 单目操作符

单目操作符有这些:!、++、--、&、*、+、-、~ 、sizeof、(类型)

单目操作符的特点是只有⼀个操作数,在单⽬操作符中只有&和*没有介绍,这2个操作符,我们放在学习指针的时候学习。

5. 逗号表达式

1 exp1, exp2, exp3, …expN

逗号表达式,就是⽤逗号隔开的多个表达式。逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。

6. 下标访问[]、函数调用()

[ ] 下标引⽤操作符

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

int  arr[10];//创建数组

arr[9] = 10;//实⽤下标引⽤操作符。

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

 函数调⽤操作符接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数

四、结构成员访问操作符

1.结构体

用来描述复杂对象

其和数组一样是自定义类型

C语言已经提供了内置类型:char、short、int、long、float、double等

但是当我们遇见复杂类型的对象是就不够用了,如:学生这个对象,拥有 名字、性别、年龄、成绩等等一系列的,这个时候就需要我们自己创造不同的变量

结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚⾄是其他结构体。


结构体的声明

struct tag

{

   member-list;

}variable-list;

 

struct Point
{
	int x;
	int y;
}p1;
struct Point p2;

struct Point p3 = { 10,20 };

struct Stu
{
	char name[15];
	int age;
};

struct Stu s1 = { "zhangsan",20 };
struct Stu s2 = {.age = 20, .name = "lisi"};


struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10,{4,5},NULL};

struct Node n2 = { 20,{5,6},NULL};
结构体成员的直接访问

用点操作符(.)访问

#include <stdio.h>
struct Point
{
int  x;
int  y;
}p = {1,2};
int main()
{
printf("x: %d y: %d\n", p.x, p.y);
return 0;
}
结构体成员的间接访问

有的时候没有一个结构体变量,而是一个指向结构体的指针

这个时候就吧p.x  p.y

这样的直接访问形式改为:

struct Point *p = &p;//获得结构体变量的地址

p->x   p->y

五、结束语

下一篇博主会给大家讲解一下操作符是使用注意事项,之后我们就进入指针的学习了!

敬请期待! 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值