- 博客(45)
- 收藏
- 关注
原创 网络基础(二)
在发送的设备中 网络层也有自己的IP地址 也具有自己的路由功能 而在同一个子网中 大家IP地址的前缀是相同的 所以通过目的IP地址的前缀与自己的前缀进行判断 就能区分 如果是相同IP地址 那么说明这个数据是在当前1局域网传播的 如果前缀不同 说明要进行垮局域网传播。内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的 多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之 分.这就要在网络的背景下,在系统中,标识主机的唯一性。
2025-03-25 10:55:15
894
原创 网络基础
例子在上课时 老师提问张三问题 这是所有都会听到的 但是只有张三站起来回答问题 其他人是不会站起来的 这是因为只有张三的名字叫做张三 也就是只有这一台的MAC地址是能够与发出的信号上的目的MAC地址进行匹配的 而其他人虽然也接受到了 但是由于MAC地址的不同 是不会抓取信息的。在TCP/IP在内核中实现的 网络协议栈在不同的系统中是完全相同的 通过相同的协议栈就来实现通信 网络其实操作系统的一部分 而网络在所有操作系统中的都是一致的 所以将网络单独拎出来学习。:负责信号传输,是网络通信的基础。
2025-03-23 08:00:00
720
原创 工作日志 线程池概念 线程安全单例模式 线程安全 与 函数重入 死锁概念
⽇志认识计算机中的⽇志是记录系统和软件运⾏中发⽣事件的⽂件,主要作⽤是监控运⾏状态、记录异常信 息,帮助快速定位问题并⽀持程序员进⾏问题修复。它是系统维护、故障排查和安全管理的重要⼯ 具。⽇志格式以下⼏个指标是必须得有的• 时间戳• ⽇志等级• ⽇志内容以下⼏个指标是可选的• ⽂件名⾏号• 进程,线程相关id信息等线程池: ⼀种线程使⽤模式。线程过多会带来调度开销,进⽽影响缓存局部性和整体性能。⽽线程池维护着多 个线程,等待着监督管理者分配可并发执⾏的任务。
2025-03-22 08:00:00
621
原创 虚拟地址物理地址转换 缺页中断 线程优缺点 线程控制
首先我们先介绍虚拟地址与物理地址之间的转换原理首先我们要有的认识时 在我们讨论虚拟物理地址之间的转换时 地址映射关系已经在加载时就已经完成了。
2025-03-21 08:00:00
1209
原创 linux线程进程对比 线程控制
2.返回值 线程退出方式 1.return 其他线程return退出只是当前线程退出 而如果是主线程退出的话 真个进程都会退出 返回值的类型也是(void*) 也就是说返回值的类型也可以是任意的 也可以一次性返回多个类型。线程取消 pthread_cancel (线程一定是被其他线程取消的 也就是说一定是其他线程调用此函数来取消当前线程) 1.必须要join等待 2.返回值一定为-1。4.进程中函数 线程是共享的 只要有对应函数的入口地址 每个线程都可以访问。5.全局变量在线程内部是共享的。
2025-03-20 08:00:00
407
原创 线程概念与地址空间
我们的虚拟地址有32位前十位用于在页目录中查找对应的页表地址 中10位用查找页表中对应的起始页框地址 后十二位表示的页框中的一个偏移量 之后我们按照类型的4字节或者8字节等进行查找 数据就可以被有效的读取到了。在进程中每个进程都有属于自己的pid 而我们的lwp也可以算是线程的id号 新线程的pid与进程pid好是相同的 而两者的pid是不同的 指令查看 LWP : ps-al| head -1 && ps -aL| grep mythread。:线程的启动函数,即线程开始执行时调用的函数。
2025-03-19 08:00:00
890
原创 共享栈 线程局部存储 线程互斥 线程同步 消费者生产者模型
共享栈 第一个主线程会在栈区 而当其他线程创建时实在共享区动态申请的栈区线程局部存储 __thread 关键字 与编译有关全局变量是被线程共享的 每个线程都能看到 修改 但是如果对该全局变量加上__thread关键字后 该全局变量就不会被共享 将变量在库中的每一个线程的属性集合中都会添加一份 访问时用的是自己属性中的变量地址 这样每个线程访问的地址不同也就不会起冲突了类本身就是一个全局变量在共享区动态创建的共享栈是不会动态向下生长的 是固定大小8M 通过mmap调用穿件stack。
2025-03-18 21:46:42
1035
原创 用户态 内核态 可重入函数 volatile SIGCHLD信号
2.为什么从4返回到用户态时不直接回到1 而是要进入内核态的5 最后在返回 内存区 这里与函数调用栈针的原理相似 在调用系统调用函数时 首先将下一条要执行的代码指令放入栈中 之后执行系统调用函数 而在调用系统调用函数时实在os态中执行的 所以想要返回到下一条指令的位置 就要先进入内核态中将栈中的下一条执行指令弹出 这样再从内核态放回用户态 完成系统调用。进程是程序的运行实例,操作系统负责进程的创建、调度、同步和通信。操作系统通过文件系统管理磁盘上的文件和目录,支持文件的创建、读写、删除和权限控制。
2025-03-18 08:00:00
808
原创 进程信号 信号记录 捕捉信号
对于信号的捕捉 除了自定义信号 还有 忽略信号和默认行为现在我们介绍忽略信号SIG_DFL定义为。表示使用默认动作处理信号。默认动作通常是操作系统为特定信号预设的处理方式,例如终止进程、忽略信号或生成核心转储文件等。SIG_IGN定义为。表示忽略信号,即不对信号采取任何行动。当用户按下Ctrl+C时(通常发送SIGINT信号),程序会调用函数处理这个信号。而对于SIGCHLD信号,程序选择忽略它,不进行任何处理。一些常见的信号概念实际执行信号的处理动作称为信号递达。
2025-03-17 08:00:00
548
原创 进程信号 信号概念 信号产生 信号处理
对于野指针的话 cpu中会由MMU硬件 和CR3 CR3会记录下条执行指令的地址 通过MMU去进行虚拟与物理地址的转换 但是如果执行的地址是一个野指针的话 通过MMU进入页表访问时就会产生错误 这是cpu中的MMU就会出错发生中断 之后系统接受到cpu的信号就会对应去处理对应的进程。发送信号的本质是写入信号,操作系统修改目标进程的进程控制块(PCB)中的信号位图,将对应的位从0改为1。硬件和操作系统可以并行执行。来发送一个中断信号(默认是SIGINT,信号编号2)给前台进 程,这通常会终止该进程。
2025-03-16 08:00:00
977
原创 system V 标准 共享内存 共享消息队列 共享消息量
shmat:该函数用于将一个共享内存段附加(attach)到进程的地址空间。它将共享内存段映射到调用进程的虚拟地址空间中,从而允许进程访问该内存段。shmdt:该函数用于将一个共享内存段从进程的地址空间中分离(detach)。分离后,进程将不再能访问该共享内存段。shmid:共享内存段的标识符,由shmget函数创建。shmaddr:指定共享内存段附加到进程地址空间的虚拟地址。如果为NULL,则由系统选择一个地址。shmflg:控制附加操作的标志,可以是读/写模式等。shmat 返回值。
2025-03-15 09:48:29
830
原创 管道 匿名管道 以及命名管道笔记
匿名管道的实现方式是系统在内存中创建一个pipe内存级文件 之后通过父进程的两个fd去链接这个管道 并作为读端和写端 之后 通过创建子进程 根据子进程会继承父进程的原理 我们的子进程会继承父进程的file_array表格 这样我们的父子进程就能同时看到这个管道 之后我们将父进程的写端关闭 子进程的读端关闭 或者是相反形成单向通信(特点) 这样就能够通信了。:操作系统通过对比进程的UID和GID与文件的UID和GID,以及检查文件的权限模式,来决定进程是否有权访问文件。
2025-03-12 10:37:10
644
原创 myset mymap
1. 在起点时哨兵位节点的情况时进行的特殊处理 在std库中 header的结点是红色的 所以如果一个节点时红色 且该节点的parent的parent 是他自己 那么这个节点就是header 我们直接让它指向它的右孩子 也就是最右节点 而在我们自己的rbtree中我们设置的end()返回的是空 所以如果一个节点指针是空的话 这里我们就返回这棵树的最右节点。
2024-10-25 23:14:43
590
原创 红黑树(创建 插入 测试验证)
情况三 如果判断叔叔节点存在且为黑色 这里的情况不是直接产生 这里是由于情况一产生并且维护后继续第二次维护cur节点的时候会发生的情况 这里也是分单旋转和双旋转 也是通过cur parent grandfather 三个节点时直线型 则为单旋转如果是折线型就是双选转 单旋转完成后将父节点变为黑色将爷爷节点变为红色 双旋转之后将cur节点变为黑色 将爷爷节点变为红色。cur节点时黑 是由情况一变过来导致变为红色的 ab是一个红色节点 新增节点在ab任意位置上。
2024-10-22 17:19:12
1016
原创 AVL树(创建 插入 遍历 测试是否平衡)
接下来处理subr的_parent pparent是parent的父节点 如果pparent等于nullptr 说明 此时subr就是根节点 同时要将subr的_parent等于nullptr 如果pparent不为空 则subr的_parent = pparent 如果parent是pparent的左节点 那么将subr放在pparent左边 否则 subr放在pparent右边。1.如果更新后 parent的平衡因子变为0 则说明之前是1/-1 插入节点在较低的一侧插入。
2024-10-21 11:37:49
776
原创 map和set(一)
insert的返回值是一个pair 这个pair的类型是<iterator,bool>如果为true插入成功 说明之前是没有这个值的 并且返回的迭代器是这个新插入位置 如果为false插入失败 说明之前已经有相同的值 返回迭代器是相同值位置的迭代器。这里的set库中erase使用的是第三种迭代器区间范围删除 lower_bound(x) 取的在set中最靠近 的大于等于 x位置的迭代器 而upper_bound(x)则是取最靠近的 大于x的值。
2024-10-14 13:24:51
941
1
原创 key形式和key/value形式二叉树
模拟一下key/value形式类 使用的结构是搜索二叉树 每一个节点中有左孩子和右孩子 还有一个key 和一个value 当我们找到可以key之后 也就找到了对应的value。模拟一下key/value形式类 使用的结构是搜索二叉树 每一个节点中有左孩子和右孩子 还有一个key 和一个value 当我们找到可以key之后 也就找到了对应的value。首先模拟一下key形式类 使用的结构是搜索二叉树 结点中有左孩子和右孩子 还有一个存储的值。主要功能有四个 删除 插入 遍历 查找。
2024-10-13 16:33:45
703
原创 二叉树进阶(一)
将没有孩子 和有一个孩子节点删除归为一种情况 首先判断留有的是左孩子还是有孩子 没有孩子自动归为没有左孩子一类 之后判断是否有父节点 如果没有父节点 删除的是跟节点 则直接让其孩子作为跟节点 如果有父节点 则判断当前节点时父节点的左孩子还是右孩子 如果左孩子 则让当前节点的孩子链接父节点的左边 如果是右孩子 则令当前节点的孩子链接父节点的右边 最后删除当前节点 返回true。而两个孩子的节点删除 就需要找一个节点进行替代 分别是左子树的最大节点 和右子树的最小节点。
2024-10-13 14:56:27
945
原创 多态(二)
多态是看指向的对象是谁 如果是b 那就会进入Base 中去通过虚表指针去找到Base类的虚表 在虚表中找到对应的函数去调用 而如果是d 虽然指针是Base类型 但是确实从Derive类中的Base部分虚表去找对应的函数调用 由于该函数发生重写 已经不再试Base:: 而是变成了Derive类域中的同名函数 所以在调用时也是调用的是子类中的同名函数 产生多态效果 (多态的原理)一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数 的地址要被放到虚函数表中,虚函数表也简称虚表。
2024-10-12 22:16:19
485
原创 继承(二)+多态
这是很多人都会去选择D 选项 但是D是错误 正确选项选择B 这是因为多态的调用原理时调用父类的虚函数声明 而是用的内容是来自子类的同名函数 这也就是为什么子类的同名函数即使不加virtual也依然构成函数重写。这里首先是通过继承关系子类调用父类的成员函数test() 之后test函数调用func 这是this->func()这里的this是A类型的指针 由于满足多态的两个条件 所以调用的是b类型中的func函数内容。组合的耦合度低,代码维护性好。类之间的关系可以用 继承,可以用组合,就用组合。
2024-10-12 13:30:27
870
原创 c++中的继承(一)
2.这更好的总结方式是:基类的其他 成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。1.派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。2.子类默认生成的拷贝构造 :对于父类的成员 调用父类的拷贝构造 对于子类的自定义成员 调用他的拷贝构造 对于内置类型成员 进行值拷贝。构造显示写是一定写在初始化列表的 因为初始化列表中是按照声明的顺序进行初始化的 而父类成员的说明一定是在前面的。
2024-10-11 19:33:51
795
原创 模版进阶 非类型模版参数
原因是原模版中const修饰的T类型的内容 也就是指针指向的内容 而将const放在data*前面 则会修饰到指针 并没有修饰到指针指向的内容 所以要将data*放在const之前 让const修饰到指针指向的内容。这里的第三个比较使用的是指针 那么日期类的指针比较的大小不在是日期的的大小比较 而是变成了比较指针地址的大小 这是我们不想要的结果 这时就需要用到函数模版特化去解决。这里不仅可以特化普通的类型还可以特化指针和引用 指针中的特化是一个大类 其中的二级指针三级指针都可以使用这个大的特化类。
2024-10-10 19:56:43
996
原创 stack和queue priority_queue(二)(模拟实现)
与list比较,空间利用率比 较高。之后最大子节点与父节点进行比较 如果子节点更大那么交换位置 更新父节点位置 并确定新的左子节点位置并且重新比较 如果父节点大于子节点(建立大堆) 那么就可以停止 或者走到叶子节点也可以停止了 注意这里向下调整法中使用的类型是无符号类型。比较父节点与子节点的值 如果子节点的值比较大(这里实现的是大堆)那么交换父节点和子节点 之后 之后从子节点更新到父节点的位置 再次计算新的父节点位置再次进行比较大小 如果父节点大于孩子 则结束或者一直调整到根节点。
2024-09-21 20:15:38
732
原创 stack和queue(一)
stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行 元素的插入与提取操作。队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端 提取元素。empty是stack的成员函数 用于检测当前stack是否为空 返回布尔值 若为空返回真 不为空返回假。检测队列是否为空,是返回true,否则返回false。接下来建立一个栈并且完成栈的遍历。将stack中尾部的元素弹出。返回stack中元素的个数。返回队列中有效元素的个数。
2024-09-21 10:47:00
280
原创 list(二) (list模拟实现)
这里创立prev节点 和cur节点 指针 prev指向cur指向节点的prev指向节点 cur指向pos位置的节点 同时有newnode作为新插入节点的指针 首先prev节点的next指向newnode newnode节点的prev指向prev节点 newnode节点的next指向cur的结点 cur节点的prev 指向newnode节点。一个const迭代器 和一个普通的迭代器 两者之间非常的冗余 而且有很大的相似程度 这里我们可以用一个类来同时实现两个迭代器的功能。
2024-09-20 21:42:39
1169
原创 list(一)
list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。list的begin()指向头结点的下一个结点 也就是第一个有效元素的结点 end()指向头节点 也就是最后有效元素的下一个结点 rbegin()指向头结点 rend()指向头节点的下一个结点。这里使用的是第一个版本 将lsit容器x的全部元素插入 到 mylist1的pos位置 且此时链表二中被转移的内容是不会在存在在链表二的 相当于是转移。
2024-09-20 09:42:48
1408
原创 vector(二)vector模拟实现
这里在测试时可能会出现随机值问题 这是因为出现的pos迭代器失效的情况 原理是pos迭代器指向原本的空间 但是如果发生扩容 就会深拷贝 导致pos迭代器还是指向已经消失的空间 没有指向对应的新空间的对应位置上 解决方法 就是使用len记录pos在空间上距离_start的距离 之后在扩容结束后 使用新的_start对pos迭代器进行更新 这样就能 保证迭代器在函数体内正常使用。vector成员变量是三个迭代器 vector的迭代器底层与string相同是使用 指针实现的 使用的是类模版T*指针。
2024-09-10 21:42:08
706
原创 vetor(一)
string和vector<char>的底层非常相似 但是接口不同 如append +=这样的接口vector是没有的。sort是存在algorithm库中的 它是一个函数模版 它的参数传的是函数的迭代器。string是专门针对字符串数组设计的 而vector是根据所有类型设计的 两者不相同。vector的begin是指向数组的第一个元素 而end是指向数组最后一个元素的下一个。而vector容器是通过迭代器确定范围 返回的也是对应位置的迭代器。这里数组使用指针确定范围 同时返回的是对应位置的指针。
2024-09-10 09:45:26
839
原创 string(三)
这里的iterator 利用的是char*指针 begin和end分别返回字符串数组首元素和有效元素最后一位的下一位 []的参数是下标 返回的值的对应数组下标位置中的内容 []不仅可以访问内容也可以进行修改。这里是string的构造 这里的初始化列表与代码块一起使用来进行初始化 初始化列表的初始化顺序是按照私有成员的创建顺序进行的 和这里的顺序无关。而插入位置是任意的 所以可能需要挪动字符 为插入的内容腾出空间 而挪动字符位置的方式有两种。
2024-09-09 23:08:13
485
原创 string笔记(二)
除了用三个参数来插入字符之外 还有一种版本 第一个参数放入的是要插入的位置 不过不是用下标而是使用迭代器中的begin()成员函数来代替下标表示位置 第二个参数则放入将要插入的字符内容。想要插入或者头插一个字符用上述的两个参数是行不通的 需要三个参数 第一个依旧是位置下标 第二个是要插入字符的数量 第三个是要插入的字符。replace有三个参数 第一个参数是提供下标位置 第二个参数是要从当前位置之后开始替换的长度 第三个是要替换的内容。而两个参数的版本不仅可以修改size还可以对内容进行统一的初始化。
2024-09-03 21:28:30
676
原创 string笔记(一)
C语言中的字符串 C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数, 但是这些库函数与字符串是分离开的,不太符合OOP(面向对象编程)的思想,而且底层空间需要用户自己管理,稍不留神可 能还会越界访问。那么为什么会有两个 相同功能的 这是string比stl先出 当时string用的是length 但后来stl出现后 又统一设立了size 所以size在stl中时通用的 而length则是string中独有的。
2024-09-02 23:07:20
684
原创 c++ new delete 模版
在空间上执行析构函数,完成对象中资源的清理工作。在申请空间失败时会抛异常, malloc会返回。在申请的空间上执行构造函数,完成对象的构造。解决add(a1,d1)中就有用到显式实例化。申请和 释放的是单个元素的空间,new[]类模板实例化与函数模板实例化不同,如果申请的是内置类型的空间,模版分为函数模版和类模版。申请的是连续空间,而且。在释放的对象空间上执行。,对于模板函数的使用,,对于字符类型也是如此。,注意:匹配起来使用。
2024-07-15 11:17:00
606
原创 类和对象+内存管理 4.18
(2).num1中有十个为int的空间 所以10*4 = 40 char2中除了abcd外还有斜杠0 所以有5个char大小的空间 所以是5*1=5 char2的长度是指abcd所以是4 pChar3是int指针 所以其sizeof大小是4 pChar3指向abcd 所以strlen的长度也是4 ptr1也是int指针 所以sizeof大小也是4()ptr1是局部 所以也处于栈中 而ptr1指正指向的空间是通过malloc出来的 malloc出来的空间是在堆中的 所以*ptr1在堆中。
2024-05-24 16:28:34
737
原创 新手c++之类和对象(下)4.16
内部类是一个独立的类,它不属于外 部类,更不能通过外部类的对象去访问内部类的成员。(两者是类似于平行的关系) 注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中 的所有成员。但是外部类不是内部类的友元。在这里的初始化列表本质就相当于每个对象中成员定义的地方 而我们的const修饰的常变量是不可改变的 而引用的变量是需要进行初始化的 且const变量只有一次初始化的机会 ,就是在定义的时候,所以const常变量和引用变量初始化都是必须通过初始化列表的。
2024-05-20 23:12:39
763
原创 新手c++之类和对象(中)2
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。总结一下:返回对象是一个局部对象或者临时对象,出了当前func函数作用域,就析构销毁了,那么不能用引用返回用引用返回是存在风险的,因为引用对象在func函数栈帧已经销毁了。且这时在随便调用一个函数后 ref的会发生修改 原因是引用返回时的内容已经被析构 这里接受func函数的ref相当于为空 当在出现新的函数调用会把ref进行覆盖。
2024-05-06 15:12:02
728
原创 新手c++之类与对象(中)
系统默认生成的无参的构造函数和无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。在这个myqueue中 s1 和s2是自定义类型 会去调用相对应自定义类型的构造和析构 而_size是内置类型 而且没有资源需要清理 所以myqueue类型中不需要去主动定义析构函数。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。在上图中如果没有写析构函数 系统自动生成的默认析构是不会去清理_array 的空间的 这时就会发生内存泄漏 这是非常可怕的 内存泄漏是不会报错的。
2024-05-05 03:18:37
579
2
原创 新手c++之类与对象笔记(上)
那是因为在类的实例化时 每个对象的成员变量都会开独自的空间 而成员函数是放在公共空间的 是不会在每个对象中都存放一个成员函数的(每个对象都放成员函数会造成浪费)这里的计算时的成员变量时所有的 不论是在公共的 还是私有的都会参与计算。而如果不对齐 可能会进行多次访问 在上图中右边的不对齐中 第一次读取4个字节 会读到_ch和_i的三个字节 之后还要在读取_i的剩下的一个字节空间和三个空白空间 这样就造成不必要的浪费 而且读取下来 还要进行裁剪和拼接才能读取到正确的内容。的操作,都是通过该指针去访问。
2024-04-25 22:55:54
717
1
原创 新手C++之函数重载 引用 内联函数
在上图编译中在.i .s .o 文件中都是没有函数定义的 只存在函数声明 原因是编译开始时 .h头文件和.cpp源文件是分开编译的 在没有链接之前 .cpp的源文件的机械码中只有只有声明 没有定义 这是是不会通过call和jump跳到 函数定义的 只有链接后 才会存在函数定义 若在链接后只有函数声明 而没有找到函数定义 这时产生无法解析的外部符号错误 这种错误是链接错误 (编译错误是指语法出现一些问题)这里是不会报错的 这不是权限的放大 是通过x的拷贝给p p的修改不会影响到x的。int &b= a;
2024-04-23 09:43:34
539
原创 新手c++入门之命名空间
那么我们在展开空间时 与外界的同名的变量 函数等可能会产生冲突吗 答案是不怕的 我们会按照默认的顺序去寻找 而且同名的变量在是局部域使用的会在使用其功能时也会智能使用局部域中的功能 使用命名空间域中的定义时也会智能的从命名空间域中去使用操作其功能。也就是说我们得到了张大爷的允许 我们可以进入张大爷的菜地中摘菜了 而全部展开就相当于我们可以摘张大爷家的所有种类的菜 而指定展开就相当于我们只能摘张大爷家的指定展开的菜 而菜地中的其他菜我们依旧是不能采摘的。答案是不会的 应该相同的命名空间会默认自动发生合并。
2024-04-15 13:10:57
784
1
原创 简易贪吃蛇代码
实现吃食物功能 需要通过头插法将食物结点插入蛇的链表中 然后将整个新的蛇身再次打印 这是创建一个cur结点 cur开始在蛇头结点位置通过while循环和setpos wprintf函数依次打印 之后删除free旧的食物结点 通过 createfood函数再次创建一个新的食物结点 之后 将食物的分数加入到所得的游戏总分上面。在snakeend函数中首先要根据蛇的结束状态通过Switch语句来选择不同的结束语 写出不同的结束游戏的原因 之后将创建的贪吃蛇的空间全部free掉 并置为空。
2024-02-26 23:01:15
1374
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人