硅基计划 学习总结 拾
一、结构成员
##引子##
如果我么想规划一个区域来存储我们的相关信息,但又不想很杂乱的存储,那我们可以用到结构体这个函数,来帮助我们结构化管理信息,我们暂时只介绍“.”
1.结构体
它可以用于复杂的、多个对象的,属于自定义数据类型,你可以自定义一些值的集合,值可以是不同类型的变量,甚至是嵌套结构体
我们给出示例:
struct tag(函数名)
{//一些成员列表
}(变量的列表,可有可无,可以在创建结构化函数时候创建变量,默认是全局变量);
##我们给出一段代码,参照上面的注释,我想你应该能明白,这里不过多赘述啦
struct adr
{char name[10];
};struct stu//先规定好结构体内部信息
{struct adr one [10];//这里的one是结构体名称char name[10];int age;float score;
};int main()
{//struct stu s1 = {"xiao_san",20,95.5f};//我们可以利用这个结构体存储不同的信息,这里s1代表一号学生//我们也可以不按照顺序初始化,可以指定初始化内容,利用“.”/*struct stu s1 = { .name = "zlh",.age=18,.score=95.5 };*///如果结构体里面套一个结构体呢?这个时候我们如何初始化呢?struct stu s3 = { {"heihei"},"wangwu",20,99.9f };//这里我们的括号里的括号就是针对adress来初始化的,如果里面还有数组,我们再加括号即可printf("%s\n", s3.one[0].name);//你可以添加多个“.”来访问多层结构体里的元素,注意结构体中你规定的存了10个信息,下标也是从0开始return 0;
}
二、操作符优先级
1.优先级
表达式含有各个运算符,优先级高的先执行,例如3+4*5=23;
2.结合性
假设优先级相同,那这个时候结合性说了算,究竟是左结合还是右结合,大部分都是左结合,少部分右结合,例如5*6/2=15,具体参照下表:
##你肯定想到这么多,我们懒得记,我们就记一些常用的吧
1.圆括号( () ),自增运算符( ++ ),自减运算符(-- )
2.单目运算符( + 和 ) • 乘法( * ),除法( / ) • 加法( + ),减法( )
3.关系运算符( < 、 > 等)
4.• 赋值运算符( = )
如果你不想这么麻烦,有一个终极办法,你想哪个部分先计算,就把哪个部分用括号括起
三、表达式求值
1.整型提升
整型默认是int类型,如果你想用long long类型你只需在数据后加上字母“ll”,为了获得这种精度,表达式中字符和短整型使用之前要被转化为普通整型
整型提升规则
1.有符号整型按照变量的数据类型的符号位提升,即其他位要么补0要么补1
2.无符号整数提升高位直接补0
为什么要这样做,这是因为CPU难以用除4字节或者8字节其他非4字节类型计算
##我们举个例子:
int main()
{char a = 20;char b = 120;char c = a + b;printf("%d", c);//为什么结果是-116?return 0;
}
为什么结果是-116?为什么你正数结果后面给我搞出个负数?诶,我们娓娓道来
##拓展:%d我们也可以十进制形式打印一个有符号整型int
1.首先我们要知道char类型的取值范围是-128~127,而你变量C求出来后是140,存不下呀
2.而且你char类型的变量只能接收一个字节大小,即8个比特位,对于二进制8位,那必然要对你二进制表示进行取舍
3.我们开始存取数据
变量a的值是20,转化成二进制后的补码是0000 0000 0000 0000 0000 0000 0001 0100,而你char类型只能存8比特位,即存入0001 0100,相当于把20这个值截断后存入
同理我们来存入b变量值120,转化成二进制补码是0000 0000 0000 0000 0000 0000 0111 1000,同理char类型变量我们存入8比特位,即0111 1000
4.要想相加,你只有8比特位显然是不行的,要进行整型提升,按照规则,a提升后为(高位补0):0000 0000 0000 0000 0000 0000 0001 0100,同理b为:0000 0000 0000 0000 0000 0000 0111 1000,我们再把两个整型提升后的变量相加,结果是:0000 0000 0000 0000 0000 0000 1000 1100
5.我们再把这个变量存入char类型中,截断后为1000 1100,但是你打印类型是整型,我们得再次发生整型提升(根据规则,符号位是1,我们高位补1)之后再转换成原码进行打印:1000 0000 0000 0000 0000 0000 0111 0100,打印的结果就是-116了
##怎么样,看似简单的算式背后可是有很复杂的逻辑
2.算数转化:如果你的各个操作数属于不同类型,我们要将其中一个操作数类型转化成另外一个操作数类型,我们根据下面这个表由下到上转化优先级(int是起点)
感谢比特教育科技提供的图解,感谢
四、问题表达式
##有时候有些人在写程序,也不知道脑回路是怎样的,写的程序让编译器都不知所措
1.加法优先级问题
a*b+c*d+e*f;
这个表达式如果是你,你肯定先算乘法再加起来
但是机器不管这些,都有自己独特算法
比如我们先计算前两个乘法,相加后,第三个乘法计算后,再相加
又或是先计算三个乘法,把前两个结果相加后得到的结果,再和第三个乘法结果相加
如果是变量值还好,但假设是表达式呢,是不是会影响最终结果
2.C到底何时加
C+ ++C;
这个代码问题在于到底是什么时候加上C,是我++之后还是++之前呢?
3.逻辑混乱
int i = 10;
i = i-- - --u*(i=3)*i++ + ++i;
第一眼你看到这个代码是不是想这个表达式到底要传达什么意思,如果你用不同编辑器去计算,会有不同结果,这个算式出自于一本书《C和指针》作者都抓狂了这个代码
感谢比特教育机构提供的图
4.fun函数究竟什么时候开始调用
int fun()
{static int count = 1;return ++ count;
}int main()
{int answer;answer = fun()-fun()*fun()
printf("%d\n",answer);
return 0;
}
##如果你把这个表达式放在VS2022中,结果就是2-3*4=-10
5.这位更是重量级
int main()
{int i = 1;int ret = (++i) + (++i)+(++i);printf("%d\n", ret);printf("%d\n", i);return 0;//VS中是12 4,而你用Dev是10 4
}
为什么是截然不同的结果
在VS中是算出三个++i之后的i的结果再把三个i相加
而在Dev中是先算出前两个++i之后,先把前两个i相加,最后再i再加1,之后再把上一次相加值加到这一次
我搞不明白为什么有的学校把这个当成期末考试题还给出选项
因此,我们不要写以上这些难看的low代码,想先算哪个加括号就好
五、内存
1.我们都知道1byte(比特)=8字节,其他都是1024进制转化
2.我们把内存划分成一个个小的空间,每一个空间都是一个字节,为一个内存单元,我们可以给内存单元编号,就是指针,就是地址
3.各个硬件之间进行数据传递,CPU与内存之间有很多“线”连接起来,一般有“地址总线”,“数据总线”,“控制总线”,我们读写都是通过这些进行的
4.CPU访问内存的时候需要知道其位置,我们就给内存编址,给每个内存单元编号(硬件设计的时候已经编好)
32位机器有32根地址总线,每根总线有0和1两张状态,攻击2的32次方中编号,64位机器择优2的64次方种编号
六、指针变量和地址(Part 1)
1.取地址操作符(&)
我们回忆下,变量创建的本质是什么,就是在内存中申请4个字节空间,以此来存储数据
例如int a =10,其中这个a不是给编译器和计算机看的,是给你看的,它们看的是地址
你可以在调试中找到监视输入取地址操作符查看变量a的地址,中间那一行是十六进制存储的,比如10=1011=啊,我们就可以看到000a
但是a它有四个字节啊,不应该有四个地址吗,如果你通过取地址操作符,你会看到是地址中较小的地址,为什么?
因为这样可以顺理成章求出其他地址,存放地址的变量就成为指针变量,如:
int *p=&a,这里的int *就为a的类型,而且指针变量是专门存放地址的,在它的眼里什么都是地址
3.解引用操作符(“*”)
int a =10;
int *p=&a;
*p=0;
我们注意区分下面两个式子区别,下面那个式子中,“*”是用来间接访问的,通过p的地址找到地址所对应的对象,这是另一种放大求变量
4.指针变量的大小
因为指针也是变量,也是需要向内存中申请空间的
我们根据地址存储大小,32位的机器通过32跟地址线传输,需要32bit=4字节空间存储
因此指针变量大小是4字节,不管你指针变量里面的数据是什么类型
统统都是4字节,而六十四位机器就是8字节
作者学术不精,难免有疏漏,若有错误欢迎指出,评论区讨论
END