零基础搞定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的主要内容,如果未能解决你的问题,请参考以下文章