c语言常用操作符(2)

mljy. 2024-07-12 08:05:03 阅读 67

 1.移位操作符

移位操作符分为<<左移操作符和右移操作符>>

注:移位操作符的操作数只能是整数,同时移位操作符移动的是存储在内存中的二进制位(也就是补码

同时移位操作符不要移动负数位,这个是标准未定义的。

1.<<操作符

移位规则:左边抛弃、右边补0

例1

<code>#include<stdio.h>

int main()

{

int a=10;

int b=a<<1;

printf("a=%d\n",a);

printf("b=%d\n",b);

return 0;

}

由于a为正整数,所以补码与原码相同 

 所以b输出结果为20

例2 

<code>#include<stdio.h>

int main()

{

int a = -1;

int b = a << 1;

printf("a=%d\n", a);

printf("b=%d\n", b);

return 0;

}

由于a为负整数,所以补码等于原码取反加一

所以输出b输出结果为-2

 由以上例1与例2可以发现左移操作符有乘2的效果

 2.>>操作符

在右移操作符不同于左移操作符,右移操作符有两种运算

1. 逻辑右移:左边用0填充,右边丢弃

2. 算术右移:左边用原该值的符号位填充,右边丢弃

 例1

<code>#include<stdio.h>

int main()

{

int a = -1;

int b = a >> 1;

printf("a=%d\n", a);

printf("b=%d\n", b);

return 0;

}

 

所以算数右移b等于-1,逻辑右移b等于一个很大的正整数 

右移是采取算数右移还是逻辑右移是取决于编译器的 通常采取的都是算数右移

在vs中采取的也是算数右移

例2

<code>#include<stdio.h>

int main()

{

int a = 10;

int b = a >> 1;

printf("a=%d\n", a);

printf("b=%d\n", b);

return 0;

}

 以上代码输出结果为

通过以上代码可以发现右移有除2的效果 

2.位操作符

位操作符有:

&  按位与

|    按位或

^   按位异或

~   按位取反

注:位操作符的操作数必须是整数,同时位操作符是对存储在内存中的二进制位(也就是补码)进行运算

在这不要将&和|与之前讲到的&&和||混淆 &&和||关注的是操作符两端的真假 &和|关注的是操作符两端的二进制序列

1.& 按位与

<code>#include<stdio.h>

int main()

{

int a = -7;

int b = 6;

int c = a & b;

printf("c=%d\n", c);

return 0;

}

在以上代码中a&b  首先我们知道&是对操作数在内存中存储的二进制位进行运算,所以先将a和b的补码表示出来如下所示

按位与操作符中两个操作数对应二进制位有0则为0,俩个都为1时,才为1 

所以就可得出c的补码

 最终c的结果为0

运行程序验证以上运算

2.|  按位或

<code>#include<stdio.h>

int main()

{

int a = -7;

int b = 6;

int c = a | b;

printf("c=%d\n", c);

return 0;

}

将此先的代码再使用一遍,而这时将c=a | b 

 在按位或操作符中两个操作数对应二进制位有1则为1,俩个都为0时,才为0

所以就可得出c的补码

 最终c的结果为-1

运行程序验证以上运算

3.^   按位异或

<code>#include<stdio.h>

int main()

{

int a = -7;

int b = 6;

int c = a ^ b;

printf("c=%d\n", c);

return 0;

}

在以上代码中用到了按位异或操作符,要得到c的结果首先要知道^的计算逻辑

按位异或操作符中两个操作数对应二进制位不同则为1,俩个相同时,才为0

 

所以最终c输出结果为-1

运行程序验证以上运算

4.~   按位取反  

按位取反操作符是将整数的二进制位全部取反 

<code>#include<stdio.h>

int main()

{

int a = -7;

int b = 6;

int c = a ^ b;

int d = ~c;

printf("d=%d\n", d);

return 0;

}

例如在以上代码中对c按位取反 最终d输出结果为0

 运行程序验证以上运算

5.练习

练习1.一道面试题

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

 

<code>#include<stdio.h>

int main()

{

int a = 0;

int b = 0;;

scanf("%d %d", &a, &b);

a = a ^ b;

b = a ^ b;

a = a ^ b;

printf("a=%d b=%d",a,b);

return 0;

}

要理解这种方法就要再了解一下^的一些特点 

1.a^a=0

2.a^0=a

3.a^b^c=a^c^b=b^a^c=b^c^a=c^a^b=c^b^a(异或是支持交换率)

来举一些例子让我们更好理解以上特点 

 例如:3^3操作符的二进制位都相同所以异或后都为0,所以最终3^3=0

            3^0操作符的二进制位都不同所以异或后都为原来3的二进制位,3^0=3

            1^2^3与3^2^1最终计算结果是相同的

在此之后我们再来理解以上代码

在b=a^b中的a=a^b,在最后的a=a^b中a=a^b b=a

运行程序验证以上运算

       

练习2

编写代码实现:求⼀个整数存储在内存中的二进制中1的个数 

我们知道要将一个数从十进制转换为二进制是需要通过不断整除2然后取出余数

所以我们可以想到以下方法来求一个数二进制中1的个数

<code>#include<stdio.h>

int Number(int n)

{

int count=0;

while(a)

{

if(a%2==1)

{

count++;

}

a=a/2;

}

return count;

}

int main()

{

int a=0;

scanf("%d",&a);

int n=Number(a);

printf("%d",n);

return 0;

}

在以上方法会存在一个问题就是无法计算负数的二进制1的个数 这时有的读者会想到将形参用unsigned int,这种方法确实能解决问题 但有没有更好的方法呢?

#include<stdio.h>

int Number(int a)

{

int count=0;

int i=0;

for(i=0;i<32;i++)

{

if((a>>i)&1)

{

count++;

}

}

return count;

}

int main()

{

int a=0;

scanf("%d",&a);

int n=Number(a);

printf("%d",n);

return 0;

}

 以上这种方法是将整数的二进制数的每一位都按位与1,若输出为1就count++;实现二进制位中1的计数 但这种方法也有一定的缺陷就是无论输入整数的二进制位中有几个1都需要将32位全部遍历一遍,这样会使得代码的效率不高 因此我们能否再设计一种方法来让统计出所有二进制1时就停止循环呢?

#include<stdio.h>

int Number(int a)

{

int count=0;

int i=0;

while(n)

{

a=a&(a-1);

count++;

}

return count;

}

int main()

{

int a=0;

scanf("%d",&a);

int n=Number(a);

printf("%d",n);

return 0;

}

 要理解上面这种方法首先要了解n&(n-1)结果的特点

n&(n-1)能将整数的二进制位中去除一个1

例如当n=5时

所以利用这种方法就可以在二进制位1的个数为0时不再继续执行程序,提升了程序的效率

练习3

二进制位置0或者置1

 编写代码将13二进制序列的第5位修改为1,然后再改回0

13的2进制序列: 00000000000000000000000000001101

将第5位置为1后:00000000000000000000000000011101

将第5位再置为0:00000000000000000000000000001101

<code>#include<stdio.h>

int main()

{

int a=13;

printf("%d",a);

a=a|(1<<4);

printf("%d",a);

a=a&~(1<<4);

printf("%d",a);

return 0;

}

3.逗号操作符

 首先了解什么是逗号表达式

1 exp1, exp2, exp3, …expN

正如以上所示用逗号隔开的多个表达式就是逗号表达式,而这其中的逗号就是逗号操作符

逗号表达式中有一特点:从左向右依次执行并计算,整个表达式的结果是最后⼀个表达式的结果

int a = 1;

int b = 2;

int c = (a>b, a=b+10, a, b=a+1);//逗号表达式

c是多少?

 在以上代码中c的等号右边是一个逗号表达式,要从左向右计算得出的才是正确结果,因为前面表达式的计算可能会影响后面表达式的计算

a=b+10=12后b=a+1=13 所以最终c=13

逗号表达式同时还能在if;while等语句的判断部分使用,起到简化代码的作用

a = get_val();

count_val(a);

while (a > 0)

{

//业务处理

//...

a = get_val();

count_val(a);

}

如果使用逗号表达式就可以简化为:

while (a = get_val(), count_val(a), a>0)

{

//业务处理

}

4.下标访问操作符、函数调用操作符

1. [ ] 下标引用操作符 

int arr[4]={1,2,3,4};

int n=arr[3];

arr[3]表示数组下标为3的元素是4 这里面的[]就是下标引用操作符 arr[3]中操作数arr和3 

由此可见 [ ]下标引用操作符也是双目操作符 

注:在int arr[4]中的[ ]是用来指定数组元素大小不是在访问数组的某个元素,所以不是下标引用操作符

2.函数调用操作符

#include<stdio.h>

int Add(int x,int y)

{

return x+y;

}

int main()

{

int a=0;

scanf("%d %d",&a,&b);

printf("%d %d\n",a,b);

int n=Add(a,b);

printf("%d",n);

return 0;

}

在以上代码中库函数printf和自定义函数Add后的括号都是函数调用操作符

其中Add后()的操作数是Add ,3,5

那函数调用操作符至少有几个操作数呢?

答案是至少有一个,原因是在调用时候函数名不可省略,但参数可能为0

5. 结构成员访问操作符

但要描述一个复杂对象时单一的数据类型已经不足以实现,C语言为了解决这个问题,增加了结构体这种自定义的数据类型,让程序员可以自己创造适合的类型。

📌 结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:

标量、数组、指针,甚至是其他结构体。

1.结构的声明 

在结构体的声明要用到struct关键字

 

struct tag//tag的名字可是自定义的

{

member-list;//成员列表

}variable-list;//变量列表

例如用struct定义一个学生类型

 

struct Stu//学生类型

{

char name[20];//名字

int age;//年龄

char sex[5];//性别

char id[20];//学号

}; //分号不能丢

2.结构体变量的定义和初始化

变量的定义 

struct Stu//学生类型

{

char name[20];//名字

int age;//年龄

char sex[5];//性别

char id[20];//学号

}s3,s4;

struct student s2;

int main()

{

struct student s1;

return 0;

}

正如以上所示变量的创建可以是全局变量也可以是局部变量,还可以在结构体声明的末端

 变量的初始化

struct Stu //类型声明

{

char name[15];//名字

int age;//年龄

};

struct Stu s1 = {"zhangsan", 20};//初始化

struct Node

{

int data;

struct Stu p;

int arr[4];

}n1 = {1,{"zhangsan", 20},{1,2,3,4},};//结构体嵌套初始化

struct Node n2 = {6,{"lisi", 19},{9,2,5,4},};//结构体嵌套初始化

结构成员访问操作符

结构体成员的直接访问是通过点操作符(.)访问的。

使用方式:结构体变量.成员名

#include<stdio.h>

struct Stu //类型声明

{

char name[15];//名字

int age;//年龄

};

struct Stu s1 = {"zhangsan", 20};//初始化

struct Node

{

int data;

struct Stu p;

int arr[4];

}n1 = {1,{"zhangsan", 20},{1,2,3,4},};//结构体嵌套初始化

struct Node n2 = {6,{"lisi", 19},{9,2,5,4},};//结构体嵌套初始化

int main()

{

printf("%d %s %d %d",n2.data,n2.p.name,n2.p.age,n2.arr[1]);

return 0;

}

 代码运行结果

 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。