- 博客(24)
- 收藏
- 关注
原创 minidoc项目
minidocx 是一个跨平台且易于使用的 C++ 库,用于从零开始创建 Microsoft Word 文档。因为DOCX本质上是一个包含多个XML文件的ZIP包。可以使用特定的库和工具来完成这种转换,从而生成符合要求的docx文档。因此这个项目当中就是采用pugixml来进行XML的处理。
2024-07-18 13:49:54
417
原创 Office文档结构
docx使用OpenXML(OOXML)协议,它是微软在Office 2007中提出的一种新的文档格式,Office 2007及其以后的Word、Excel、PowerPoint默认均采用OpenXML格式。具体来说,它定义了包内各个文件的内容类型(MIME类型),使得应用程序能够正确识别和处理包内的不同文件。我们常用的Office Word格式分为doc和docx两种格式,doc是Word 97-2003版本使用的格式,Word2007及其之后的版本,默认格式是docx。定义文件扩展名的默认内容类型。
2024-07-18 13:47:13
846
原创 为什么在IO读写当中协程比线程的效率更高
web服务器在处理IO请求时,一般是将socket交给子线程来处理,然后每个子线程处理一个,但这个问题就是 当IO阻塞,线程就会阻塞,此时会发生线程切换,但当处理高并发的情况下发生线程频繁切换,这会导致很大的时间浪费。所以就给每个子线程多个协程,一个子线程处理多个,但每个协程各自处理一个,还是一个子线程处理一个,但在某个协程IO阻塞时,就可以切换到另一个协程,就避免了线程切换的耗时,使得支持的并发量上升了。将用户缓冲区和内核缓冲区进行了映射,这样减少了数据从用户缓冲区到内核缓冲区的一次拷贝。
2024-01-27 17:52:39
492
1
原创 从零开始构建torch环境
之后可以看到jupyter notebook中可以切换kernel,点击conda按钮可以看到所有的环境。完成之后再重新打开jupyter notebook,在项目中的Kernel就可以修改环境。得到对.jupyter文件的重写的效果。查询已有环境 查看是否创建虚拟环境成功。命令创建python环境。
2024-01-09 18:02:21
445
原创 同步与异步、阻塞与非阻塞、并发和并行
阻塞和非阻塞在于第一个过程,针对的是调用方,阻塞就是说发起IO请求之后调用方只能等着,在这个过程中不能做其他事情,就像阻塞的read读操作一样,而反之就是非阻塞。而同步和异步在于第二个过程,关键在于被调用方,如果操作系统帮你完成了读写操作再通知调用者,那就是异步,要调用者自己完成读写操作就是同步。一个IO的过程分为两个过程:发起IO请求和实际的IO读写操作。
2024-01-07 23:19:44
360
1
原创 C语言多个源代码文件的编译
在c和c++的linux系统编程项目中,项目中的文件经常被分为.h文件和.c文件,对于多个文件的编译我总是不太清楚,所以今天对linux系统中多个文件的编译进行一下总结,参考的课程是翁恺老师的c语言课程。头文件的作用就是把函数原型放到一个头文件 (以.h结尾) 中,在需要调用这个函数的源代码文件 (c文件) 中#include这个头文件,就能让编译器在编译的时候知道函数的原型。2、stdio.h里只有printf的原型,printf的代码在另外的地方,某个.lib(Windows)或.a(Unix)中。
2024-01-05 11:12:29
1892
原创 单例模式(懒汉模式与饿汉模式)
以两个线程为例,假设phread_1刚判断完 instance 为NULL 为真,准备创建实例的时候,切换到了thread_2, 此时thread_2也判断intance为NULL为真,创建了一个实例,再切回pthread_1的时候继续创建一个实例返回,此时就不是单例了,这是多线程访问出的安全问题,最直观和简单的方法就是加把锁,使得线程同步,因此引入了下面线程安全的懒汉模式。这两者的区别在于括号的存在与否。都会调用类的默认构造函数,但在这个特定的情境下,由于类的构造函数是无参数的,它们是等效的。
2024-01-04 16:13:51
784
1
原创 关于学习深拷贝和浅拷贝过程中的一些总结
首先涉及到深拷贝和浅拷贝问题的一个场景是:内部包括指针变量的对象的赋值,在下面的代码中,假如不重载赋值运算符 ,那么进行。最近在学习c++的基础知识,赋值运算符重载的这一章是以联系深拷贝和浅拷贝问题,作为知识的运用背景引入的。,但我的疑惑在于什么情况下会生成临时对象,什么情况下会直接进行赋值呢,在下面的这段代码中,好像体现的是当。的返回值是person(引用)的时候,就会直接赋值,而返回值是。这一操作时,就会进行浅拷贝,也就是其内部的指针进行的操作是。的结果会先创建一个临时对象,然后再将该临时对象赋值给。
2023-12-18 18:02:58
395
原创 背包问题理论基础(滚动数组)
如上面的j=3,i=0,第一个dp[3]表示若不放入物品0,装满容量为3的背包有几种方法,因为这是刚刚遍历到容量为3的背包,因此dp[3]此时是等于0的,而dp[3-1]表示若放入物品0,装满容量为3的背包有几种方法,实际上就是dp[3-1]=dp[2]时的情况集合加入元素0,dp[2]中的情况有两种[1,1,],[2],在这两种情况下再分别加入元素0,也就是[1,1,1]和[2,1]这两种情况。二维dp数组dp[i][j]表示从【0-i】中任取物品装在容量为j的背包,背包中的最大价值为dp[i][j]
2023-10-31 19:06:48
117
1
原创 代码随想录-二叉树章节技巧总结
2、搜索一条边的解法使用的是前序遍历,思想在于若当前结点不满足对称条件,就结束遍历,而搜索整棵树的解法是后续遍历,也可以说是回溯的思想,当某个结点不满足对称条件时,会将false传递到他的父结点,而父节点通过left或right变量进行承接。4、前序遍历包含遍历即处理的思想,且遍历完左节点回到中间结点时有一个回退的操作,而后序遍历则是先遍历左右结点,根据左右结点的结果得到中间结点的结果,因此要注意两种遍历方法的思想。的操作,最先处理的是根结点,最后被处理的是树最右端的结点。
2023-10-15 19:43:20
107
1
原创 c++的变量作用域
原始代码如下,当我希望根据当前所在结点左右子树情况的不同更新result时,我错误地在if语句的函数体内声明变量result,我原来以为这样不管函数进入哪一条if分支都会创建变量result,但实际上这样忽略了变量的作用域,也就是说分支内的变量result只在分支内有效,因此这样会导致错误。正确的方法是在合适的作用域内声明一次变量,然后在不同的分支内对它进行赋值,从而确保变量在整个函数内都是有效的。的变量,但它们的作用域是局部的,只在各自的分支内有效。这也是为什么在的原始代码中,多次声明了同名的。
2023-08-08 15:53:57
124
1
原创 代码随想录-设计链表
最后要记得cur指针后移两个结点,即。,但是仔细考虑就会发现当链表是空链表时这样是不行的,因为这种方法只有在链表不为空时适用,然后才可以通过这个方法找到链表的最后一个元素,但当链表是空链表时,cur指针就被初始化为空指针,而合理的方法是当链表为空时,cur应该指向头结点,这样才能进行插入操作,因此这里应该将cur初始化为指向头结点(_dummyHead),然后利用。(2)对于addAtTail函数,最开始,我是直接想参照get函数的方法,初始化cur指针指向第一个结点,然后利用上面的方法,即。
2023-07-04 15:36:01
87
原创 linux0.11中的sleep_on、wake_up函数与任务等待队列的调度
linux0.11进程睡眠sleep_on函数和唤醒wake_up函数分析。linux0.11进程调度(运行态\就绪态\睡眠态之间的转换)学习linux0.11-schedule函数。操作系统实验3:进程运行轨迹的跟踪与统计。[参考文档] linux内核完全注释。
2023-04-19 21:17:07
549
原创 全局描述表GDT、任务状态段TSS、局部描述表LDT之间的关系
在计算机从实模式(16位)转换到保护模式(32位)的过程中,段寄存器却一直是16位,只能访问64KB内存,但是保护模式下的内存范围是4GB,16位段寄存器就能够访问所有内存的秘诀就在于GDT这一结构,保护模式下段寄存器中保存的不再是段基址,而是是段选择子,通过段选择子在GDT表中索引段描述符,而段描述符当中存储着真正的段基址(32位),因此全局描述符表GDT就相当于内存段的身份证,记录着一个内存段的各种信息(前面说的段基址只是段描述符信息的一部分)。下面的图可以表示出三者之间的关系。
2023-04-12 21:18:51
598
原创 leetcode链表题报错 runtime error: member access within null pointer of type ‘ListNode‘
刚开始的代码是这样的,逻辑是先建立一个头结点放到链表头部,这样就可以统一链表结点删除的操作了,然后创建ListNode类型指针cur,初始化其指向头结点的下一个结点,利用while循环遍历链表,当cur指针指向Null时停止遍历。可以发现这个代码与我的代码不同有两点:第一是cur指针初始化时指向的是头结点,而我的代码cur指向是指向头结点的下一个结点,即原始链表的第一个结点,第二是while循环中的条件为。而且判断某结点的值时利用的是。,即当cur结点的下一个结点不为空时继续循环,而我的代码是。
2023-04-11 21:33:01
11123
3
原创 代码随想录-长度最小的子数组以及螺旋矩阵
上题的方法可以结合事例2的矩阵进行理解,第一圈第一条边,i不变,j的遍历范围是【0,2】,遍历第二条边时j不变,i的遍历范围是【0,1】,后面两条边类似,当进入第二次循环,即开始遍历更内一层,第一条边j的遍历范围是【1,1】,第二条边i的遍历范围是【1,1),因此没有可取的值,后面两条边同理,这里就可以看出规律,每进到更内一层,遍历边的起点+1,而终点-1。思路:这道题和上面的螺旋数组的区别是上面的数组一定为正方形,长和宽都为n,而本题长宽不一定一致,因此要先求出矩阵的长宽。
2023-04-10 19:54:33
225
3
原创 代码随想录-移除元素
这样我们就能确定了平方后最大值的位置, 所以用双指针指向数组的两端, 必定能找到平方后的最大值, 将其放到新数组末尾, 之后不断向中间移动, 通过比较两个指针平方后的大小, 就能不断地将当前的最大值放入数组的尾部, 直到两个指针相遇为止.“删除排序数组中的重复项”有异曲同工之妙,采用快慢指针,重构两个字符串,再比较重构后的两个字符串是否相等即可。,且快慢指针初始化时,快指针初始化为1,因为0号元素肯定没有重复出现,不用检验,而慢指针设置为0,存放着0号元素,当快指针找到下一个没有重复出现的元素时,
2023-04-03 11:03:12
50
原创 哈工大操作系统实验3-进程运行轨迹的跟踪与统计
wait是父进程调用的,表面上功能是使父进程阻塞自己,直到子讲程调用exit结束运行,然后获得子进程的返回值,本质上是内核在幕后将子进程的返回值传递给父进程并会唤醒父进程,然后将子进程的pcb 回收。只要调用了waiit系统调用,若没有子进程,wait会返回-1,若有子进程,该进程会被阻塞,当其某个子进程退出了,会将子进程退出的值返回给父进程,并将父进程唤醒。总结来说,使用了fork()函数,程序末尾出现wait()函数是为了防止僵尸进程的出现,进而防止僵尸进程过多导致进程加载失败。
2023-03-19 15:59:51
563
原创 TypeError: attrib() got an unexpected keyword argument ‘convert‘
TypeError: attrib() got an unexpected keyword argument ‘convert’调用OS库时出现了一个类似这样的错误,之后运行其他程序也总是会出现File “/usr/local/lib/python3.7/site-packages/_pytest/tmpdir.py”, line 35, in TempPathFactorylambda p: Path(os.path.abspath(six.text_type§))TypeError: attri
2020-08-06 14:26:17
775
原创 函数内部改变变量值时报错
函数内部引用并改变变量值报错:name ‘z’ is not defined在爬虫时遇到这样一个问题,改写成下面简单一点的代码,刚开始报错:local variable ‘a’ referenced before assignment ,在网上查了,解决方法是使用global关键字,就在Y()函数内加上global z,def X(): z=0 def Y(): global z z+=1 print(z) Y() X()
2020-05-19 07:04:46
230
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人