【C语言】6.操作符2

6. 关系操作符

>

>=

<

<=

! = 用于测试“不相等”

== 用于测试“相等”

注: 在编程的过程中 == 和 = 不小心写错,导致的错误。

7. 逻辑操作符

逻辑操作符有哪些︰
&&		逻辑与
||		逻辑或

区分逻辑与和按位与区分逻辑或和按位或
    1 & 2-----> 0
    1 && 2----> 1
    1 | 2-----> 3
    1 || 2----> 1
    
逻辑与和或的特点∶
    逻辑与 && 表示的是交集,2个条件同时成立,结果才为真
    逻辑或 || 表示的并集,只要有一个条件成立,结果就为真
#include <stdio.h>

int main()
{
    int a = 5;
    int b = 20;
    //int c;

    if (a && b)//逻辑与 a 与 b 不为 0,为真
    {
        printf("Line 1 - 条件为真\n");//执行
    }

    if (a || b)//逻辑或  a 与 b 任意一个非零,则条件为真
    {
        printf("Line 2 - 条件为真\n");//执行
    }

    if (!(a && b))//条件为真则逻辑非运算符将使其为假
    {
        printf("Line 3 - 条件为真\n");
    }
    else
    {
        printf("Line 3 - 条件为假\n");//执行
    }

    return 0;
}

7.1 笔试题

#include <stdio.h>

int main()
{
	int i = 0, a = 0, 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);//1	2	3	4
	/*
	因为a++是后置++,先使用a再++,a在此时是0,为假,
	逻辑与只要一个为假全部为假,所以a++之后的没有执行
		b仍等于2	c仍等于3	d仍等于4

	*/

	return 0;
}
#include <stdio.h>

int main()
{
    int i = 0, a = 0, 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);//1 3 3 4
	/*
	逻辑或:只要有个判断为真就为真,a++先使用a后++,a是0,所以为假
	然后 ++b 先 ++ 后使用,所以不为0,为真所以b之后判断停止执行
		c仍等于3	d仍等于4
	*/

	return 0;
}
#include <stdio.h>

int main()
{
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    
	//将 a++ 改成 ++a
	i = ++a || ++b || d++;
	printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c, d);//1	2	3	4	
	/*
	因为 ++a 是++操作并使用,a为1,所以为真,为真之后判断停止执行
		b仍等于2	c仍等于3	d仍等于4
	*/

	return 0;
}

8. 条件操作符

//条件操作符
//
//三目运算符
//	exp1 ? exp2 : exp3

#include <stdio.h>
	
int main()
{
	int a = 0;
	int b = 0;

	if (a > 5)
		b = 3;
	else
		b = -3;
	printf("b = %d\n", b);

	b = (a < 5 ? 3 : -3);
	printf("b = %d\n", b);

	return 0;
}
#include <stdio.h>

int main()
{

	//求两数最大值
	int a = 10;
	int b = 20;
	int max = 0;

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

9. 逗号表达式

exp1,exp2,exp3,...expN
	逗号表达式,就是用逗号隔开的多个表达式。逗号表达式,从左向右依次执行。
	整个表达式的结果是最后一个表达式的结果。
#include <stdio.h>

int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
	printf("c = %d\n", c);//输出答案13,计算到最后只保留最后一个表达式

	return 0;
}
#include <stdio.h>

int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
	printf("c = %d\n", c);

	int d = 0;
	if (a = b + 1, c = a / 2, d > 0)//逗号表达式
	{
		printf("c = %d\n", c);
		printf("123");
	}
	else
	{
		printf("c = %d\n", c);
		printf("777");
	}
	
	return 0;
}
#include <stdio.h>

int main()
{
	//代码3
	int a = 1;
	a = get_val();
	count_val(a);
	while (a > 0)
	{
		//业务处理
		a = get_val();
		count_val(a);
	}

	//如果使用逗号表达式,改写:
	while (a = get_va1(), count_va1(a), a > 0)
	{
		//业务处理
	}

	return 0;
}

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

  1. [ ]下标引用操作符

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

#include <stdio.h>

/*
	1.	[ ]下标引用操作符
		操作数:一个数组名+一个索引值
*/
int main()
{
	int arr[10];//创建数组
	arr[9] = 10;//实用下标引用操作符。[]的两个操作数是arr和9。

	return 0;
}
  1. ()函数调用操作符

    ()函数调用操作符接受一个或者多个操作数︰第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

/*
	()函数调用操作符:
		()函数调用操作符接受一个或者多个操作数︰
		第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
*/
#include <stdio.h>

void test1()
{
	printf("hehe\n");
}
void test2(const char* str)
{
	printf("%s\n", str);
}
int main()
{
	test1();            //实用()作为函数调用操作符。
	test2("hello world");//实用()作为函数调用操作符。

	return 0;
}
#include <stdio.h>

//函数调用操作符
get_max(int x, int y)
{
	return x > y ? x : y;
}

int main()
{
	int a = 10;
	int b = 20;
	//调用函数的时候()就是函数调用符
	int max = get_max(a, b);
	printf("max = %d\n", max);

	return 0;
}
  1. 访问一个结构的成员
//下标引用、函数调用和结构成员

/**
 * 访问一个结构的成员
 * . 结构体			    .成员名 
 * -> 结构体指针	    ->成员名
*/

//创建一个结构体类型 -struct Stu
#include <stdio.h>

struct Stu
{
	char name[20];
	int age;
	char id[20];
};

int main()
{
	int a = 0;
	//使用struct Stu这个类型创建一个学生对象s1,并初始化
	struct Stu s1 = { "张三",20,"20201128" };


	//打印结构体内容
	//结构体变量.成员名(结构体变量 点 成员名)
	printf("%s\n",s1.name);
	printf("%d\n", s1.age);
	printf("%s\n", s1.id);

	//有点啰嗦
	struct Stu* ps = &s1;
	printf("%s\n", (*ps).name);
	printf("%d\n", (*ps).age);
	printf("%s\n", (*ps).id);

	//更好的打印方法
	//struct Stu* ps = &s1;
	printf("%s\n", ps->name);
	printf("%d\n", ps->age);
	printf("%s\n", ps->id);

	return 0;
}

eg:

#include <stdio.h>

struct Stu
{
	char name[10];
	int age;
	char sex[5];
	double score;
};

void set_age1(struct Stu stu)
{
	stu.age = 18;
	printf("自定义的set_age1函数的age = %d\n", stu.age);
}
void set_age2(struct Stu* pStu)
{
	pStu->age = 19;//结构成员访问
	printf("自定义的set_age2函数的age = %d\n", pStu->age);
};
int main()
{
	struct Stu stu;
	struct Stu* pStu = &stu;
	
	stu.age = 20;
	printf("age = %d\n", stu.age);
	set_age1(stu);

	pStu->age = 20;
	printf("age = %d\n", pStu->age);
	set_age2(pStu);
	
	return 0;
}

11. 表达式求值

11.1 隐式类型转换

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

整型提升的意义︰

​ 表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

​ 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。

​ 通用CPU ( general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。

​ 所以,表达式中各种长度可能小于 int 长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

#include <stdio.h>

int main()
{
	char a = 3;
	//00000000000000000000000000000011 -- 被截断
	//00000011 - a  -- 截断后

	char b = 127;
	//00000000000000000000000001111111 -- 被截断
	//01111111 - b -- 截断后

	// a 和 b 如何相加?
	//00000000000000000000000000000011
	//00000000000000000000000001111111
	//00000000000000000000000010000010 -- 被截断

	char c = a + b;
	//10000010 - c -- 截断后
	//整型提升
	//11111111111111111111111110000010 - 补码
	//11111111111111111111111110000001 - 反码
	//10000000000000000000000001111110 - 原码
	//-126

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

	return 0;
}

//因为char类型被定义了整型值,32个字节,而char类型只能存放8个字节,所以被截断,从小位(右边)开始截断
//整型提升是因为进行运算的数达不到运算要求而进行的操作
//b和c的值被提升为普通整型,然后再执行加法运算。加法运算完成之后,结果将被截断,然后再存储于a中。

在这里插入图片描述

如何进行整体提升呢?

  • 整型提升是按照变量的数据类型的符号位来提升的
#include <stdio.h>

int main()
{
	//负数的整形提升
	char c1 = -1;
	//变量c1的二进制位(补码)中只有8个比特位:1111111
	//因为char 为有符号的char
	//所以整形提升的时候,高位补充符号位,即为1
	//提升之后的结果是 :
	//11111111111111111111111111111111
	
	//正数的整形提升
	char c2 = 1;
	变量c2的二进制位(补码)中只有8个比特位:00000001
	//因为char为有符号的char
	//所以整形提升的时候,高位补充符号位,即为0
	//提升之后的结果是 :
	//00000000000000000000000000000001
	
	//无符号整形提升,高位补O

	return 0;
}

整型提升的例子

1

#include <stdio.h>

int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	
	if (a == 0xb6)
		printf("a");//	a整型提升,所以与Ox600不匹配,不打印a

	if (b == 0xb600)
		printf("b");//	b整型提升,所以与Ox6000不匹配,不打印b

	if (c == 0xb6000000)
		printf("c");//	c就是整型,所以匹配成功打印c

	return 0;
}
/*
	例子中的a,b要进行整形提升,但是c不需要整形提升a,
	b整形提升之后,变成了负数,所以表达式a==0xb6 , b==0xb600的结果是假,
	但是c不发生整形提升,则表达式c==Oxb6000000的结果是真.
	所以程序输出的结果是:c
*/

在这里插入图片描述

2

#include <stdio.h>

int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));//1
	printf("%u\n", sizeof(+c));//4
	printf("%u\n", sizeof(-c));//4

	return 0;
}
/*
	例子中的,c只要参与表达式运算,就会发生整形提升,表达式+c ,就会发生提升,所以sizeof(+c)是4个字节.
	表达式-c也会发生整形提升,所以sizeof(-c)是4个字节,但是sizeof(c),就是1个字节.
*/

11.2 算术转换

​ 如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换。

long double
double
float
unsigned long int
long int
unsigned int
int 

​ 如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

#include <stdio.h>

int main()
{
   float f = 3.14;
   int num = f;//隐式转换,会有精度丢失
   printf("%d", num);//3

   return 0;
}

11.3 操作符的属性

复杂表达式的求值有三个影响的因素。

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?

取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性

操作符优先级

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

说明:

  • 同一优先级的运算符,运算次序由结合方向所决定。
  • 简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

12. 练习

12.1 选择题

下面代码的结果是:(C)

/*
	char* pc每次操作一个字节
	因此char* pc = 0操作只改变a的44为0
	所以打印的是11 22 33 00

*/

#include <stdio.h>

int main()
{
	int a = 0x11223344;
	char* pc = (char*)&a;
	*pc = 0;
	printf("%x\n", a);

	return 0;
}

在这里插入图片描述

#include <stdio.h>

/*
short每次改变两个字节的
for循环四次,所以改变了八个字节int类型是四个字节
所以for循环只改变前面数组的两个元素所以答案是0 0 3 4 5
*/
int main()
{
	int arr[] = { 1,2,3,4,5 };
	short* p = (short*)arr;
	int i = 0;
	for ( i = 0;  i < 4;  i++)
	{
		*(p + i) = 0;
	}

	for ( i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

12.2 解释代码意思

  1. 下面代码输出的是什么:
#include <stdio.h> 

int i;//全局变量-不初始化-默认是0

int main()
{
	i--;
	//-1
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	//
	if (i > sizeof(i)) //sizeof() - 计算变量 / 类型所占内存的大小 >= 无符号数
					   //sizeof求得大小大于或等于0,所哟一sizeof不可能是负数
	{
		printf(">\n");
	}
	else
	{
		printf("<\n");
	}

	return 0;
}

/*
	当sizeof (i)的数转成无符号数
	i和sizeof (i)比较的话
	i会被转换成无符号的整数,
	-1被转换成无符号的整数会变成很大的数
	所以i>sizeof(i)
	所以为真,输出 >

*/
  1. 下面代码输出的是什么:
#include <stdio.h>

int main()
{
	int a, b, c;
	a = 5;//a = 6
	c = ++a;//c =6

	/*
		等于号=的优先级大于逗号,所以先计算 b = ++c , b= 7, c= 7 
		c++ =8
		++a = 7
		a++ = 8
	*/
	b = ++c, c++, ++a, a++;

	/*
		+=的优先级小于+,
		所以a++ =9,因为是后置++,所以先赋值后加加
		所以b 加的a其实等于8
		运算之后a加加等于9
		再加c = 8
		b = b + a + c = 23
			7   8   8 
	*/
	b += a++ + c;

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

	return 0;
}

在这里插入图片描述

12.3 求a的二进制(补码)表示中有几个 1

算法1

//写一个函数求a的二进制(补码)表示中有几个1

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

int count_bit_one(int n)
{
	int count = 0;
	while (n)
	{
		if (n % 2 == 1)
		{
			count++;
		}
		n = n / 2;
	}
	return count;
}

int main()
{
	int a = 0;
	scanf("%d", &a);
	int count = count_bit_one(a);
	printf("count = %d\n", count);

	return 0;
}

出现问题:输入 -1 出现问题

在这里插入图片描述

 //写一个函数求a的二进制(补码)表示中有几个1

 //-1出现问题
//修改
#include <stdio.h>
#include <stdlib.h>

int count_bit_one(unsigned int n)//修改处:unsigned int n
{
	int count = 0;
	while (n)
	{
		if (n % 2 == 1)
		{
			count++;
		}
		n = n / 2;
	}
	return count;
}

int main()
{
	int a = 0;
	scanf("%d", &a);
	int count = count_bit_one(a);
	printf("count = %d\n", count);

	return 0;
}

算法2:按位与

 //写一个函数求a的二进制(补码)表示中有几个1

 //另一个算法:
/*
	先右移操作
	然后和 1 (000000000000000000000000000000000001) 按位与若按位与操作等于1,则执行if语句
	循环执行,直到32位遍历完
*/
#include <stdio.h>

int count_bit_one(int n)
{
	int count = 0;
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (((n >> i) & 1) == 1)
		{
			count++;
		}
	}
	return count;
}

int main()
{
	int a = 0;
	scanf("%d", &a);

	//写一个函数求a的二进制(补码)表示中有几个1
	int count = count_bit_one(a);//-1
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	//00000000000000000000000000000001

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

	return 0;
}

算法3

 //写一个函数求a的二进制(补码)表示中有几个1

 //第三种算法
/*
	n = n & (n -1)
	n
	13
	1101 n
	1100 n - 1
	1100 n - 1
	1000 n
	0111 n - 1
	0000 n 
*/
#include <stdio.h>
int count_bit_one(int n)
{
	int count = 0;
	while (n)
	{
		n = n & (n - 1);
		count++;
	}
	return count;
}
int main()
{
	int a = 0;
	scanf("%d", &a);
	//写一个函数求a的二进制(补码)表示中有几个1
	int count = count_bit_one(a);//-1
	//10000000000000000000000000000001
	//11111111111111111111111111111110
	//11111111111111111111111111111111
	//00000000000000000000000000000001
	printf("count = %d\n", count);

	return 0;
}

13.4 求二进制中不同位的个数

编程实现:

两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?

输入例子: 1999 2299

输出例子: 7

//求二进制中不同位的个数题目内容:
//编程实现:
//两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同 ?
//	输入例子 : 1999 2299
//	输出例子 : 7


#include <stdio.h>

int get_diff_bit(int m, int n)
{
	int tmp = m ^ n;
	int count = 0;
	//return count_bit_one(tmp);
	while (tmp)
	{
		tmp = tmp & (tmp - 1);
		count++;
	}
}

int main()
{
	int m = 0;
	int n = 0;
	scanf("%d%d", &n, &m);
	int count = get_diff_bit(m, n);
	printf("count = %d\n", count);

	return 0;
}

12.5 交换二进制的奇数位和偶数位

题目内容:

获取一个整数二进制序列中所有的偶数数位和奇数位,分别打印出二进制序列

//交换二进制的奇数位和偶数位
//题目内容 :
//获取一个整数二进制序列中所有的偶数数位和奇数位,分别打印出二进制序列

#include <stdio.h>

void print(int m)
{
	int i = 0;
	printf("奇数位:\n");
	for (i = 30; i >= 0; i -= 2)
	{
		printf("%d", (m >> i) & 1);
	}
	printf("\n");
	printf("偶数位:\n");
	for (i = 31; i >= 1; i -= 2)
	{
		printf("%d", (m >> i) & 1);
	}
	printf("\n");
}

int main()
{
	int m = 0;
	scanf("%d", &m);
	print(m);

	return 0;
}

GitHub代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值