C-操作符详解

发布时间:2024年01月14日

1.进制转换

1.1 10进制转2进制

方法:短除法

1.2 2进制转换8进制

8进制的数字每?位是0~7的,0~7的数字,各?写成2进制,最多有3个2进制位就?够了,?如7的?进制是111,所以在2进制转8进制数的时候,从2进制序列中右边低位开始向左每3个2进制位会换算?个8进制位,剩余不够3个2进制位的直接换算。
如:2进制的01101011,换成8进制:01530开头的数字,会被当做8进制。
我有一个问题:怎么区别 0111是8进制还是2进制?
1.3 2进制转换16进制
2进制转化16进制和2进制转换8进制十分相似,
16进制的数字每?位是0~9,a ~f 的,0~9,a ~f的数字,各?写成2进制,最多有4个2进制位就?够了,
?如 f 的?进制是1111,所以在2进制转16进制数的时候,从2进制序列中右边低位开始向左每4个2进
制位会换算?个16进制位,剩余不够4个?进制位的直接换算。
如:2进制的01101011,换成16进制:0x6b,16进制表?的时候前面加0x
2 原码,反码,补码
整数 的2进制表??法有三种,即原码、反码和补码
有符号整数的三种表??法均有符号位数值位两部分,2进制序列中,最?位的1位是被当做符号
位,剩余的都是数值位。
符号位都是?0表?“正”,?1表?“负”。
正整数的原、反、补码都相同。
负整数的三种表??法各不相同。
原码:直接将数值按照正负数的形式翻译成?进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
反码得到原码也是可以使?:取反,+1的操作
对于整形来说:数据存放中其实存放的是补码。
//操作符详解
#include<stdio.h>

int main()
{
	int num1 = 10;
	//10存放在整型变量num1中,占4个字节==32个bit位
	//0000 0000 0000 0000 0000 0000 0000 1010 -原码
	//0000 0000 0000 0000 0000 0000 0000 1010 -反码
	//0000 0000 0000 0000 0000 0000 0000 1010  -补码

	//正数的原码,反码,补码都一样
	int num2 = -10;
	//-10存放在整型变量num2中,占4个字节==32个bit位
	//1000 0000 0000 0000 0000 0000 0000 1010 -原码
	//1111 1111 1111 1111 1111 1111 1111 0101 -反码
	//1111 1111 1111 1111 1111 1111 1111 0110 -补码

	//负数的原码,反码,补码要经过计算
	return 0;
}

为什么计算机中存补码呢?

在计算机系统中,数值?律?补码来表?和存储。原因在于,使?补码,可以将符号位和数值域统? 处理;同时,加法和减法也可以统?处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
简单举个例子:
1-1
 1+(-1)
 0000 0000 0000 0000 0000 0000 0000 0001 -1的补码
 1111 1111 1111 1111 1111 1111 1111 1111 -(-1)的补码
 相加
1 0000 0000 0000 0000 0000 0000 0000 0000
 最高位被丢弃
 结果是0

3 移位操作符(移动的是补码)

3.1左移操作符

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

#include<stdio.h>

int main()
{
	int num = 10;
	int n = num << 1;
	printf("n= %d\n", n);
	printf("num= %d\n", num);
	return 0;
}

3.2 右移操作符

右移操作符比左移操作符稍微复杂一点。

首先他的移位规则就分为两种:
1. 逻辑右移:左边?0填充,右边丢弃
2. 算术右移:左边?原该值的符号位填充,右边丢弃

?应用哪种规则取决于编译器,目前大部分编译器上使用的算术右移,

#include <stdio.h>
int main()
{
	int num = -10;
	int n = num >> 1;
	printf("n= %d\n", n);//-5
	printf("num= %d\n", num);//-10
	return 0;
}
逻辑右移:
算术右移
警告??:
对于移位运算符,不要移动负数位,这个是标准未定义的。
int num = 10;
num>>-1;//error

4. 位操作符:& | ^ ~

注意:他们操作的对象必须是整数

区别: && (逻辑与)||(逻辑或),他们是逻辑操作符

#include <stdio.h>
int main()
{
	int num1 = 3;
	//0000 0000 0000 0000 0000 0000 0000 0011  3的补码
	int num2 = -5;
	//1111 1111 1111 1111 1111 1111 1111 1011   -5的补码
	// 
	//按照(二进制)位进行运算

	printf("%d\n", num1 & num2);//3
	//& 有0就是0,全1为1
	//0000 0000 0000 0000 0000 0000 0000 0011

	printf("%d\n", num1 | num2);//-5
	//| 有1为1,全0为0
	//1111 1111 1111 1111 1111 1111 1111 1011   

	printf("%d\n", num1 ^ num2);//-8
	//^ 相同为0,相异为1
	//1111 1111 1111 1111 1111 1111 1111 1100

	printf("%d\n", ~0);//-1
	//~ 按位取反
	// 1111 1111 1111 1111 1111 1111 1111 1111 -(-1)的补码

	return 0;
}
拓展?试题:
不能创建临时变量(第三个变量),交换两个整数
方法:使用^?
#include <stdio.h>
int main()
{
	int a = 10;
	//0000 0000 0000 0000 0000 0000 0000 1010
	int b = 20;
	//0000 0000 0000 0000 0000 0000 0001 0100  
	a = a ^ b;
	//a=
	//0000 0000 0000 0000 0000 0000 0001 1110
	//30
	b = a ^ b;
	//b=
	//0000 0000 0000 0000 0000 0000 0000 1010
	//10

	a = a ^ b;
	//a=
	//0000 0000 0000 0000 0000 0000 0001 0100  
	//20
	printf("a = %d b = %d\n", a, b);
	return 0;
}

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

int main()
{
	//方法1:&的应用
	int num =5;
	int i = 0; int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (((num >> i) & 1) == 1)//不用考虑正负数,移位操作符移动的是补码
			count++;
	}
	printf("%d", count);
	return 0;
}

问题: 什么时候要考虑正负数嘞?

#include <stdio.h>

int count_one_bit(unsigned int n)
//int count_one_bie(int n) 针对负数就可能出错
{
	int count = 0;
	while (n)
	{
		if (n % 2 == 1)
			count++;
		n = n / 2;
	}
	return count;
}

方法3:

//最高效的一种
int count_one_bit(unsigned int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}

5. 单目操作符

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

6.逗号表达式

逗号表达式,就是?逗号隔开的多个表达式。
逗号表达式,从左向右依次执?。整个表达式的结果是最后?个表达式的结果。
7.下标访问[]、函数调?()
7.1 [ ] 下标引?操作符
操作数:?个数组名 + ?个索引值
int arr[10];//创建数组
arr[9] = 10;//实?下标引?操作符。
//[ ]的两个操作数是arr和9。

7.2 () 函数调用操作符
#include <stdio.h>
void test1()
{
 printf("hehe\n");
}
void test2(const char *str)
{
 printf("%s\n", str);
}
int main()
{
 test1(); //这?的()就是作为函数调?操作符。
 test2("hello bit.");//这?的()就是函数调?操作符。
 return 0;
}

8.结构体访问操作符

C语?已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类
型还是不够的,假设我想描述学?,描述?本书,这时单?的内置类型是不?的。描述?个学?需要 名字、年龄、学号、??、体重等;描述?本书需要作者、出版社、定价等。C语?为了解决这个问题,增加了结构体这种?定义的数据类型,让程序员可以??创造适合的类型。
📌 结构是?些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如: 标量、数组、指针,甚至是其他结构体
结构体声明
struct Stu
{
	char name[20];
	int age;
	float score;
}stu;//全局变量

结构体的使用

//结构体的声明
struct Stu
{
	char name[20];
	int age;
	float score;
}stu = {"Bob",18,97.5f};//全局变量的初始化

int main()
{
	//结构体变量的初始化
	struct Stu s1 = { "Mary",15,96.5 };//局部变量
	//结构体的直接访问
	printf("%s %d %lf\n", s1.name, s1.age, s1.score);
	printf("%s %d %lf\n", stu.name, stu.age, stu.score);
	//结构体的间接访问
	struct Stu* ps = &s1;
	printf("%s %d %lf\n", ps->name,ps->age,ps->score);
	return 0;
}

9. 操作符的优先级和结合性

9.1 优先级

优先级指的是,如果?个表达式包含多个运算符,哪个运算符应该优先执?。各种运算符的优先级是不?样的。
1 3 + 4 * 5 ;
??例中,表达式 3 + 4 * 5 ??既有加法运算符( + ),?有乘法运算符( * )。由于乘法的优先级?于加法,所以会先计算 4 * 5 ,?不是先计算 3 + 4
9.2结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执?顺序。?部分运算符是左结合(从左到右执?),少数运算符是右结合(从右到左执?),?如赋值运算符( = )。
1 5 * 6 / 2 ;
上??例中, * / 的优先级相同,它们都是左结合运算符,所以从左到右执?,先计算 5 * 6
再计算 6 / 2 。 运算符的优先级顺序很多,下?是部分运算符的优先级顺序(按照优先级从?到低排列),建议?概
记住这些操作符的优先级就?,其他操作符在使?的时候查看下?表格就可以了。
? 圆括号( ()
? ?增运算符( ++ ),?减运算符( --
? 单?运算符( + -
? 乘法( * ),除法( /
? 加法( + ),减法( -
? 关系运算符( < > 等)
? 赋值运算符( =
由于圆括号的优先级最?,可以使用它改变其他运算符的优先级。

C语言中,可以通过数字的前缀来区分二进制和八进制。如果一个数字以0开头,则表示它是八进制数;如果一个数字以0b或0B开头,则表示它是二进制数。

例如,对于数字0111,根据前缀0,它被视为八进制数。要将其转换为十进制数,可以使用C语言中的atoi()函数或strtol()函数。

下面是一个示例代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *binary = "0111";
    int decimal = strtol(binary, NULL, 8);
    
    printf("Decimal value: %d\n", decimal); // 输出:73
    
    return 0;
}

在上面的代码中,我们将字符串"0111"转换为八进制数73,并将其打印为十进制数

文章来源:https://blog.csdn.net/qq_59293418/article/details/135574985
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。