零基础搞定C语言——10

Posted 林慢慢i

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了零基础搞定C语言——10相关的知识,希望对你有一定的参考价值。

前言:本期的主要内容是C语言中的操作符




算数操作符

对于除号而言想要打印小数?如何做?

1.输出为1

int a = 6 / 5;
printf("%d\\n", a);

2.输出还是1

float a = 6 / 5;
printf("%f\\n", a);

3.输出为1.2,ok了

float a = 6.0 / 5;
printf("%f\\n", a);

总结,对于除号,想打印浮点数,分子分母至少一个是浮点数!




移位操作符

int main()
{
	int a = 2;
	//把a的二进制位向左移动一位
	int b = a << 1;
	printf("b = %d\\n", b);//输出为4
	return 0;
}

在这里插入图片描述

总结:左移位操作符移动的是数字的二进制,(总共32位)移动规则是左边丢弃,右边补0。

int main()
{
	int a = 10;
	//把a的二进制位向右移动1位
	int b = a >> 1;
	printf("a = %d\\n", a);
	printf("b = %d\\n", b);

	return 0;
}

在这里插入图片描述

int main()
{
	int a = -1;
	//把a的二进制位向右移动1位
	int b = a >> 1;
	//当前的右移操作符使用的:算术右移
	printf("b = %d\\n", b);

	return 0;
}

整数的二进制表示形式有三种:

原码:直接根据数值写出的二进制序列就是原码

反码:原码的符号位不变,其他位按位取反就是反码

补码:反码+1就是补码

例:以负数-1为例

原码:10000000 00000000 00000000 00000001

反码:11111111 11111111 11111111 11111110

补码:11111111 11111111 11111111 11111111

总结:右移操作符也是移动二进制,分为俩种右移:1.算数右移(通常都是这个,上边俩个例子都是算数右移):右边丢弃,左边补原符号位。2.逻辑右移:右移丢弃,左边补0。




位操作符

& 按位与

| 按位或

^ 按位异或

阅读如下代码及注释:
int main()
{
	int a = 3;
	int b = 5;

	//^  - 按(2进制)位异或
	//对应的二进制位进行异或
	//规则:相同为0,相异为1

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

	//00000000000000000000000000000011
	//00000000000000000000000000000101
	//00000000000000000000000000000110
	//6


	//  | - 按(2进制)位或
	int c = a | b;
	printf("%d\\n", c);

	//00000000000000000000000000000011
	//00000000000000000000000000000101
	//00000000000000000000000000000111
	//7
	 
	 
	//& -  按(2进制)位与
	int c = a & b;
	printf("c = %d\\n", c);
	
	//00000000000000000000000000000011
	//00000000000000000000000000000101
	//00000000000000000000000000000001
	//1
}
例题:不用第三个参数交换a、b的值

方法一(数值太大可能溢出):

a = a + b;
b = a - b;
a = a - b;
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);

方法二的理解:任何俩个相同的数异或后都是0,任何数跟0异或得到的都是那个数本身,所以b=abb可以理解成a=a^0=a。




赋值操作符

a=x=y+1;//连续赋值

注释:从右往左赋值,最终a、x均等于y+1.

a>>=3;

注释:和a=a>>3效果一样。




单目操作符

sizedof是操作符,不是函数!
printf("%d\\n", sizeof(a));//计算a所占空间的大小,单位是字节
printf("%d\\n", sizeof(int));
printf("%d\\n", sizeof a);//a不需要加(),正说明sizeof是操作符

自己思考下下面这段代码输出是多少?
short s = 5;
int a = 10;
printf("%d\\n", sizeof(s = a + 2));
printf("%d\\n", s);

输出为2、5,首先因为s是short类型,会强制截断;其次,sizeof()是在编译器里边处理的,所以()里边的表达式不会执行,压根没计算过!

取反操作符~
int main()
{
	int a = -1;
	//10000000000000000000000000000001 - 原码
	//11111111111111111111111111111110 - 反码
	//11111111111111111111111111111111 - 补码
	//~ 按位取反
	//11111111111111111111111111111111
	//00000000000000000000000000000000
	//
	int b = ~a;
	printf("%d\\n", a);
	printf("%d\\n", b);

	return 0;
}

在这里插入图片描述

前置与后置的区别:
int a = 10;
printf("%d\\n", a--);//10
printf("%d\\n", a);//9
int a = 10;
int b = a++;//后置++,先使用,再++
printf("%d\\n", a);//11
printf("%d\\n", b);//10
int a = 10;
int b = ++a;//前置++,先++,后使用
printf("%d\\n", a);//11
printf("%d\\n", b);//11
解引用操作符*
int main()
{
	int a = 10;
	printf("%p\\n", &a);//& - 取地址操作符
	int * pa = &a;//pa是用来存放地址的 - pa就是一个指针变量
	*pa = 20;//* - 解引用操作符 - 间接访问操作符
	printf("%d\\n", a);//20

	return 0;
}

在这里插入图片描述

(类型) :强制类型转换
int main()
{
	int a = (int)3.14;

	return 0;
}
指针大小永远是4字节或8字节
void test1(int arr[])//相当于int *arr
{
	printf("%d\\n", sizeof(arr));//4
}
void test2(char ch[])//相当于char *arr
{
	printf("%d\\n", sizeof(ch));//4
}
int main()
{
	int arr[10] = { 0 };
	char ch[10] = { 0 };
	printf("%d\\n", sizeof(arr));//40
	printf("%d\\n", sizeof(ch));//10
	test1(arr);
	test2(arr);
	return 0;
}

在这里插入图片描述




双目操作符

逻辑与:&&

逻辑或:||

注意与按位与、按位或区分开。

1&2   ----->0
1&&2  ----->1
    
1|2   ----->3
1||2  ----->1
    
想下如下程序段输出结果是多少?
int main()
{
    int i = 0, a = 0, b = 2, c = 3, d = 4;
    i = a++ && ++b && d++;//i=0表达式为假,后边都不执行
    printf("a = %d\\nb = %d\\nc = %d\\nd =%d\\n", a, b, c, d);
    return 0;
}

与运算符,i=0表达式判断前边就为假,后边都不执行

在这里插入图片描述

int main()
{
    int i = 0, a = 0, b = 2, c = 3, d = 4;
   /* i = a++ && ++b && d++;*/

    i = a++ || ++b || d++;//或运算符,第一个为假就判断第二个。
    printf("a = %d\\nb = %d\\nc = %d\\nd =%d\\n", a, b, c, d);

    return 0;
}

在这里插入图片描述

int main()
{
    int i = 0, a = 0, b = -1, c = 3, d = 4;
    i = a++ || ++b || d++;
    printf("a = %d\\nb = %d\\nc = %d\\nd =%d\\n", a, b, c, d);

    return 0;
}

在这里插入图片描述

总结:

与运算符,i=0表达式第一个假,后边都不执行,若第一个为真继续判断第二个,第二个为真在判断第三个;或运算符,第一个为假就判断第二个,第二个也为假就判断第三个,若是第一个为真后边也不需要计算。




逗号表达式

从左向右依次计算,但是整个表达式的结果是最后一个表达式的结果,但不能只计算最后一个的结果,前边表达式可能影响最后一个表达式的值。

int main()
{
	int a = 3;
	int b = 5;
	int c = 0;
	//逗号表达式 - 要从左向右依次计算,但是整个表达式的结果是最后一个表达式的结果
	int d = (c = 1, a = c + 3, b = a - 4, c += b);
    //a=4         b=0    c=1  
    
	printf("%d\\n%d\\n%d\\n%d\\n", d,a,b,c);

	return 0;
}

在这里插入图片描述

推理下面代码运行过程:
#include <stdio.h>
int main()
{
	int a, b, c;
	a = 5;
	c = ++a;    // ++a:加给a+1,结果为6,用加完之后的结果给c赋值,因此:a = 6  c = 6
	
    b = ++c, c++, ++a, a++;  
    // ++c:c为7 c++:c值不变 ++a:a的值为7,a++:a值不变,b取a的值:7
	// 表达式结束时,c++和a++会给a和c分别加1,此时c:8,a:8,b:7
    
	b += a++ + c; 
    // a先和c加,结果为16,在加上b的值7,比的结果为23,最后给a加1,a的值为9
	
    printf("a = %d b = %d c = %d\\n:", a, b, c); 
    // a:9, b:23, c:8
	return 0;
}

(a = 9 b= 23 c = 8 )




结构成员访问操作符

.
->

很多时候int float char short double long 这些数据类型不够用,比如:书:书名,书号,定价。这就需要我们去自定义一个结构体

访问结构体内容的俩种方式:

结构体变量名.成员名

结构体指针->成员名

实例:
//创建了一个自定义的类型
struct Book
{
	//结构体的成员(变量)
	char name[20];
	char id[20];
	int price;
};

int main()
{
	int num = 10;
	//结构体变量名.成员名
	struct Book b = {"C语言", "C20210509", 55};
 	printf("书名:%s\\n", b.name);//%s打印字符串
	printf("书号:%s\\n", b.id);
	printf("定价:%d\\n", b.price);

	struct Book * pb = &b;//说明pb是struct Book类型的指针

	//结构体指针->成员名
	printf("书名:%s\\n", pb->name);
	printf("书号:%s\\n", pb->id);
	printf("定价:%d\\n", pb->price);

	printf("书名:%s\\n", (*pb).name);
	printf("书号:%s\\n", (*pb).id);
	printf("定价:%d\\n", (*pb).price);


	return 0;
}

在这里插入图片描述




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

char类型打印成整形必然发生整形提升,char只有8个比特位,提升就变成32位。char只有一个字节,CPU内整型运算器的操作数的字节长度一般就是int的字节长度(4个字节)

负数的整形提升:

char c1=-1;变量c1的二进制位(补码)中只有8个比特位:11111111,因为char为有符号的char,高位补充符号位即为1,提升后是:11111111 11111111 11111111 11111111

char c2=1;变量c2的二进制位(补码)中只有8个比特位:00000001,因为char为有符号的char,高位补充符号位即为0,提升后是:00000000 00000000 00000000 00000001

无符号的整形提升,高位补0

例题1:
int main()
{
	char a = 3;
	//00000000000000000000000000000011
	//00000011 - a
	char b = 127;
	//00000000000000000000000001111111
	//01111111 - b

	char c = a + b;
	//00000000000000000000000000000011
	//00000000000000000000000001111111
	//00000000000000000000000010000010
	
	//10000010 - c
	//11111111111111111111111110000010 - 补码
	//11111111111111111111111110000001 - 反码
	//10000000000000000000000001111110 - 原码
	//-126
	//发现a和b都是char类型的,都没有达到一个int的大小
	//这里就会发生整形提升

	printf("%d\\n", c); //-126

	return 0;
}
例题2:
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;

	if (a == 0xb6)//发生整形提升,不一样了
		printf("a");
	if (b == 0xb600)//发生整形提升,不一样了
		printf("b");
	if (c == 0xb6000000)//不发生整形提升,不一样了
		printf("c");

	return 0;
}

注释:例题2只会输出c

例题3:
int main()
{
	char c = 1;
	printf("%u\\n", sizeof(c));//1
	printf("%u\\n", sizeof(+c));//4
	printf("%u\\n", sizeof(-c));//4
	printf("%u\\n", sizeof(!c));//4 gcc - 4

	return 0;
}

总结:char跟short这俩种类型,因为在参与表达式运算的时候达不到整型长度,会发生整型提升!而比int大的类似float等等不需要整形提升。

算术转换

如果某个操作符的各个操作数属于不同类型,那么某些操作数必然要转换为其它操作数的类型。

例如:int转换成float(往精度更高的转)

b6000000;

if (a == 0xb6)//发生整形提升,不一样了
	printf("a");
if (b == 0xb600)//发生整形提升,不一样了
	printf("b");
if (c == 0xb6000000)//不发生整形提升,不一样了
	printf("c");

return 0;

}


>  注释:例题2只会输出c

###### 例题3:

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

	return 0;
}

总结:char跟short这俩种类型,因为在参与表达式运算的时候达不到整型长度,会发生整型提升!而比int大的类似float等等不需要整形提升。

算术转换

如果某个操作符的各个操作数属于不同类型,那么某些操作数必然要转换为其它操作数的类型。

例如:int转换成float(往精度更高的转)

以上是关于零基础搞定C语言——10的主要内容,如果未能解决你的问题,请参考以下文章

零基础搞定C语言——导航汇总篇

零基础搞定C语言——9

零基础搞定C语言——8

结构体struct零基础搞定C语言——12

指针初阶零基础搞定C语言——11

免费报表工具零代码零基础轻松搞定 web 报表