C初阶(三十四) 操作符_sizeof两个陷阱_&& ||陷阱

知识点1:算数操作符:+ - * / %

1、/—对于除,若两个数都为整数,执行整数除法;只要有浮点数才执行浮点数除法
2、%—对于取余,两个数必须为整数,返回的是整除之后的余数;取模操作符绝对
不能浮点数类型
3、注意:浮点数类型用float 或 double —打印时使用 %lf—打印小数点后六位

int main()
{ 
	// /除操作符
	int a = 1;
	int b = 3;
	printf("%d \n", a / b);

	int c = 7 / 2;
	printf("%d \n", c);

	double d = 7.0 / 2;
	printf("%lf \n", d);

	float d1 = 7.0 / 2;
	printf("%f \n", d1);

	// %模操作符
	int e = 4 % 3;
	printf("%d \n", e);
	return 0;
}

知识点2:移位操作符:>>(右移) <<(左移)

   1、移动的是二进制位
   2、整数的二进制表现形式---原码、反码、补码
        正整数:原码、反码、补码相同
        负整数:直接写的二进制序列 ---原码
               原码字符位不变,其他位按位取反 ---反码
               反码+1 ---补码
   3、内存中存储整数时存储的是补码---计算时转换为补码
   4、算数右移:左边补符号位,右边丢弃----某些情况下,右移除二的效果
  				 逻辑右移:左边补0,右边丢弃
  				 算数右移,逻辑右移---跟编译器有关
   5、左移:左边丢弃,右边补0----某些情况下,左移乘二的效果
   6、移位时绝对不能移位的数字为负数---int num = 10;num >> -1;
   7、操作数必须为整数
int main()
{
	//正整数右移
	//分析:整数4个字节 -- 32位 
	//     原码、反码、补码:00000000 00000000 00000000 00001110----第一位0代表符号位-正数
	//     右移一位:0 00000000 00000000 00000000 0000111 ---补符号位0---VS算数右移 ---7
	int a = 14;
	int b = a >> 1;
	printf("%d ", b);//7
	
	//负整数右移
	//分析:原码:1000000 0000000 00000000 00000001 --- 第一位1代表符号位-负数
	//     反码:1111111 1111111 11111111 11111110
	//     补码:1111111 1111111 11111111 11111111
	//     右移一位:1 1111111 1111111 11111111 1111111 ---补符号位1 --- -1
	int a1 = -1;
	int b1 = a1 >> 1;
	printf("%d ", b1);//-1

	//正整数左移
	//分析:整数4个字节 -- 32位 
	//     原码、反码、补码:00000000 00000000 00000000 00001110----第一位0代表符号位-正数
	//     左移一位:0000000 00000000 00000000 00001110 0  ---补0 ---4+8+16 = 28
	int a2 = 14;
	int b2 = a2 << 1;
	printf("%d ", b2);//28

	//负整数左移
	//分析:原码:1000000 0000000 00000000 00000001 --- 第一位1代表符号位-负数
	//     反码:1111111 1111111 11111111 11111110
	//     补码:1111111 1111111 11111111 11111111
	//     左移一位:111111 1111111 11111111 11111111 0  ---补0 
	//          -                                    1
	//        反码:111111 1111111 11111111 11111110 1
	//        原码:100000 0000000 00000000 00000001 0 --- -2

	int a3 = -1;
	int b3 = a3 << 1;
	printf("%d ", b3);//-2
	return 0;
}

在这里插入图片描述

知识点3:位操作符:& | ^

1、&:同时为1 —为1
2、|:同时为0 —为0
3、^:相同为0,不同为1
4、按二进制位进行&,|,^

//知识点3:位操作符:& | ^
//     1、&:同时为1 ---为1
//     2、|:同时为0 ---为0
//     3、^:相同为0,不同为1
//     4、按二进制位进行&,|,^

int main()
{
	//& 按位与
	//3:00000000 00000000 00000000 00000011
	//5:00000000 00000000 00000000 00000101
	//  00000000 00000000 00000000 00000001 ---1
	int a = 3;
	int b = 5;
	int c = a&b;
	printf("%d\n", c);

	//| 按位或
	//3:00000000 00000000 00000000 00000011
	//5:00000000 00000000 00000000 00000101
	//  00000000 00000000 00000000 00000111 ---7
	int a1 = 3;
	int b1 = 5;
	int c1 = a1|b1;
	printf("%d\n", c1);

	//^ 按位异或
	//3:00000000 00000000 00000000 00000011
	//5:00000000 00000000 00000000 00000101
	//  00000000 00000000 00000000 00000110 ---6
	int a2 = 3;
	int b2 = 5;
	int c2 = a2^b2;
	printf("%d\n", c2);
	return 0;
}

案列1:不能创建临时变量(第三个变量),实现两个数的交换

//创建变量
int main()
{
	int a = 3;
	int b = 5;
	int temp = 0;
	printf("a = %d b=%d\n", a, b);
	temp = a;
	a = b;
	b = temp;
	printf("a = %d b=%d\n", a, b);
	return 0;
}

//不创建变量
//方法1:存在溢出
int main()
{
	int a = 3;
	int b = 5;
	printf("a = %d b=%d\n", a, b);
	a = a + b;//和给a
	b = a - b;//和减b为a--给b ---b=a
	a = a - b;//和减b(实际交换了为a),和减a为b--给a ---a=b
	printf("a = %d b=%d\n", a, b);
	return 0;
}
//方法2:异或
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;
}

在这里插入图片描述

案列2:求一个整数存储在内存中的二进制中1的个数 思想:若a按位与1为1—则该位为1;再将a向右移动1位,依次完成32位比特位

在这里插入图片描述

int BinaryReturn(int x)
{
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (((x >> i) & 1) == 1)
			count++;
	}
	return count;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int ret = BinaryReturn(n);
	printf("%d\n", ret);
	return 0;
}

知识点4:赋值操作符–复合赋值操作符

1、赋值操作符 --- =   
2、复合赋值操作符 --- +=,-=,*=,/=,%=,&=,|=,^=,>>=,<<=
int main()
{
	int a = 10;
	a = 20;
	
	int num = 0;
	num = num + 1;
	num += 1;
	
	int num = 0;
	num = num >> 1;
	num >>= 1;

	return 0;
}

知识点5:单目操作符—有一个操作数

 ! -  逻辑反操作
 - -  负值
 + -  正值
 & - 取地址
 * - 间接访问操作符(解引用操作符)
 sizeof - 操作数的类型长度、
 ~ - 对一个数二进制按位取反
 -- - 前置、后置--
 ++ - 前置、后置++
 (类型) - 强制类型
//操作符 ! -  逻辑反操作
int main()
{
	int a = 3;
	printf("%d\n", !a);//0为假,非0为真
	int flag = 0;
	if (flag)
	{
		//如果flag为真进来
	}
	if (!flag)
	{
		//如果flag为假进来
	}
	return 0;
}
//操作符+ -
int main()
{
	int a = -1;
	a = -a;
	a = +a;
	printf("%d\n", a);
	return 0;
}
//操作符& *
int main()
{
	int a = 10;
	int* pa = &a;//将a的地址存在pa中---pa是一个指针变量---类型为int*
	printf("%p\n", pa);//等价于printf("%p\n", &a)
	*pa = 20;//通过pa找到a的值
	printf("%d\n", a);
	return 0;
}
//操作符sizeof---计算变量所占空间的大小
int main()
{
	int a = 10;
	//计算变量所占空间的大小
	printf("%d\n", sizeof(a));//4
	printf("%d\n", sizeof(int));//4--类型不能省略括号
	printf("%d\n", sizeof a);//4

	//计算数组的总大小,单位为字节
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	printf("%d\n", sizeof(arr));//10*sizeof(int)=40
	printf("%d\n", sizeof (int [10]));//数组类型--40
	//类型为:除过变量名就是类型
	return 0;
}

// case1:陷阱1
int main()
{
	int a = 5;
	short s = 3;
	printf("%d\n", sizeof(s = a + 3));//2--与s的类型short类型字节有关
	printf("%d\n", s);//3 不改变s的值
	return 0;
}

//case2:陷阱2---指针大小不会随类型变换而变换,32位-4字节;64位-8字节
void test1(int arr[])
{
	printf("%d\n", sizeof(arr));//(2)--4或者8
}
void test2(char ch[])
{
	printf("%d\n", sizeof(ch));//(4)--4或者8
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\n", sizeof(arr));//(1)--40
	printf("%d\n", sizeof(ch));//(3)--10
	test1(arr);
	test2(ch);
	return 0;
}
//操作符~
int main()
{
	int a = 0;
	printf("%d\n", ~a);
	//分析:00000000 00000000 00000000 00000000 -补码
	//     11111111 11111111 11111111 11111111 -补码
	//     11111111 11111111 11111111 11111110 -反码
	//     10000000 00000000 00000000 00000001 -原码 -- -1
	return 0;
}

在这里插入图片描述

//案列:变某一位为1,并将其还原
int main()
{
	int a = 10;
	//二进制为:00000000 0000000 0000000 00001010 --- 将第五位变为1
	//         00000000 0000000 0000000 00010000 --- 1 << 4
	//         或|
	//         00000000 0000000 0000000 00011010 --- 或 ---将第五位变为1
	//         11111111 1111111 1111111 11101111 --- ~(1<<4)
	//         与&
	//         00000000 0000000 0000000 00001010 --- 与 ---将第五位变为1
	a = a | (1 << 4);
	printf("%d\n", a);//26

	a = a & (~(1 << 4));
	printf("%d\n", a);//10
	return 0;
}
//操作符++ --
int main()
{
	int a = 10;
	int b = ++a;//先++ 后使用
	printf("b = %d a=%d\n", b, a);//b=11,a=11
	int c = a++;//先使用,后++
	printf("c = %d a=%d\n", c, a);//c=11,a=12
	int d = a--;//先使用,后--
	printf("d = %d a=%d\n", d, a);//d=12,a=11
	int e = --a;//先--后使用
	printf("e = %d a=%d\n", e, a);//e=10,a=10
	return 0;
}
//操作符 (类型)
int main()
{
	int a = (int)3.14;//转换为整形
	printf("%d\n", a);
	return 0;
}

知识点6:关系操作符

  >,<,>=,<=,!=,==
  == - 等于
  =  - 赋值
int main()
{
	int a = 10;
	if (10 == a)
	{
		printf("%d \n", a);
	}
}

知识点7:逻辑操作符

&& -两个均为真 则为真
|| -两个均为假 则为假
注意:&&从左到右操作时,第一个为假,则不用计算后面
||从左到右操作时,第一个为真,则不用计算后面


int main()
{
	int a = 10;
	int b = 0;
	int c = a&&b;
	printf("%d\n", c);//0
	int d = a||b;
	printf("%d\n", d);//1
	return 0;
}
//case:&&与||陷阱
int main()
{
	int i = 0, a = 0, b = 2, c = 3, d = 4;
	//i = a++ && ++b && d++; //a++时,i=0,a =1 ---则为假,不用计算后面 - a =1,b = 2, c = 3, d = 4
	
	i = a++||++b||d++;//i=0,a=1;b=3,i=3 --为真,不用计算后面,a=1;b=3,c = 3, d = 4
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}

int main()
{
	int i = 0, a = 1, b = 2, c = 3, d = 4;
	//i = a++ && ++b && d++; //i=1,a=2;b=3,i=3;i=4,d=5 --- a=2,b=3,c = 3, d = 4
	i = a++ || ++b || d++;//i=1,a=2 ---为真,不用计算后面,a=2,b = 2, c = 3, d = 4
	printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
	return 0;
}

在这里插入图片描述

知识点8:条件操作符 — 三目操作符 - exp1?exp2:exp3

int main()
{
	int a = 10;
	int b = 20;
	int max = 0;
	if (a > b)
	{
		max = a;
	}
	else
	{
		max = b;
	}
	printf("max = %d\n", max);

	a > b ? a : b;
	printf("max = %d\n", max);
	return 0;
}

知识点9:逗号表达式 - exp1,exp2,exp3,…,expN

从左向右依次执行。整个表达式的结果是最后一个表达式的结果。与前面的结果没关系,前面结果只是为了计算。

int main()
{
	//代码1
	int a = 1;
	int b = 2;
	int c = (a>b, a = b + 10, a, b = a + 1); //整个表达式的结果是最后一个表达式的结果。
	//printf("%d %d %d\n", a, b, c);//12,13,13

	//代码2
	int d = 2;
	if (a = b + 1, c = a / 2, d > 0)//只决定最后一个表达式
	{
		printf("%d %d %d %d\n", a, b, c,d);//14,13,7,2
	}
	else
	{
		printf("输入错误");
	}

	//代码3 a = get_val();
	count_val(a);
	while (a > 0) 
	{
		//业务处理
		a = get_val();
		count_val(a);
	}
	//用逗号表达式修改之后
	while (a = get_val(), count_val(a), a>0) 
	{
		//业务处理
	}
}

知识点10:下标引用、函数调用和结构成员

[] -下标引用操作符 - 一个数组名 + 一个索引值
  () -函数调用操作符 - 接受一个或者多个操作数:第一个操作数是函数名,
      剩余的操作数就是传递给函数的参数。
  . -> -结构成员
//  [] -下标引用操作符
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	printf("%d\n", arr[4]);// [] - 下标引用操作符 -- 两个操作数 - 一个为arr数组名,一个4参数
	return 0;
}

//() -函数调用操作符
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;
	int sum = Add(a, b);
	printf("sum = %d\n", sum);//() -函数调用操作符 ---三个操作数 - 一个为Add函数名,另外两个为a,b参数
	return 0;
}

// . -> -结构成员
#include <stdio.h>
#include <string.h>
struct Stu //Stu结构体类型
{
	char name[10];
	int age;
	char sex[5];
	double score;
};

int main()
{
	struct Stu s = { "张三", 20, "男" , 98.89 };//s为结构体变量

	//s.name = "张三";//对于字符串不能直接赋值 -- 使用strcpy
	//strcpy(s.name, "张三");

	printf("%s\n", s.name);
	printf("%d\n", s.age);
	printf("%s\n", s.sex);
	printf("%lf\n", s.score);

	printf("-----------------\n");
	struct Stu* ps = &s;//将s的地址存在ps中,struct Stu*为结构体地址类型
	printf("%s\n", ps->name);
	printf("%d\n", ps->age);
	printf("%s\n", ps->sex);
	printf("%lf\n", ps->score);
	return 0;
}


#include <stdio.h>
#include <string.h>
struct Stu //Stu结构体类型
{
	char name[10];
	int age;
	char sex[5];
	double score;
};
void set_age1(struct Stu stu) {
	stu.age = 18;
}

void set_age2(struct Stu* pStu) {
	pStu->age = 18;//结构成员访问
}

int main()
{
	struct Stu stu;
	struct Stu* pStu = &stu;//结构成员访问

	stu.age = 20;//结构成员访问
	set_age1(stu);

	pStu->age = 20;//结构成员访问
	set_age2(pStu);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值