- 博客(22)
- 收藏
- 关注
原创 ChatRoom测试报告
从功能性来看,它的主要功能包括登录、消息接收发送、搜索联系人、创建会话、以及是否能够正常显示消息的功能。此外对于安全性,在登录时测试了用户输入是否隐藏、SQL注入、多次失败锁定等,保障用户隐私。在测试过程中发现了6个Bug,其中有1个严重级别、3个一般级别、2个轻微级别。,并且根据测试用例中的安全测试也使用自动化的方式进行测试,根据设计的测试用例编写自动化脚本。(2)进行了基础的安全测试,SQL注入、隐藏密码等测试,发现1个Bug。(2)目前只能发送文本信息,可以添加发送文件,音乐,视频等文件的功能。
2025-04-10 18:05:15
499
原创 C++list常用接口和模拟实现
关于const的迭代器设计与之前的string和vector都有所不同,对于节点的指针进行了又一层的封装。list底层是不连续的存储空间,小的节点容易出现内存碎片的问题,空间利用率低。这里的Ref控制解引用的返回类型,Ptr控制箭头的返回类型;并且这样写还有一点好处是,对于普通的迭代器使用正常的模板参数即可,对于const迭代器使用const的模板参数即可。节点的结构就是双向链表的结构,这里也可以写成结构直接默认类成员公有的也可以。需要注意的是这里的迭代器在底层并不是原生指针,具体实现在后文给出。
2025-04-02 20:20:21
506
原创 C++vector常用接口和模拟实现
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问 题。C++中的vector是一个可变容量的数组容器,它可以像数组一样使用[]进行数据的访问,但是又不像C语言数组空间是静态的,它的空间是动态可变的。的问题,对于vector而言,它的迭代器底层就是原生指针。因此迭代器失效的原因就是指针所指向的空间被销毁了,指向了一个已经被释放的空间。例如上面这些例子,他们都引起了底层空间的改变,就会导致it失效,如果在后面的代码中使用失效的迭代器就会导致程序崩溃。
2025-03-26 20:03:48
339
原创 C++容器string类
(1)这里值得一提的是size()和length ()底层实现是一样的,但是实现size()出现的原因是为了和其他容器保持一致。一般而言使用size()。C++中对于字符串的处理进行了特殊的封装,使得这个容器既具有普通容器的性质,又能对于字符串进行处理。(2)clear只清楚内容,不会清楚底层空间。下面对一些常用的string接口进行说明。最后可以大致模拟实现一个string容器。首先来看string的构造函数。5.string类的非成员函数。3.string类对象的访问。4.string常用修改操作。
2025-03-24 20:07:24
308
原创 C++动态内存管理
这里给出malloc的函数声明,可以看到的是它返回的是空指针,那么意味着我们在使用的时候要进行强制类型转换。这里给出一个简单的示例。其中malloc、calloc,realloc是进行内存的开辟,free是进行内存的释放。这里的返回值与malloc代表的是一样的意义,形参列表中num代表的是开多少个空间,size代表的是所开空间的类型。这里的返回值也和malloc相同,ptr是指向一个已经开辟空间的指针,size是要扩容的空间大小。这里表示的就是申请10个int类型的连续的空间,用p指针指向这块空间。
2025-03-20 20:27:41
402
原创 C++类和对象——日期类(面向对象基本总结)
(5)构造函数是函数,那么它就支持函数重载,这就支持了拷贝构造的实现。静态成员也有一些特性:(1)静态成员不属于某个对象,是属于整个类的。(3)如果不写编译器会生成一个默认的赋值重载,也是浅拷贝。(2)拷贝函数的参数必须是引用传递,否则会引起拷贝的无限递归。析构函数与构造函数的功能相反,它是释放对象销毁后的资源的。这里需要考虑到闰年和平年的情况,由于一年中每个月的天数基本固定,可以直接存到静态区,通过访问静态数组返回天数。这两个只能定义再类的外,但是可以使用友元函数突破类的限制让其访问类中的元素。
2025-03-18 20:29:42
709
原创 C++面向对象类的总结
众所周知C++是在C语言的基础上发展而来的,而C语言是一个面向过程的语言,只关注过程,分析求解的步骤,调用函数解决问题。但是随着面向对象开发的发展,C语言渐渐的就不满足需求了,因此在C语言的基础上增加了类来满足面向对象的需求。这里先给出结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐 注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。类定义了一个新的作用域,类的所有成员都在类的作用域中。这就是一个简单类的定义,下面给出一个简单的日期类的定义。
2025-03-14 19:57:52
910
原创 C++常用基础语法
C++中使用inline修饰的就是内联函数,内联函数是在编译阶段,编译器使用函数体来替换函数调用,这是一种以空间换时间的方法。这就是一个简单的内联函数,需要注意的是内联函数的声明和定义最好不要分离,很可能会导致链接错误,因为inline展开之后找不到函数体的地址,无法完成替换就会报错。C++中允许函数名相同,在同一个作用域中,只要函数的形参列表(形参类型,个数,顺序)不同那么同名函数就可构成函数重载。函数重载是通过函数命名修饰规则来支持的,只要参数不同,修饰出的名称就不同,这样就构成了函数重载。
2025-03-13 20:23:58
593
原创 快速排序和归并排序的非递归C++实现
这里我们可以利用栈的特性实现这个效果,这里的思路就是我们可以在每次排序之前先把之前排好序的区间出栈,把下一次将排序的区间入栈,每次top取栈顶元素得到待排序的区间。只要栈不为空就重复上面的过程。最容易想到的就是我们也去模拟它的递归的过程,将每次排序单独写一个函数放在外面,每次控制好区间之后调用这个函数并且顺带返回它选取的基准值,这里的基准值还是使用三数取中的方式,这样就能达到模拟递归实现的效果。归并排序的基本思想是:将带排序的序列分为子序列,使得每一个子序列有序之后再合并这些子序列就能得到有序的序列。
2025-03-09 16:24:20
475
原创 C语言排序算法
首先从右侧开始找小于3的元素是2,然后右侧停下,从左侧开始找大于3的元素,但是不能发生交叉,那么就会在2处相遇这时候就代表着这一趟已经确定了左边小于3,右边大于3的元素位置,这时候交换3与2的位置,数组变为[2,1,3,5,4]。快速排序的思想是,选取一个待排序数组中的元素作为基准值,然后根据这个基准值将待排序数组分为两部分,左边是小于这个基准值的数组,右边是大于这个基准值的数组,然后左右数组重复这个过程,直到所有元素在对应的位置上。冒泡排序的思想是,遍历数组,只要后面的元素符合排序的大小关系就交换。
2025-03-02 17:02:35
492
原创 C语言堆以及堆排序
了解了思想之后我么来解决为什么排升序的时候建造大堆而不建造小堆,如果建小堆,每次只能拿到数组中的最小值,无法找到数组中的最大值也就意味着和最后一个元素交换后,无法的到升序的序列,而且还需要额外的空间来实现,效率低。堆的删除只有一点需要注意的是,我们如果直接删除堆顶元素的话,这会导致堆的结构被破坏,我们不希望只是删除一个元素就要去重建整个堆。需要注意的是,堆的物理上就是顺序表,删除堆顶的元素就是删除第一个元素,那么理所当然的需要移动剩下的数据,这里与顺序表也是一致的,那么顺序表如何删除效率高呢?
2025-03-02 11:37:18
739
原创 C语言二叉树
一棵树中有一个特殊的节点称为根节点,很容易想到的是,根是这棵树的起始,它没有前驱。这里使用递归实现是较为简单的实现方式,例如前序遍历,先遍历根节点的左子树直到左子树的孩子为空返回,然后遍历根节点最后遍历右节点。这里同样是分治的思想,将二叉树不断分为左右子树,计算左右子树较高的子树的高度再加1就是整个树的高度。在三种遍历结束之后,我们再实现一个求二叉树有多少个节点的功能,这里的思想与上面是一样的,都是递归地遍历整个树。完全二叉树通俗来讲就是对于k层的二叉树,它的k-1层是满的,第k层的节点是连续的。
2025-02-28 20:15:06
820
原创 C语言队列
因为这里使用的是链式结构,所以插入节点时需要申请一个空间,然后在头进行插入即可。需要注意的是,我们要设置指针之间的连接关系,如果队列为空,那么直接进行插入即可,如果不为空,则需要设置插入节点的指针连接关系,和尾指针的指向。由于栈只能在头删除,因此这里设置cur指针指向头,让cur指针向后移动,每移动一个free掉一个直到为NULL,此时在将head和tail后设为NULL,size重置为0即可。队列与栈类似,也是一种特殊的线性表,但是队列规定,只能在一段进行数据的插入操作,另一端进行数据的删除操作。
2025-02-24 20:51:05
517
原创 C语言栈实现
因为再物理结构上,栈就相当于是线性表,只不过我们规定了他的数据出入的位置而已,让它拥有了“先进后出”或者"后进先出"的特性,其本质还是一个顺序表。这里选择的是2倍扩容,扩容之后,由于这里设置的top是栈顶位置的下一个元素,所以直接在top位置赋值,然后再自增即可。栈首先是一个顺序表,它特殊的地方在于栈只能从一端进行数据的插入和删除,这一端称为栈顶,相应的另一端就称为栈底。这里的逻辑简单,对于栈中有多少个元素,直接返回top即可,如果设置的top是指向栈顶元素的,那么这里加1即可。这里先给出栈的各个接口。
2025-02-24 20:22:27
358
原创 C语言双向链表
尾删时只要找到尾巴地前一个节点,让这个节点的next指向头节点,头节点的prev指向这个节点,断开和尾巴的指针free掉即可。这里插入同样需要找到pos之前的节点,不过不需要遍历,pos的prex就指向了这个节点。删除某个位置上的节点,需要找到前一个和后一个节点,之后修改链接关系free即可。前一个节点的next指向后一个节点,后一个节点的prev指向前一个节点。头插时,需要插入到头节点的next。首先实现链表的初始化函数,对于链表的初始化需要申请节点,因此直接将申请节点这一功能封装成函数。
2025-02-16 15:09:26
321
原创 C语言单链表
单链表的尾插相对于头插而言较为复杂,因为需要找到链表的最后一个元素,那么就需要遍历这个链表找尾,然后让尾的next指向插入的节点。这里与8相同,需要找到pos的前面一个节点进行删除,让前驱节点的next指向pos节点的next之后再free掉pos位置的节点即可,同样如果pos是头节点位置,这里就相当于头删,可以复用前面的代码。单链表的头删也相对简单,但同样需要注意的是,我们不能直接释放掉头节点,直接释放头节点也会造成我们找不到这个链表从何开始的问题。链表分为很多种类,这里先实现最简单的一种链表,单链表。
2025-02-16 08:00:00
475
原创 C语言顺序表
接下来是对于动态顺序表而言,我们malloc了空间那么就需要释放,因此我们直接将释放空间的代码封装成一个函数,就是这里的SLDestory()函数。接下来是尾删这个功能,事实上对于顺序表而言,采用数组的方式进行存储,对于这种物理地址连续的顺序表那么它的删除就更为简单,我们直接对他的size--就达到了我们的目的。接下来实现插入的功能,对于有n个元素的顺序表,在第i个位置插入时,我们需要移动n-i个元素。下面是头插这个功能,对于顺序表的头插,需要注意的一点是,我们每插入一个数据都要移动当前顺序表的其他数据。
2025-02-15 21:21:55
359
原创 C语言通讯录
首先实现通讯录时,我们要知道,有姓名,电话,地址等变量需要存储。因此可以采用结构体来存储。并且这个通讯录应该有添加,删除,查找以及打印等功能。那么这个简单的通讯录结构就有了。可以看到的是,这里提供了三种方式。第一种静态数组的方式实现,将数组容量提前写定。第二种动态实现,使用realloc来申请空间。第三种采用文件操作,将内容存入文件中进行操作。在contact.h头文件中对这些函数进行声明,并且设置各类数组的容量。在text.c文件中我们调用这个功能。函数具体实现在contact.c文件中。
2025-01-19 11:31:37
261
原创 C语言字符串函数模拟与内存函数模拟实现
strcpy函数基本构成如上,传入要拷贝字符串的地址用source接收,以及传入要拷贝到那个字符串上去的地址用destination接受,返回一个char*类型的指针。strcmp()函数的作用是比较两个字符串,如果相通则返回0,如果str1大于str2,则返回一个大于0的数字,反之则返回一个小于0的数字。这里的想法是,如果要在dest的后面追加字符串,那么首先要找到dest这个字符串的末尾,从这个末尾开始追加src。这个函数的作用与strcpy的作用类似,但是这个函数可以限制拷贝的长度。
2025-01-19 10:56:44
451
原创 C语言三字棋
最后我们已经能够正常下棋,但是会发现无法判断输赢,因此我们还需要一个判断输赢的函数,对于井字棋而言,我们可以遍历每一行和每一列以及对角线是否有相同的元素,依次来判断输赢。PrintBoard函数的实现实际上也是遍历这个二维数组的过程,但是为了能够更好的区分,这里对棋盘做了分割,在打印列时,将“|”与数组元素看为一组打印,在一行数据打印完成后,再打印“_”进行分割。完成上述功能之后,我们实现Player函数,首先在下棋时需要先进性合法性判断,玩家输入的坐标不能超过数组的下标,否则会发生越界。
2025-01-08 22:00:53
406
原创 C语言,打印乘法表,判断素数或者判断闰年
素数的定义是如果一个数只能被1和它自身整除,那这个数就是素数。换言之也就是说,如果在区间(2,n)之间找不到一个数能被n+1整除,那么n+1就是素数。需要注意的是在内层循环结束后需要换行,事实上这也就是嵌套循环的巧妙之处。因此我们在判断数字i+1是否为素数时,只要看在区间(2,根号i)是否有数字能够被i+1整除就可以判断。首先在判断素数前,我们要知道,如果一个数c能够写成c=a*b的形式的话,那么a或者b总是小于等于根号下c的。其中1,2,4,8都是小于等于根号8的。1):能被4整除但是不能被100整除;
2025-01-04 22:16:02
448
原创 C语言计算n的阶乘以及阶乘求和
当了解了阶乘之后,自然而然的想到如何将阶乘相加呢?显而易见的是如果使用递归,其效率无疑是很低的。可以写成sum1=1!这段代码在功能上明显区分,便于修改。这事实上也是将功能模块化的好处之一。其运行结果与之前结果相同。当我们能够使用函数后,完全可以将这种计算通过函数实现。首先,本文不考虑递归的方式实现。尽管递归书写简单,但是对于新手而言并不很好理解。运行结果与上面也类似,但毫无疑问的是这使得功能更加清晰。
2025-01-03 22:10:24
230
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人