我的C语言日记09-操作符

操作符

算数操作符

% 取模操作符,左右操作数都必须为整数
/ 除号等,+ - * 的左右操作数可以为浮点数或整数

移位操作符

右移操作符:
1.算术右移
    右边丢弃,左边补原符号位
 

int main()//算术右移,右边丢弃,左边补原符号位
{
	int a = -1;//负数按照补码的方式存储,正数存储的也是补码(正数的补码和原码相同)
	//1000000000000001-原码
	//1111111111111110-补码
	//1111111111111111-补码
	int b = a >> 1;//移位移的是内存中的二进制
	printf("%d\n", b);
	return 0;//结果为-1,证明负数右移之后还是负数
}


2.逻辑右移
    右边丢弃,左边补0

右移一位有除二的效果

int main()
{
	int a = 16;
	int b = a >> 1;
	int c = a >> 2;
	printf("%d %d\n", b,c);//结果分别为8 4 
	return 0;
}

左移操作符:
左边丢弃,右边补0
有乘二的效果
 

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

负数左移还是负数 

int main()
{
	int a = -5;
	int b = a << 1;
	printf("%d\n", b);
	return 0;//-10
}

警告⚠

1.不要移动负数位,是未定义的行为

int num = 10;
num >> -1;///错误

 2.只能作用于整数

&、|、^

&按位与

int main()
{
	//&按2进制位与
	int a = 3;
	int b = 5;
	int c = a&b;
	//011
	//101
	//001
	printf("%d\n", c);
	return 0;
}

|按位或

int main()
{
	//|按2进制位或
	int a = 3;
	int b = 5;
	int c = a | b;
	//011
	//101
	//111
	printf("%d\n", c);//7
	return 0;
}

 ^按位异或

int main()
{
	//^按2进制位异或  相同为0,相异为1
	int a = 3;
	int b = 5;
	int c = a^b;
	//011
	//101
	//110
	printf("%d\n", c);
	return 0;
}

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

int main()
{
	int num = 0;
	int count = 0;
	scanf("%d", &num);
	//统计num的补码中有几个1
	while (num)
	{
		if (num % 2 == 1)//判断末位是否为1
			count++;
		num = num / 2;//去掉判断过的末位
	}
	printf("%d\n", count);
	return 0;//但负数会出现问题
}

但负数会出现问题

int main()
{
	int num = 0;
	int count = 0;
	scanf("%d", &num);//当num&1,比如num=3即0011,num&1即为0011&0001,末位为1时&1必定为1,末位是0&1必定是0
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (1 == ((num >> i) & 1))
			count++;
	}
	printf("%d\n", count);
	return 0;
}

逻辑操作符

&&逻辑与       ||逻辑或
逻辑与或和按位与或是有区别的,
按位与或:二进制对应位进行与或
逻辑与或:判断数字本身的真假

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;//a=0&&后面都为假,不运行//用后自加一
	printf("a=%d\n b=%d\n c=%d\n d=%d\n", a, b, c, d);
	return 0;//1 2 3 4 
}

&&

左边为假&&后面不计算

int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;//a=0为假&&后面不计算,不运行//用后自加一
	printf("a=%d\n b=%d\n c=%d\n d=%d\n", a, b, c, d);
	return 0;//1 2 3 4 
}

左边为真时&&后计算

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	i = a++ && ++b && d++;
	printf("a=%d\n b=%d\n c=%d\n d=%d\n", a, b, c, d);
	return 0;//2 3 3 5
}

||

左边为真时||后不计算

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	i = a++ || ++b || d++;//a=1为真||后面的不计算,然后自加一
	printf("a=%d\n b=%d\n c=%d\n d=%d\n", a, b, c, d);
	return 0;//2 2 3 4
}

条件操作符

格式为:表达式1?表达式2:表达式3;
表达式1为真时结果为表达式2,表达式为假时结果为表达式3

int main()
{
	int a = 0;
	int b = 0;
	if (a > 5)
		b = 3;
	else
		b = -3;
	//用条件操作符来表示
	b = (a > 5 ? 3 : -3);
	return 0;
}

逗号表达式

从左向右依次执行,整个表达式的结果是最后一个表达式的结果

int a=1;
int b=2;
int c=(a>b,a=b+10,a,b=a+1);
c的值为13

还可以简化表达式

a = get_val();
count_val(a);
while (a > 0)
{
    //业务处理
    a = get_val();
    count_val(a);
}
//----逗号表达式优化---
while (a = get_val(), count_val(a), a > 0)
{
    //业务处理
}

 下标引用、函数调用和结构成员

[]下标引用操作符

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

int arr[10];//创建数组
arr[9] = 10;//实用下标引用操作符
[]的两个操作符是arr和9

 函数调用操作符

调用函数的时候的()就是函数调用操作符,定义函数的()不是
()的操作数有:函数名,参数

结构成员

struct Stu
{
	char name[20];//成员变量
	int age;
	char id[20];
};
int main()
{
	int a = 10;
	//使用struct Stu这个类型创建了一个学生对象s1,并初始化
	struct Stu s1 = {"张三",20,"2019010305"};
	printf("%d\n", s1.age); //结构体变量.成员名//.操作符可以访问成员
	printf("%s\n", s1.id);
	struct Stu* ps = &s1;
	printf("%d\n", (*ps).age);
	printf("%d\n", ps->age);//结构体指针->成员名
	return 0;
}

struct Stu{}相当于图纸,根据图纸建造出来名为s1的房子,所以struct Stu s1占用内存空间,可以存放各种参数

表达式求值

隐式类型转换

c的整型算数运算总是至少以缺省整型类型的精度来进行的
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

整型提升是按照变量的数据类型的符号位来提升的(高位补符号位)

int main()
{
	char a = 3;
	//00000000000000000000000000000011  正常一个整数所占32位
	//00000011这就是char a //但char只能存放一个字节,要发生截断,取低位一个字节
	char b = 127;
	//00000000000000000000000001111111   同理
	//01111111这就是char b
	char c = a + b;//计算时进行整型提升
	//00000000000000000000000000000011 //整型提升:高位补符号位
	//00000000000000000000000001111111 //整型提升:高位补符号位
	//00000000000000000000000010000010 a+b得到c,因为c是char类型要截断
	//10000010就是char c
	printf("%d\n", c);//要打印整型//整型提升:高位补符号位
	//11111111111111111111111110000010 - 补码//因为是负数,所以要求原码
	//11111111111111111111111110000001 - 反码
	//10000000000000000000000001111110 - 原码//-126
	return 0;
}

算术转换

类型不同的操作数进行运算,低精度的类型转换为高精度的类型,类型一致再进行运算

自加和自减详解

总结:自增减(++/--)前置:在运算之改变变量
           自增减(++/--)后置:在运算之改变变量

1.

int main()
{
	int i = 0;
	int j = i++ + ++i;//++i优先级高于i++,所以相当于int j=++i + i++; 
                      //此时i=0,1(此时i=1)+1(此时i=2)=2
	int k = --i + i--;//此时i=2,(此时i=1)1+1(此时i=0)=2
	printf("%d %d %d\n", i, j, k);
	return 0;
}

当运行int j = i++ + ++i;
        分析优先级:自加高于+,两个自加同级从左向右计算;其中++i的优先级比i++高,即变为
int j=++i + i++
        运算之前:因为++i,在运算之前使得变量i加一(0+1=1);此时i=1
        运算之中:加上i++,因为是后置++,所以此时i仍然是1,所以为1+1=2赋值给j
        运算之后:因为i++,在运算之后使得变量i加一(1+1=2);此时i=2
当运行int k = --i + i--;
        运算之前:因为--i,在运算之前使得变量i减一(2-1=1);此时i=1
        运算之中:加上i--,因为是后置--,所以此时i仍然是1,所以为1+1=2赋值给j
        运算之后:因为i--,在运算之后使得变量i减一(1-1=0);此时i=0

2.

int main()
{
	int i = 0;
	int j = i + i++;//0+0(i=1)=0
	printf("%d %d\n", i, j);
	return 0;
}

运行int j = i + i++;
        运算之前:无
        运算之中:加上i++,因为是后置++,所以此时i仍然是0,所以为0+0=0赋值给j
        运算之后:因为i++,在运算之后使得变量i加一(0+1=1);此时i=1

3.

int main()
{
	int i = 0;
	int j = i + ++i;//1+1=2
	printf("%d %d\n", i, j);
	return 0;
}

运行 int j = i + ++i;
分析优先级:自加高于+,即变为int j=++i + i;
        运算之前:因为++i,在运算之前使得变量i加一(0+1=1);此时i=1
        运算之中:加上i,此时i仍然是1,所以为1+1=2赋值给j
        运算之后:无

猜你喜欢

转载自blog.csdn.net/qq_44928278/article/details/119913594