关于c++:CSCI-2132-Software-Development

Assignment 7CSCI 2132: Software DevelopmentDue April 8, 2019Assignments are due on the due date before 23:59. All assignments must be submitted electronically via the course SVNserver. Plagiarism in assignment answers will not be tolerated. By submitting your answers to this assignment, you declarethat your answers are your original work and that you did not use any sources for its preparation other than the class notes,the textbook, and ones explicitly acknowledged in your answers. Any suspected act of plagiarism will be reported to theFaculty’s Academic Integrity Officer and possibly to the Senate Discipline Committee. The penalty for academic dishonestymay range from failing the course to expulsion from the university, in accordance with Dalhousie University’s regulationsregarding academic integrity.General Instructions: How to Submit Your WorkYou must submit your assignment answers electronically: Change into your subversion directory on bluenose: cd ~/csci2132/svn/CSID . Create a directory a7 for the current assignment. Change into your assignment directory: cd a7 . Create files inside the a7 directory as instructed in the questions below and put them underSubversion control using svn add <filename> . Only add the files you are asked to add! Once you are done answering all questions in the assignment (or the ones that you are able toanswer—hopefully all), the contents of your a7 directory should look like this:a7permutations.clinked_list.clinked_list.hnode_pool.cnode_pool.hstringset.c(You will also have executable programs and potentially some data files in this directory, but youshould not add them to SVN.) Submit your work using svn commit -m"Submit Assignment 7" .1(Q1) RecursionConsider the sequence of the first n positive integers, ?1,2, . . . , n?. A permutation of this sequence isany sequence that contains each of the numbers 1, 2, . . . , n exactly once. So, ?3, 4, 2,is a permutation of 1, 2, 3, 4 but 1, 3, 2, 3 and 1, 5, 3, 2 are not.A permutation x1 is lexicographically less than another permutation y1 yn if andonly if there exists an index 1 ≤ k ≤ n such that xi = yifor all 1 ≤ i < k and xk < yk.So,2, 1, 3, 4 is lexicographically less than 2, 3, 1, 4 because x1 = y1 = 2 and x2 = 1 < y2 = 3. If theelements in the sequence were letters rather than integers, you could interpret the sequence of lettersas a word and the ordering defined here would simply be the one in which the words would occur in adictionary.Your task is to write a C program permutations that takes a command line argument n and outputsall permutations of the sequence ?1,2, . . . , n? in lexicographic order. The output should consist ofn! lines, each containing one permutation. The numbers in each permutation must be printed inorder, separated by exactly one space between each pair of consecutive numbers. Thus, when runningpermutations 3, you should see the following output on your screen:$ ./permutations 31 2 31 3 22 1 32 3 13 1 23 2 1permutations 4 should produce$ ./permutations 41 2 3 41 2 4 31 3 2 41 3 4 21 4 2 31 4 3 22 1 3 42 1 4 32 3 1 42 3 4 12 4 1 32 4 3 13 1 2 43 1 4 223 2 1 43 2 4 13 4 1 23 4 2 14 1 2 34 1 3 24 2 1 34 2 3 14 3 1 24 3 2 1As the title of the question suggests, recursion is a natural strategy to implement this program. Youshould not have to generate the permutations and then sort them. Your code should be able to generatethe permutations in the desired order.The basic strategy is fairly simple: Your top-level invocation of the function that generates the permutationshould iterate over all possible choices of the first element in the permutation, from smallestto largest. For each such choice, you make a recursive call that generates all permutations of theremaining n 1 elements. How do you do this? You iterate over all possible choices for the secondelement, from smallest to largest and, for each such choice, make a recursive call that generates allpermutations of the remaining n?2 elements, and so on. The deepest recursive call is asked to generatea permutation of 0 elements, that is, you have already chosen all n elements in the permutation. Thisis the point at which you print the current permutation.One issue you will have to deal with is how to keep track of the elements that can still be chosen asthe second, third, fourth, . . . element in the permutationu after choosing the first one, two, three, . . .elements in the permutation. One easy way to do this is to initialize an array of size n that containsall the numbers from 1 to n. Whenever you choose an element from this array, you set its entry to 0and, in subsequent recursive calls, you skip elements that are 0 because they were already chosen.Don’t forget to restore each number x in this array of candidates when it is no longer part of the set ofelements currently chosen as part of the permutation. This is not the most efficient way to do this, butefficiency is not your main concern in this question.Implement your program in a single source file permutations.c. Do not submit the executable fileobtained by compiling it. However, you should obviously compile and test your code.3(Q2) Structs, unions, and dynamic memory managementThe ability to allocate and deallocate memory on the heap at arbitrary times is key to writing flexibleprograms, but every allocation or deallocation has an associated cost because the runtime system oroperating system needs to perform a certain amount of bookkeeping to keep track of which memorylocations on the heap are currently occupied and which ones are available for future allocation requests.As a result, in programs that create and destroy many small objects on the heap, the cost of heapmanagement may become the main performance bottleneck. This is the case in object-oriented programsthat manipulate complex collections of small objects and in the implementation of pointer-based datastructures such as linked lists and binary search trees, where a na?ve implementation represents eachlist or tree node as a separately allocated block on the heap.A common technique to improve the performance of such programs substantially is to allocate largerchunks of memory at a time, large enough to hold hundreds or thousands of the manipulated objects(e.g., a chunk that is big enough to hold 1000 list nodes in a linked list implementation). Your codethen has to manually track which of the slots in this large memory chunk are occupied or not, but thisis a much simpler problem that can be solved much more efficiently than general heap management.The data structure that manages the allocation of individual list nodes from this array of list nodes isoften referred to as a “node pool”.Here, your task is to implement a linked list that uses a node pool to efficiently manage the memoryoccupied by its nodes. As an application, you will use the same test program as in Lab 8, which needsa data structure to store a collection of strings. In Lab 8, you implement this collection as a splay treein order to guarantee fast searches. Here, you do not worry about the speed of searching the datastructure, only about the cost of heap management, so a linked list suffices as the data structure tostore the collection of strings.1Develop your code for this question in four steps: ...

June 28, 2021 · 16 min · jiezi

关于c++:C内存管理18补充

谈谈 const当成员函数的 const 和 no-const 版本同时存在, const object 只会(只能)调用 const 版本, non-const object 只会(只能)调用 non-const 版本是否可被调用const object(data members 不得变动)non-const object(data members 可变动)const member functions(保障不更改data members)√√non-const member functions(不保障 data members 不变)×√const String str("hello word");str.printf();如果当初设计 String::printf() 时未指明 const, 那么以上代码将是经由 const object 调用 non-const member function, 编译时会报错(并非咱们所愿)class template std::basic_string<...> 有如下两个 member funcionscharT operator[](size_type pos) const{ ... /* 不用思考 COW */ }reference operation[](size_type pos){ ... /* 必须思考 COW */ }COW: Copy On Write (援用技术数据共享机制) ...

June 27, 2021 · 1 min · jiezi

关于c++:C内存管理17G49-的七个分配器

规范库规定,分配器最顶层在 《...\memory》 头文件下new_allocatornew_allocator 的 allocate 间接调用的 ::operator new ,deallocate 间接调用 ::operator delete malloc_allocatormalloc_allocator 的 allocate 间接调用的 malloc,deallocate 间接调用 free。 array_allocatortr1 (Technical Report 1) 不是正式的库只是一个草案,作为C++ 2003规范的附加库被大多数编译器厂商所反对,它是个过渡性质的库,其实现将会作为C++11规范的一部分。到 C++2011 时,其局部内容被正式蕴含到规范库,在应用形式上依然保留 std::tr1,例如 std::tr1::array 可用 std::array 代替。 在构造函数中须要传入一个指针,这个指针能够指向动态调配的数组,也能够指向动态分配的数组,所以说内存调配不是在array_allocator中进行的,array_allocator 只是对调配好的内存进行治理(因而 deallocate 什么都没做)。 array_allocator 并不会"回收"(指从新被array_allocator治理)已给出的内存空间,因而很少被应用 动态内存调配的形式应用 动态内存调配的形式应用 debug_allocator 包裹另一个分配器,应用至多一个元素大小的空间,用于记录整个区块大小(子元素数量)(是不是相等于另一种 cookie? 但 allocator 的主要用途是缩小 cookie,因而很少被应用)pool_allocatorG2.9 容器应用的分配器不是 std::allocator 而是 std::alloc (毛病,只申请不偿还) G4.9 中的进化G4.9 规范库中有许多 extented allocators, 其中 __pool_alloc 就是 G2.9 的化身 #include <iostream>#include <cstddef>#include <memory> //內含 std::allocator#include <ext\pool_allocator.h> //欲应用 std::allocator 以外的 allocator, 就得自行 #include <ext/...>#include <ext\array_allocator.h>#include <ext\mt_allocator.h>#include <ext\debug_allocator.h>#include <ext\bitmap_allocator.h>#include <ext\malloc_allocator.h>#include <ext\throw_allocator.h>#include <ext\new_allocator.h> //這其實已被 <memory> included, 它就是 std:allocator 的 base class#include <iostream>#include <list>#include <deque>#include <vector>using namespace std;template<typename Alloc>void cookie_test(Alloc alloc, size_t n){ typename Alloc::value_type *p1, *p2, *p3; //需有 typename p1 = alloc.allocate(n); //allocate() and deallocate() 是 non-static, 需以 object 呼叫之. p2 = alloc.allocate(n); p3 = alloc.allocate(n); cout << "p1= " << p1 << '\t' << "p2= " << p2 << '\t' << "p3= " << p3 << '\n'; alloc.deallocate(p1,sizeof(typename Alloc::value_type)); //需有 typename alloc.deallocate(p2,sizeof(typename Alloc::value_type)); //有些 allocator 對於 2nd argument 的值無所謂 alloc.deallocate(p3,sizeof(typename Alloc::value_type));}int main(){ //從語法上試用各式各樣的 allocators cout << sizeof(std::allocator<int>) << endl; //1 cout << sizeof(__gnu_cxx::new_allocator<int>) << endl; //1. //觀察 STL source 可知: new_allocator 是 std::allocator 的 base //我們無法改變 std::allocator 的 base class, 那該如何应用其余的 GNU allocators ? //是否要寫個 custom_allocator (像下面) 並為它加上我想要的 base (例如 __pool_alloc) ? //不,不用,就间接应用, 但需自行 #include <ext/...> cout << sizeof(__gnu_cxx::malloc_allocator<int>) << endl; //1. 大小 1者其實為 0, fields 都是 static. cout << sizeof(__gnu_cxx::__pool_alloc<int>) << endl; //1 cout << sizeof(__gnu_cxx::__mt_alloc<int>) << endl; //1 cout << sizeof(__gnu_cxx::bitmap_allocator<int>) << endl; //1 cout << sizeof(__gnu_cxx::array_allocator<int>) << endl; //8 ==> 因為它有一個 ptr 指向 array 和一個 size_t 示意耗费到 array 哪兒 cout << sizeof(__gnu_cxx::debug_allocator<std::allocator<double>>) << endl; //8 //! cout << sizeof(__gnu_cxx::throw_allocator<int>) << endl; //只有 throw_allocator_base, throw_allocator_random, throw_allocator_limit, 沒有 throw_allocator !! cout << endl; //搭配容器 list <int, __gnu_cxx::malloc_allocator<int>> list_malloc; deque <int, __gnu_cxx::debug_allocator<std::allocator<int>>> deque_debug; vector<int, __gnu_cxx::__pool_alloc<int>> vector_pool; //! vector<int, __pool_alloc<int>> vector_pool; //如果沒加上 namespace : [Error] '__pool_alloc' was not declared in this scope cookie_test(std::allocator<int>(), 1); //相距 10h (示意帶 cookie) cookie_test(__gnu_cxx::malloc_allocator<int>(), 1); //相距 10h (示意帶 cookie) cookie_test(__gnu_cxx::__pool_alloc<int>(), 1); //相距 08h (示意不帶 cookie) //以下將 int 改為 double 結果不變,象征上述 ints 間隔 8 (而非 4) 乃是因為 alignment. cookie_test(std::allocator<double>(), 1); //相距 10h (示意帶 cookie) cookie_test(__gnu_cxx::malloc_allocator<double>(), 1); //相距 10h (示意帶 cookie) cookie_test(__gnu_cxx::__pool_alloc<double>(), 1); //相距 08h (示意不帶 cookie) cout << endl; try { //示範应用 array_allocator: 須先 new an array, 將其 ptr 設給 array_allocator, 最後還要 delete array std::tr1::array<double,100>* arrayTR1 = new std::tr1::array<double,100>; //应用 tr1::array cookie_test(__gnu_cxx::array_allocator<double, std::tr1::array<double,100>>(arrayTR1), 1); //相距 08h (示意不帶 cookie) delete arrayTR1; array<double,100>* arraySTD = new array<double,100>; //应用 std::array cookie_test(__gnu_cxx::array_allocator<double, array<double,100>>(arraySTD), 1); //相距 08h (示意不帶 cookie) delete arraySTD; std::tr1::array<double,1>* p = new std::tr1::array<double,1>; //為搭配下一行 "default 2nd argument 是 std::tr1::array<T,1>" (見 source), 我們须要做一個來. cookie_test(__gnu_cxx::array_allocator<double>(p), 1); //未指明 2nd argument, 所以应用 default, 即 std::tr1::array<T,1> //bad allocation! 因為 cookie_test() 需 3 doubles 而 // 本處所用之 array_allocator 卻只能提供 1 double。 delete p; } catch(...) { cout << "bad allocation! \n"; } return 0;}输入: ...

June 27, 2021 · 6 min · jiezi

关于c++:熬夜整理近百份大厂面经2022校招提前批面经总结分享腾讯字节阿里百度京东等招聘信息必考点简历书写

整顿面经镇楼,随着高考的完结,2022的校招提前批曾经轻轻开始了,不论你是大四还是研三,应聘将会成为大家接下来半年乃至一年的重要工作! 接下来就联合我本身的教训以及我翻阅几百份最新面经后的一点点总结经验,心愿对同学们的上岸之路有所帮忙! 1.招聘信息的获取路径2.大厂面试必考点(人俗称:八股文)3.学习打算4.简历书写5.面试技巧与经验之谈 1.招聘信息的获取路径不少的同学在校招的时候,并不是没有那个实力进更好的企业,只是遗记了招聘投递工夫,毕竟在没有孤注一掷的状况下,比拟好的公司的招聘音讯都是须要留神的,那不免就会呈现脱漏与遗记。所以,第一点就是要做好招聘信息获取的渠道起源: ①各大公司官方网站与公众号②牛客网③实习僧④业余的技术QQ微信群⑤有更好的能够留言评论分享一下 2.大厂面试必考点(俗称:八股文)面试屡次的同学就会晓得,有些技术问题往往都是面试官绕不开,而你躲不掉的。而在我整顿的187份大厂面经中,面试官问到频率最高的技术点及畛域就是上面这些,这个肯定要划重点!! 技术点: 1.红黑树2.零拷贝3.过程线程4.TCP、UDP5.epoll、poll、select6.排序7.哈希8.拥塞管制9.B树和B+树10.虚拟内存11.http协定12.malloc和new的区别 就这12个问题不是全副百分之一百会全副呈现,至多搞定它们会成为你的面试加分点,毕竟作为一个应届生而言,能考的点也就那么多了。至于问的范畴泛不泛,这个就要看你的简历是如何写的了,这个文章前面也会说到。 技术畛域: 1.c++根底2.计算机网络3.操作系统4.网络编程5.数据结构与算法6.数据库7.我的项目 作为一名应届生来说,我的项目教训的有余是一种常态,所以校招时尽管也会问到相干的我的项目技术内容,然而外围点还是看你对技术自身的钻研与了解。 3.学习打算尽管总结了很多经典的面试题,然而也架不住咱面试的公司多。所以,实打实的夯实好本人的技术能力才是要害,而面试官也能够通过对你学习技术的布局与速度,来判断你的学习能力,这一点对于程序员来说也是尤为重要的。 学习打算如何制订,这里也参考了网上大多优良的同学总结进去的打算进行汇总,供有须要的同学参考。依据常考的技术畛域,咱们也将学习打算做区块的划分: c++根底1、面向对象的三大个性:封装、继承、多态 2、类的拜访权限:private、protected、public 3、类的构造函数、析构函数、赋值函数、拷贝函数 4、挪动构造函数与拷贝构造函数比照 5、深拷贝与浅拷贝的区别 6、空类有哪些函数?空类的大小? 7、内存分区:全局区、堆区、栈区、常量区、代码区 8、C++与C的区别 9、struct与class的区别 10、struct内存对齐 11、new/delete与malloc/free的区别 12、内存泄露的状况 13、sizeof与strlen比照 14、指针与援用的区别 15、野指针产生与防止 16、多态:动静多态、动态多态 17、虚函数实现动静多态的原理、虚函数与纯虚函数的区别 18、继承时,父类的析构函数是否为虚函数?构造函数能不能为虚函数?为什么? 19、动态多态:重写、重载、模板 20、static关键字:润饰局部变量、全局变量、类中成员变量、类中成员函数 21、const关键字:润饰变量、指针、类对象、类中成员函数 22、extern关键字:润饰全局变量 23、volatile关键字:防止编译器指令优化 24、四种类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast 25、右值援用 26、std::move函数 27、四种智能指针及底层实现:auto_ptr、unique_ptr、shared_ptr、weak_ptr 28、shared_ptr中的循环援用怎么解决?(weak_ptr) 29、vector与list比拟 30、vector迭代器生效的状况 31、map与unordered_map比照 32、set与unordered_set比照 33、STL容器空间配置器 举荐书籍:《C++ Primer》(第5版)、《STL源码分析》、《深度摸索C++对象模型》,面试考点根本几种在虚函数、虚继承、vector等容器的底层实现以及c++新个性上,所以应答面试这三本就够了。 计算机网络1、OSI7层网络模型:应用层、表示层、会话层、运输层、网络层、链路层、物理层 2、TCP/IP四层网络模型:应用层、运输层、网际层、接口层 综合OSI与TCP/IP模型,学习五层网络模型: 从上向下架构:应用层、运输层、网络层、链路层、物理层 链路层: 3、MTU 4、MAC地址 网络层: 5、地址解析协定 6、为啥有IP地址还须要MAC地址?同理,为啥有了MAC地址还须要IP地址? 7、网络层转发数据报的流程 8、子网划分、子网掩码 9、网络管制报文协定ICMP 10、ICMP利用举例:PING、traceroute 运输层: 11、TCP与UDP的区别及利用场景 12、TCP首部报文格式(SYN、ACK、FIN、RST必须晓得) 13、TCP滑动窗口原理 14、TCP超时重传工夫抉择 15、TCP流程管制 16、TCP拥塞管制(肯定要弄清楚与流量管制的区别) 17、TCP三次握手及状态变动。为啥不是两次握手? 18、TCP四次挥手及状态变动。为啥不是三次挥手? 19、TCP连贯开释中TIME_WAIT状态的作用 20、SYN泛洪攻打。如何解决? 21、TCP粘包 22、TCP心跳包 23、路由器与交换机的区别 24、UDP如何实现牢靠传输 应用层: 25、DNS域名零碎。采纳TCP还是UDP协定?为什么? 26、FTP协定(理解) 27、HTTP申请报文与响应报文首部构造 28、HTTP1.0、HTTP1.1、HTTP2.0比照 29、HTTP与HTTPS比照 30、HTTPS加密流程 31、办法:GET、HEAD、POST、PUT、DELETE 32、状态码:1、2、3、4、5** 33、cookie与session区别 34、输出一个URL到显示页面的流程(越具体越好,搞明确这个,网络这块就差不多了) ...

June 24, 2021 · 1 min · jiezi

关于c++:TcaplusDB知识库软件和硬件环境建议配置

TcaplusDB是专为游戏进行额定优化设计的分布式 NoSQL 数据库,作为腾讯云的数据库服务的一部分为广大客户提供极致的游戏数据体验。目前已为多个千万级 DAU 大作提供了稳固的数据存储服务,依靠腾讯云遍布寰球五大洲(亚洲、欧洲、北美洲、南美洲、大洋洲)的根底设施服务节点,游戏开发商只需接入一次,便可不便寰球游戏用户体验。 TcaplusDB 作为一款高性能分布式 NOSQL 数据库,能够很好的部署和运行在 Intel x86-64 架构服务器环境(ARM 架构的服务器环境)及支流虚拟化环境,并反对绝大多数的支流硬件网络。作为一款高性能数据库系统,TcaplusDB 反对支流的 Linux 操作系统环境。 1. Linux 操作系统版本要求Linux 操作系统平台版本Red Hat Enterprise Linux6.x - 7.xCentOS6.x - 7.xTlinux1.2 / 2.2留神: TcaplusDB 在 CentOS 6.x 、CentOS 7.x 的环境下进行过大量的测试,同时机会经营案例也有很多该操作系统部署的最佳实际,因而,倡议应用 CentOS 7.3 以上的 Linux 操作系统来部署。以上 Linux 操作系统可运行在物理服务器以及 VMware、KVM、XEN、Docker 支流虚拟化环境上2. 服务器倡议配置TcaplusDB 反对部署和运行在 Intel x86-64 架构的 64 位通用硬件服务器平台(或者 ARM 架构的硬件服务器平台)。对于开发,测试,及生产环境的服务器硬件配置(不蕴含操作系统 OS 自身的占用)有以下要求和倡议: 2.1. 开发及测试环境CPU内存本地存储网络实例数量(最低要求)8 核+16 GB+SAS, 200 GB+千兆网卡1所有组件在同一台机器部署,包含TcapOMS、Mysql、Tcapdb、Tcapcenter、Tcapdir、Tcapsvr、Tcaproxy、TcapRestProxy 留神: 如进行性能相干的测试,防止采纳低性能存储和网络硬件配置,避免对测试后果的正确性产生烦扰。2.2. 生产环境2.2.1. 最小配置模块组件CPU内存本地存储网络实例数量(最低要求)组件形容管控TcapOMS4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)Tcaplus存储网页治理端管控Tcapdb4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)提供数据缓写性能,可同步流式数据到MySQL、ES管控Tcapcenter4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)Tcaplus核心治理节点管控Tcapdir4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)Tcaplus目录服务器,提供鉴权、接入节点更新告诉性能管控Mysql4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)数据库,保留Tcaplus外围配置、监控上报数据管控Tmonitor4 核+16 GB+SAS, 100 GB+千兆网卡2(跨机房、机架部署)Tcaplus 过程监控服务存储Tcapsvr8 核+32 GB+备份、Binlog盘:SAS/SSD/NVME 1 TBdata盘:SSD/NVME 500GB万兆网卡2 (跨机房、机架部署)Tcaplus存储节点接入Tcaproxy8 核+32 GB+备份、Binlog盘:SAS/SSD/NVME 1 TBdata盘:SSD/NVME 500GB万兆网卡2 (跨机房、机架部署)Tcaplus接入节点接入TcapRestProxy8 核+32 GB+备份、Binlog盘:SAS/SSD/NVME 1 TBdata盘:SSD/NVME 500GB万兆网卡2 (跨机房、机架部署)Tcaplus Rest接入节点全局索引TcapIndex Tcaplus全局索引节点冷备Gluster4 核+8 GB+SAS,举荐5T, 存储容量跟冷备天数和binlog寄存天数相干,可按需调整万兆网卡2或2的倍数Tcaplus 冷备存储节点, Gluster内做Raid1,所以理论使用率是50%,举荐按15天冷备+25天binlog寄存2.2.2. 高性能配置模块组件CPU内存本地存储网络实例数量(最低要求)组件形容管控TcapOMS4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)Tcaplus存储网页治理端管控Tcapdb4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)提供数据缓写性能,可同步流式数据到MySQL、ES管控Tcapcenter4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)Tcaplus核心治理节点管控Tcapdir4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)Tcaplus目录服务器,提供鉴权、接入节点更新告诉性能管控Mysql4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)数据库,保留Tcaplus外围配置、监控上报数据管控Tmonitor4 核+16 GB+SAS, 200 GB+千兆网卡2(跨机房、机架部署)Tcaplus 过程监控服务存储Tcapsvr24 核+64 GB+备份、Binlog盘:SAS/SSD/NVME 2 TBdata盘:SSD/NVME 1 TB万兆网卡2 (跨机房、机架部署)Tcaplus存储节点接入Tcaproxy8 核+16 GB+SAS, 100 GB+万兆网卡2(跨机房、机架部署)Tcaplus接入节点接入TcapRestProxy8 核+16 GB+SAS, 100 GB+万兆网卡2(跨机房、机架部署)Tcaplus Rest接入节点全局索引TcapIndex Tcaplus全局索引节点冷备Gluster4 核+8 GB+SAS,举荐10T, 存储容量跟冷备天数和binlog寄存天数相干,可按需调整万兆网卡2或2的倍数Tcaplus 冷备存储节点, Gluster内做Raid1,所以理论使用率是50%,举荐按15天冷备+25天binlog寄存留神: ...

June 22, 2021 · 1 min · jiezi

关于c++:DPST1092-21T2

DPST1092 21T2 — Assignment 1: cellular, 1D Cellular Automaton in MIPSAssignment 1: cellular, 1D Cellular Automaton inMIPSversion: 1.0 last updated: 2021-06-3 20:00:00Aimsto give you experience writing MIPS assembly codeto give you experience with data and control structures in MIPSGetting StartedCreate a new directory for this assignment called cellular, change to this directory, and fetch the provided code by running thesecommands:$ mkdir cellular$ cd cellular$ 1092 fetch cellularThis will add the following files into the directory:cellular.c: a cellular automaton renderercellular.s: a stub assembly file to completecellular.c: A Cellular Automaton Renderercellular.c is an implementation of a one-dimensional, three-neighbour cellular automaton. It examines its neighbours and its value inthe previous generation to derive the value for the next generation.Here, we using '#' to indicate a cell that's alive; and '.' to indicate a cell that is not.Given we examine three neighbours, there are eight states that the prior cells could be in. They are:For each one, we decide what action to take. For example, we might choose to have the following 'rule':We apply this rule to every cell, to determine whether the next state is alive or dead; and this forms the next generation. If we print thesegenerations, one after the other, we can get some interesting patterns.The description of the rule above — by example, showing each case and how it should be handled — is inefficient. We can abbreviatethis rule by reading it in binary, considering live cells as 1's and dead cells as 0s; and if we consider the prior states to be a binary valuetoo — the above rule could be 0b00011110, or 30.To use that rule, we would mix together the previous states we're interested in — left, middle, and right — which tells us which bit of therule value gives our next state.The size of a generation, the rule number, and the number of generations are supplied on standard input. For example:Files c.out and mips.out are identicalTry this for different values of the parameters.Assumptions and ClarificationsLike all good programmers, you should make as few assumptions as possible.Your submitted code must be hand-written MIPS assembly, which you yourself have written. You may not submit code in otherlanguages. You may not submit compiled output.You may not copy a solution from an online source (e.g., Github).There will be a style penalty for assignments that do not use the stack to save and restore $ra (in main)There will be a style penalty for assignments that do not follow these important MIPS calling conventions:function arguments should be passed in $a0 through $a3$s0..$s9 should be preserved across function calls: if a function changes these registers, it must restore the original value beforereturningThe above two style penalties apply only to assignments which score above CR (65+) on performance testing.If you need clarification on what you can and cannot use or do for this assignment, ask in the class forum.You are required to submit intermediate versions of your assignment. See below for details.AssessmentWhen you think your program is working, you can use autotest to run some simple automated tests:$ 1092 autotest cellular cellular.sSubmissionWhen you are finished working on the assignment, you must submit your work by running give:$ give dp1092 ass1_cellular cellular.sYou must run give before June 28 23:59:59 to obtain the marks for this assignment. Note that this is an individual exercise, the workyou submit with give must be entirely your own.You can run give multiple times.Only your last submission will be marked.You cannot obtain marks by e-mailing your code to tutors or lecturers.You can check your latest submission on CSE servers with:$ 1092 classrun -check ass1_cellularManual marking will be done by your tutor, who will mark for style and readability, as described in the Assessment section below. Afteryour tutor has assessed your work, you can collect your assignment by typing on the command line:$ 1092 classrun -collect ass1_cellularThe resulting mark will also be available by typing:$ 1092 classrun -sturecDue Date2021/6/18 DPST1092 21T2 — Assignment 1: cellular, 1D Cellular Automaton in MIPSDue DateThis assignment is tentatively due June 28 23:59:59.If your assignment is submitted after this date, each hour it is late reduces the maximum mark it can achieve by 2%. For example, if anassignment worth 74% was submitted 10 hours late, the late submission would have no effect. If the same assignment was submitted 15hours late, it would be awarded 70%, the maximum mark it can achieve at that time.Assessment SchemeThis assignment will contribute 9 marks to your final DPST1092 mark.80% of the marks for assignment 1 will come from the performance of your code on a large series of tests.20% of the marks for assignment 1 will come from hand marking. These marks will be awarded on the basis of clarity, commenting,elegance and style. In other words, you will be assessed on how easy it is for a human to read and understand your program.An indicative assessment scheme follows. The lecturer may vary the assessment scheme after inspecting the assignment submissions,but it is likely to be broadly similar to the following:HD (85+) beautiful documented code, which uses the stack with MIPS calling conventions, andimplements spec perfectlyDN (75+) very readable code, prints cells correctly if n_generations positive or negative, all rulescorrectly handledCR (65+) readable code, prints cells correctly if n_generations positive, rules mostly workingPS (55+) prints initial world (first line) correctly and sometimes more correct linesPS (50+) good progress on assignment but not passing autotests0% knowingly providing your work to anyoneand it is subsequently submitted (by anyone).0 FL forDPST1092submitting any other person's work; this includes joint work.academicmisconductsubmitting another person's work without their consent;paying another person to do work for you.Intermediate Versions of WorkYou are required to submit intermediate versions of your assignment.Every time you work on the assignment and make some progress you should copy your work to your CSE account and submit it usingthe give command below. It is fine if intermediate versions do not compile or otherwise fail submission tests. Only the final submittedversion of your assignment will be marked.Attribution of WorkThis is an individual assignment.The work you submit must be entirely your own work, apart from any exceptions explicitly included in the assignment specificationabove. Submission of work partially or completely derived from any other person or jointly written with any other person is notpermitted.You are only permitted to request help with the assignment in the course forum, help sessions, or from the teaching staff (the lecturer(s)and tutors) of DPST1092.Do not provide or show your assignment work to any other person (including by posting it on the forum), apart from the teaching staffof DPST1092. If you knowingly provide or show your assignment work to another person for any reason, and work derived from it issubmitted, you may be penalized, even if that work was submitted without your knowledge or consent; this may apply even if your workis submitted by a third party unknown to you. You will not be penalized if your work is taken without your consent or knowledge.Do not place your assignment work in online repositories such as github or any where else that is publically accessible. You may use aprivate repository.Submissions that violate these conditions will be penalised. Penalties may include negative marks, automatic failure of the course, andpossibly other academic discipline. We are also required to report acts of plagiarism or other student misconduct: if students involvedhold scholarships, this may result in a loss of the scholarship. This may also result in the loss of a student visa.Assignment submissions will be examined, both automatically and manually, for such submissions.Change LogVersion 1.0 Initial release. ...

June 21, 2021 · 6 min · jiezi

关于c++:C到C

1. 新类型 布尔 援用整型 int long浮点型 float double字符类型 char 布尔 boolbool 寄存真(1)和假(0)的类型 大小1个字节 能够寄存true false指针 寄存地址的变量 能够间接批改变量的值 定义的时候能够不必赋值 应用的时候 如果不赋值不能够解援用 应用的是指向的变量援用 变量的别名 应用援用和应用变量是一样的 定义的时候必须绑定一个变量 绑定之后不能够让援用指向别的变量2. 函数 内联 重载 缺省2.1 内联inline 宏定义#define 不带参数 能够替换简略的函数 不能替换简单函数 先替换再计算 没有函数的跳转工夫 增长代码长度 节约运行工夫长度 消耗内存 倡议应用内联函数替换带参宏 区别: 1.内联函数 参数有类型(更平安) 带参宏没有类型 2.带参宏 先替换再计算 须要思考优先级问题 内联函数 先计算 而后后果带进去 不须要思考优先级问题 内联inline关键字 放到函数后面 倡议这个函数用内联的形式编译 `inline void(int& a)//函数背后加上inline关键字称之为内联函数 { a = 2; }` 2.2 重载 C++容许函数重名 函数定义 容许重名 函数返回值类型/参数名字不一样不形成重载 次要看参数 函数参数个数不一样 形成重载 void fun(int a); int fun(int aa, int bb); 函数参数类型不一样 形成重载 void fun(int a); int fun(double b);2.3 缺省 给函数形参一个默认值 调用函数的时候 有默认值的形参能够不必传递参数 申明/定义的时候赋值 缺省必须从右往左 void fun_1(int a, int b, int c = 1); fun_1(3, 2); void fun_2(int aa, int bb = 12, int cc = 11); fun_2(13); 缺省和重载 引发一个二义性问题 两个函数形成重载 然而调用的时候两个函数都能够匹配 void fun_3(int a, int b = 2); void fun_3(int a, int b = 4, int c = 6); fun_3(1);//此时都能够调用3.C++申请内存 new deleteC语言 申请堆内存 malloc 开释 free 头文件 stdlib.hint* p = (int*)malloc(sizeof(int)*20);//申请内存free(p);//开释内存C++申请内存 应用new 开释内存 应用deleteint* p = new int;//申请一个int;delete p;//开释一个int* pp = new int[20];//申请20个 new 类型[个数]delete[] pp;//开释多个申请内存的时候给他赋初值int* p = new int(20);//()示意初值int* pp = new int[20]{1, 2, 3. 4. 5};//赋予多个初值4.C++的输入输出形式stdio.h C语言输入输出头文件 io input输出 output输入 standard规范iostream io 输入输出 stream流count<<输入的内容<<endl;//endl示意换行 输入数据cin>>变量;//输出数据

June 21, 2021 · 1 min · jiezi

关于c++:C内存管理16GNU-C-对于-Allocator-的描述

当你将元素退出容器中,容器必须调配更多内存以保留这些元素,于是它们向其模板参数 Allocator 收回申请,该模板参数往往被另名为(aliased to)allocator_type。甚至你将 chars 增加到 string class 也是如此,因为 string 也算是一个正规 STL 容器。 template <class T, class Allocator=allocator<T>>class vector;template <class T, class Allocator=allocator<T>>class list;template <class T, class Allocator=allocator<T>>class deque;每个元素类型为 T 的容器(container-of-T) 的 Allocator 模板参数默认为 allocator<T>。其接口只有大概 20 个 public 申明,包含嵌套的(nested) typedefs 和成员函数。最终要的两个函数是: T *allocate(size_type n, const void *hint = 0);void deallocate(T *p, size_type n);n 指的是客户申请的元素个数,不是指空间数量(字节数) 这些空间都是通过调用 ::operator new 取得,但何时调用以及如许频繁调用,并无具体指定 最容易满足需要的做法就是每当容器须要内存就调用 operator new, 每当容器开释内存就调用 operator delete。这种做法比起调配大块内存并缓存(caching)而后徐徐小块应用当然慢,劣势则是能够在极大范畴的硬件和操作系统上无效运作 __gnu_cxx::new_allocator实现出俭朴的 operator new 和 operator delete 语义 ...

June 20, 2021 · 2 min · jiezi

关于c++:C内存管理15Loki-allocator-源码分析

Loki是由 Andrei 编写的一个与《Modern C++ Design》(C++设计新思维)一书配套发行的C++代码库。其中有两个文件 SmallObj.h 、SmallObj.cpp 进行内存治理,能够独自进行应用 Loki 源码下载 类层次结构SmallObj 文件中有三个类:chunk, FixedAllocator 和 SmallObjAllocator。其中SmallObjAllocator 位于最顶层供应用程序调用 ChunkChunk 是类层次结构中最底层治理内存块的类,它负责向操作系统进行内存申请 Init, Reset, Release 1. Init(), 应用 operator new 申请一段内存 chunk, 并应用 pData_ 指向 chunk2. Reset(), 对 pData_ 指向的内存进行宰割。[数组代替链表,索引代替指针] [与嵌入式指针相似]每一块 block 的第一个字节寄存的是下一个可用的 block 间隔起始地位 pData_ 的偏移量(以 block 大小为单位)3. Relese(), 向操作系统偿还内存--1. blockSize、blocksblock, block 大小及数量 2. firstAvailableBlock_,以后可用内存块的偏移量3. blocksAvailable,以后 chunk 中残余的 block 数量 unsigned char i = 0;unsigned char *p = pData;for(;i!=blocks; p+=blockSize) // 以 blockSize 为距离切分 chunk 为 block *p = ++i; // 以 block 的第一个字节存储下一个可用 block 索引参数初始化后的 chunk ...

June 20, 2021 · 3 min · jiezi

关于c++:多位专家力推丨大量经典案例分析集锦带你深入学习Nginx底层源码

前言  说到学习不晓得大家有没有一种对常识的渴望,对技术的极致谋求。不晓得大家有没有,“或者”我有。当然学习是为了获取常识、总结学习后果,便于对将来工作利用中得心应手。随着大家的激情剑拔弩张,想帮忙更多和笔者们一样的人独特学习,笔者们就产生了写书的想法。而后大家不约而同,把对常识的渴望和激情撰写成一本书。   书中作者来自各“网校”与“根底服务中台”的多位专家,在本书发明之前,组织过对Nginx底层源码的浏览与调试。经验过数个月的学习与实际,通过积攒积淀了本书。在本书中RTMP模块的解析局部,也利用到屡次直播顶峰,经验过数百万在线直播验证。 准备常识  在学习Nginx源码之前能够对一些常识进行初步理解,把握这些常识后,这样便于对常识学习与了解。 C/C++根底:首先要把握C/C++语言根底,在浏览源码过程中,是否了解语意、语法、以及相干的业务逻辑。便于学习Nginx的相干常识。GDB调试:在本书中一些调试代码片段是采纳GDB进行调试,理解GDB调试工具也便于对Nginx的过程和一些逻辑进行调试。Nginx根底应用:学习的版本为Nginx1.16版本,如果您在浏览过程中,对Nginx的一些应用曾经理解。在浏览的过程中,能够起到一些帮忙。HTTP协定与网络编程基础知识。联结作者网校团队: 聂松松好未来学而思网校学习研发直播零碎后端负责人,负责网校外围直播零碎开发和架构工作。毕业于东北大学计算机科学与技术业余,9年以上音视频及流媒体相干工作教训,精通Nginx、ffmpeg相干技术栈。 根底服务中台: 赵禹好将来后端资深开发,曾参加自主守业。目前负责将来云容器平台kubernetes组件开发,隶属于容器iaas团队。相熟PHP、Ngnix、Redis、Mysql等源码实现,乐于钻研技术。 网校团队: 施洪宝好将来后端开发专家,东南大学硕士,对Redis、Nginx、Mysql等开源软件有较深的了解,相熟C/C++、Golang开发,乐于钻研技术,合著有<<Redis5设计与源码剖析>>。 网校团队: 景罗开源爱好者,高级技术专家,曾任搜狐团体大数据高级研发工程师、新浪微博研发工程师,7年后端架构教训,相熟PHP、Nginx、Redis、MySQL等源码实现,善于高并发解决及大型网站架构,“打造学习型团队”的践行者。 网校团队: 黄桃高级技术专家,8年后端工作教训,善于高性能网站服务架构与稳定性建设,著有《PHP7底层设计与源码实现》等书籍。 网校团队: 李乐好未来学而思网校PHP开发专家,西安电子科技大学硕士,乐于钻研技术与源码钻研,对Redis和Nginx有较深了解。合著有《Redis5设计与源码剖析》。 根底服务中台: 张报好将来团体接入层网关方向负责人,对Nginx,Tengine,Openresty等高性能web服务器有深刻了解,精通大型站点架构与流量调度零碎的设计与实现。 网校团队:闫昌好将来后端开发专家,深耕信息安全畛域多年,对Linux下服务端开发有较深见解,善于高并发业务的实现。 网校团队:田峰学而思网校学服研发部负责人。13年多的互联网从业教训,先后次要在搜狗、百度、360、好将来公司从事研发和技术团队管理工作,在高性能服务架构设计及简单业务零碎开发方面领有丰盛教训。 学习疏导  在学习的过程中,可能大部分人更关注的是收益问题。一方面是技术的硬技能收益,另一方面高阶晋升。   说到学习,那么能够整顿一些学习门路。能够通过一张图来看看学习Nginx源码都须要学习些什么内容。并且能够怎么样去学习,如图1-1所示。<center>图1-1 Nginx学习纲要</center>  通过上图,能够清晰的理解到学习Nginx源码都须要学习些什么内容。在学习初期,能够先理解Nginx源码与编译装置和Nginx架构根底与设计念想,从Nginx的劣势、源码构造、过程模型等几个方面理解Nginx。而后在学习Nginx的内存治理、从内存池、共享内存开展对Nginx内存治理与应用。紧接着能够开展对Nginx的数据结构学习,别离对字符串、数组、链表、队列、散列、红黑树、根底树的数据结构和算法应用。   学习完数据结构后,能够对Nginx的配置解析、通过main配置块、events配置块与http配置块进行学习,而后学习Nginx配置解析的全副过程。接下来能够学习过程机制,通过过程模式、master过程、worker过程,以及过程建通信机制残缺理解Nginx过程的治理。而后在学习HTTP模块,通过模块初始化流程、申请解析、HTTP的11个阶段解决,以及HTTP申请响应,把握HTTP模块的处理过程。   学习完HTTP模块后,再来学习Upsteam机制,对Upstream初始化、上下游建设、长连贯、FastCGI模块做肯定了解。   而后能够理解一些模块,比方Nginx工夫模块实现,Nginx事件模型的文件事件、工夫事件、过程池、连接池等事件处理流程。其次是Nginx的负载平衡、限流、日志等模块实现。   如果要跨平台应用Nginx,能够理解跨平台实现,对Nginx的configure编译文件,跨平台原子操作锁进行肯定理解。   对直播比拟感兴趣,还能够学习Nginx直播模块RTMP实现,通过RTMP协定,模块解决流程,进一步理解RTMP模块实现。 基础架构与设计理念  从诞生以来,Nginx始终以高性能、高牢靠、易扩大闻名于世,这得益于它诸多优良的设计理念,本章就站在宏观的角度来观赏Nginx的架构设计之美。 Nginx过程模型  现在大多数零碎都须要应答海量的用户流量,人们也越来越关注零碎的高可用、高吞吐、低延时、低消耗等个性,此时玲珑且高效的Nginx走进了大家的视线,并很快受到了人们的青眼。Nginx的全新过程模型与事件驱动设计使其能天生轻松应答C10K甚至C100K高并发场景。   Nginx应用了Master治理过程(治理过程Master)和Worker工作过程(工作过程Worker)的设计,如图2-1所示。<center>图2-1 Master-Worker过程模型</center>   Master过程负责管理各个Worker,通过信号或管道的形式来管制Worker的动作。当某个Worker异样退出时,Master过程个别会启动一个新的Worker过程代替它。Worker是真正解决用户申请的过程,各Worker过程是平等的,它们通过共享内存、原子操作等一些过程间通信机制来实现负载平衡。多过程模型的设计充分利用了SMP(Symmetrical Multi-Processing)多核架构的并发解决能力,保障了服务的健壮性。   同样是基于多过程模型,为什么Nginx能具备如此强的性能与超高的稳定性,其起因有以下几点。 异步非阻塞:  Nginx的Worker过程全程工作在异步非阻塞模式下,从TCP连贯的建设到读取内核缓冲区里的申请数据,再到各HTTP模块解决申请,或者是反向代理时将申请转发给上游服务器,最初再将响应数据发送给用户,Worker过程简直不会阻塞,当某个零碎调用产生阻塞时(例如进行I/O操作,然而操作系统还没将数据筹备好),Worker过程会立刻解决下一个申请,当条件满足时操作系统会告诉Worker过程持续实现这次操作,一个申请可能须要多个阶段能力实现,然而整体上看每个Worker始终处于高效的工作状态,因而Nginx只须要很多数Worker过程就能解决大量的并发申请。当然,这些都得益于Nginx的全异步非阻塞事件驱动框架,尤其是在Linux2.5.45之后操作系统的I/O多路复用模型中新增了epoll这款神器,让Nginx换上了全新的发动机一路狂飙到性能之巅。 CPU绑定  通常在生产环境中配置Nginx的Worker数量等于CPU外围数,同时会通过worker_cpu_affinity将Worker绑定到固定的核上,让每个Worker独享一个CPU外围,这样既能无效地防止频繁的CPU上下文切换,也能大幅提高CPU缓存命中率。 负载平衡  当客户端试图与Nginx服务器建设连贯时,操作系统内核将socket对应的fd返回给Nginx,如果每个Worker都争抢着去承受(accept)连贯就会造成驰名的“惊群”问题,也就是最终只会有一个Worker胜利承受连贯,其余Worker都白白地被作零碎唤醒,这势必会升高零碎的整体性能。另外,如果有的Worker运气不好,始终承受失败,而有的Worker自身曾经很繁忙却承受胜利,就会造成Worker之间负载的不平衡,也会升高Nginx服务器的解决能力与吞吐量。Nginx通过一把全局的accept_mutex锁与一套简略的负载平衡算法就很好的解决了这两个问题。首先每个Worker在监听之前都会通过ngx_trylock_accept_mutex无阻塞的获取accept_mutex锁,只有胜利抢到锁的Worker才会真正监听端口并accept新的连贯,而抢锁失败的Worker只能持续解决已承受连贯上的事件。其次,Nginx为每个Worker设计了一个全局变量ngx_accept_disabled,并通过如下形式对该值进行初始化: ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n  其中connection_n示意每个Worker一共可同时承受的连接数,free_connnection_n示意闲暇连接数,Worker过程启动时,闲暇连接数与可承受连接数相等,也就是ngx_accept_disabled初始值为-7/8 * connection_n。当ngx_accept_disabled为负数时,表明闲暇连接数曾经有余总数的1/8了,此时阐明该Worker过程非常忙碌,于是它本次事件循环放弃争抢accept_mutex锁,专一于解决已有的连贯,同时会将本人的ngx_accept_disabled减一,下次事件循环时持续判断是否进入抢锁环节。上面的代码摘要展现了上述算法逻辑: if (ngx_use_accept_mutex) { if (ngx_accept_disabled > 0) { ngx_accept_disabled--; } else { if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { return; } …… }  总体上来看这种设计略显毛糙,但它胜在简略实用,肯定水平上保护了各Worker过程的负载平衡,防止了单个Worker耗尽资源而拒绝服务,晋升了Nginx服务器的高性能与健壮性。   另外,Nginx也反对单过程工作模式,然而这种模式不能施展CPU多核的解决能力,通常只实用于本地调试。 Nginx模块化设计  Nginx主框架中只提供了大量的外围代码,大量弱小的性能是在各模块中实现的。模块设计齐全遵循了高内聚、低耦合的准则,每个模块只解决本人职责之内的配置项,专一实现某项特定的性能,各类型的模块实现了对立的接口标准,这大大加强了Nginx的灵活性与可扩展性。 ...

June 19, 2021 · 1 min · jiezi

关于c++:性能分析之CPU分析从CPU调用高到具体代码行CC

明天在培训的过程中,也提到了剖析要具体到代码的事件,如果思路方向是正确的,对java利用和C/C++利用来说,也是几个命令就能够跳到代码行了。前提是要能看得懂堆栈信息。所以始终以来我在讲课的过程中都有画过这样的一个剖析思路的图。 在性能剖析中,如果是C/C++的利用的话,也同样是有些工具能够做失去的。明天咱们来看一个简略的C代码示例,看下如何做到这几步。我在网上看到有一段示例代码,也省得本人写了。就间接拿来编译用了。上面来看一下操作。[root@7dgroup Sample6]# gcc -o test6 -g test6.c编译的时候记得加-g的参数,能够生成调试信息。[root@7dgroup Sample6]# ./test6运行起来:[root@7dgroup Sample6]# ./test6返回值 :3返回值 5返回值 :5返回值 7返回值 :7返回值 9执行过程会产生这样的数据。同时查看top。看到31356这个过程曾经耗费了CPU。因为这个过程十分的简略,所以这里我就不再细化到线程级了。间接打堆栈看了。(如果是简单的利用的话,在这一步,还要再细化一步的就是打印线程级的状态。办法有多种,能够用top -H,也能够pidstat,也能够用调试工具attach下来再查threaddump。总之抉择本人喜爱的形式就好。)间接gstack打印堆栈。[root@7dgroup ~]# gstack 31356 #0 0x00000000004005ed in function2 (input=963) at test6.c:4 #1 0x000000000040065b in function1 (a=9, b=10) at test6.c:21 #2 0x00000000004006e8 in main () at test6.c:39当然你也能够pstack打印堆栈(因为我从新运行了一次,所以PID变了)。[root@7dgroup ~]# pstack 31438 #0 0x0000000000400620 in function3 (input=3524) at test6.c:14 #1 0x000000000040067e in function1 (a=5, b=6) at test6.c:25 #2 0x00000000004006e8 in main () at test6.c:39 ...

June 17, 2021 · 1 min · jiezi

关于c++:百度C工程师的那些极限优化并发篇

导读:对于工程教训比拟丰盛的同学,并发应该也并不是生疏的概念了,然而每个人所了解的并发问题,却又往往并不对立,本文零碎梳理了百度C++工程师在进行并发优化时所作的工作。 全文15706字,预计浏览工夫24分钟。 一、背景简略回顾一下,一个程序的性能形成要件大略有三个,即算法复杂度、IO开销和并发能力。因为古代计算机体系结构复杂化,造成很多时候,工程师的性能优化会更集中在算法复杂度之外的另外两个方向上,即IO和并发,在之前的《百度C++工程师的那些极限优化(内存篇)》中,咱们介绍了百度C++工程师工程师为了优化性能,从内存IO角度登程所做的一些优化案例。 这次咱们就再来聊一聊另外一个性能优化的方向,也就是所谓的并发优化。和IO方向相似,对于工程教训比拟丰盛的同学,并发应该也并不是生疏的概念了,然而每个人所了解的并发问题,却又往往并不对立。所以上面咱们先回到一个更基本的问题,从新梳理一下所谓的并发优化。 是的,这个问题可能有些跳跃,然而在天然地停顿到如何解决各种并发问题之前,咱们的确须要先停下来,回忆一下为什么咱们须要并发? 这时第一个会冒出来的概念可能会是大规模,例如咱们要设计大规模互联网利用,大规模机器学习零碎。可是咱们认真思考一下,无论应用了那种水平的并发设计,这样的规模化零碎背地,都须要成千盈百的实例来撑持。也就是,如果一个设计(尤其是无状态计算服务设计)曾经能够反对某种小规模业务。那么当规模扩充时,很可能伎俩并不是晋升某个业务单元的解决能力,而是减少更多业务单元,并解决可能遇到的分布式问题。 其实真正让并发编程变得有价值的背景,更多是业务单元自身的解决能力无奈满足需要,例如一次申请解决工夫过久,业务精细化导致复杂度积攒晋升等等问题。那么又是什么导致了近些年来,业务单元解决能力问题有余的问题出现更加突出的趋势? 可能上面这个统计会很阐明问题: (https://www.karlrupp.net/2015...) 上图从一个长线角度,统计了CPU的外围指标参数趋势。从其中的晶体管数目趋势能够看出,尽管可能逐步艰巨,然而摩尔定律仍然尚能维持。然而近十多年,出于管制功耗等因素的思考,CPU的主频增长根本曾经停滞,继续减少的晶体管转而用来构建了更多的外围。 从CPU厂商角度来看,单片处理器所能提供的性能还是放弃了继续晋升的,然而单线程的性能增长曾经显著放缓。从工程师角度来看,最大的变动是硬件红利不再能通明地转化成程序的性能晋升了。随时代提高,更精准的算法,更简单的计算需要,都在对的计算性能提出继续晋升的要求。早些年,这些算力的增长需要大部分还能够通过处理器更新换代来天然解决,可是随着主频增长停滞,如果无奈利用多外围来减速,程序的解决性能就会随主频一起面临增长停滞的问题。因而近些年来,是否可能充分利用多外围计算,也越来越成为高性能程序的一个标签,也只有具备了充沛的多外围利用能力,能力随新型硬件演进,持续体现出指数级的性能晋升。而随同多外围多线程程序设计的遍及,如何解决好程序的并发也逐步成了工程师的一项必要技能。 上图形容了并发减速的基本原理,首先是对原始算法的繁多执行块拆分成多个可能同时运行的子工作,并设计好子工作间的协同。之后利用底层的并行执行部件能力,将多个子工作在工夫上真正重叠起来,达到真正晋升处理速度的目标。 须要留神的是还有一条从下而上的反向剪头,次要表白了,为了正确高效地利用并行执行部件,往往会反向领导下层的并发设计,例如正确地数据对齐,正当的临界区实现等。尽管减速看似齐全是由底层并行执行部件的能力所带来的,程序设计上只须要做到子工作拆分即可。然而现阶段,执行部件对下层还无奈达到通明的水平,导致这条反向依赖对于最终的正确性和性能仍然至关重要。既理解算法,又了解底层设计,并联合起来实现正当的并发革新,也就成为了工程师的一项重要技能。 三、单线程中的并行执行提到并行执行部件,大家的第一个印象往往时多外围多线程技术。不过在进入到多线程之前,咱们先来看看,即便是单线程的程序设计中,仍然须要关注的那些并行执行能力。回过头再认真看前文的处理器趋势图其实能够发现,尽管近年主频不再增长,甚至稳中有降,然而单线程解决性能其实还是有轻微的晋升的。这其实意味着,在单位时钟周期上,单核心的计算能力仍然在晋升,而这种晋升,很大水平上就得益于单核心单线程内的细粒度并行执行能力。 3.1 SIMD其中一个重要的细粒度并行能力就是SIMD(Single Instruction Multiple Data),也就是多个执行单元,同时对多个数据利用雷同指令进行计算的模式。在经典分类上,个别单核心CPU被纳入SISD(Single Instruction Single Data),而多外围CPU被纳入MIMD(Mingle Instruction Multiple D ata),而GPU才被纳入SIMD的领域。然而古代CPU上,除了多外围的MIMD根底模型,也同时附带了细粒度SIMD计算能力。 上图是Intel对于SIMD指令的一个示意图,通过减少更大位宽的寄存器实现在一个寄存器中,“压缩”保留多个较小位宽数据的能力。再通过减少非凡的运算指令,对寄存器中的每个小位宽的数据元素,批量实现某种雷同的计算操作,例如图示中最典型的对位相加运算。以这个对位相加操作为例,CPU只须要增大寄存器,内存传输和计算部件位宽,针对这个非凡的利用场景,就晋升到了8倍的计算性能。相比将外围数通用地晋升到8倍大小,这种形式付出的老本是非常少的,指令流水线零碎,缓存零碎都做到了复用。 从CPU倒退的视角来看,为了可能在单位周期内解决更多数据,减少外围数的MIMD强化是最直观的实现门路。然而减少一套外围,就象征减少一套 残缺的指令部件、流水线部件和缓存部件,而且理论利用时,还要思考额定的外围间数据扩散和聚合的传输和同步开销。一方面昂扬的部件需要, 导致残缺的外围扩大老本过高,另一方面,多外围间传输和同步的开销针对小数据集场景额定耗费过大,还会进一步限度利用范畴。为了最大限度利用好无限的晶体管,古代CPU在塑造更多外围的同时,也在另一个维度上扩大单核心的解决和计算位宽,从而实现晋升实践计算性能(外围数 * 数据宽度)的目标。 不过提起CPU上的SIMD指令反对,有一个绕不开的话题就是和GPU的比照。CPU上晚期SIMD指令集(MMX)的诞生背景,和GPU的功能定位就非常相似,专一于减速图像相干算法,近些年又随着神经网络计算的衰亡,转向通用矩阵类计算减速。然而因为GPU在设计根底上就以面向密集可反复计算负载设计,指令部件、流水线部件和缓存部件等能够远比CPU简洁,也因而更容易在量级上进行扩大。这就导致,当计算密度足够大,数据的传输和同步开销被足够冲淡的状况下(这也是典型神经网络计算的的个性),CPU仅作为控制流进行指挥,而数据批量传输到GPU协同执行反而 会更简略高效。 因为Intel本身对SIMD指令集的宣传,也集中围绕神经网络类计算来开展,而在以后工程实践经验上,支流的密集计算又以GPU实现为主。这就导致了不少CPU上SIMD指令集无用论应运而生,尤其是近两年Intel在AVX512初代型号上的降频事件,进一步强化了『CPU就应该做好CPU该做的事件』这一论调。然而单单从这一的视角来意识CPU上的SIMD指令又未免有些全面,容易漠视掉一些真正有意义的CPU上SIMD利用场景。 对于一段程序来讲,如果将每读取单位数据,对应的纯计算复杂度大小定义为计算密度,而将算法在不同数据单元上执行的计算流的雷同水平定义为模式反复度,那么能够以此将程序划分为4个象限。在大密度可反复的计算负载(典型的重型神经网络计算),和显著小密度和非反复计算负载(例如HTML树状解析)场景下,业界在CPU和GPU的选取上其实是有绝对明确“最优解”的。不过对于过渡地带,计算的反复特色没有那么强,  或者运算密度没有那么大的场景下,单方的弱点都会被进一步放大。即使是规整可反复的计算负载,随着计算自身强度减小,传输和启动老本逐步显著。另一方面,即使是不太规整可反复的计算负载,随着计算负荷加大,外围数有余也会逐步成为瓶颈。这时候,引入SIMD的CPU和引入SIMT 的GPU间如何抉择和应用,就造成了没有那么明确,见仁见智的衡量空间。 即便排除了重型神经网络,从程序的个别个性而言,具备肯定规模的反复个性也是一种普遍现象。例如从概念上讲,程序中的循环段落,都或多或少意味着批量/反复的计算负载。只管因为掺杂着分支管制,导致反复得没有那么纯正,但这种肯定规模的细粒度反复,正是CPU上SIMD施展独特价值的中央。例如最常见的SIMD优化其实就是memcpy,古代的memcpy实现会探测CPU所能反对的SIMD指令位宽,并尽力应用来减速内存传输。另一方面古代编译器也会利用SIMD指令来是优化对象拷贝,进行简略循环向量化等形式来进行减速。相似这样的一类优化办法偏『主动通明』,也是默默撑持着主频不变状况下,性能稍有回升的重要推手。 惋惜这类简略的主动优化能做到的事件还相当无限,为了可能充分利用CPU上的SIMD减速,现阶段还十分依赖程序层进行被动算法适应性革新,有 目的地应用,换言之,就是被动施行这种单线程内的并发革新。一个无奈主动优化的例子就是《内存篇》中提到的字符串切分的优化,现阶段通过编译器剖析还很难从循环 + 判断分支提取出数据并行pattern并转换成SIMD化的match&mask动作。而更为显著的是近年来一批针对SIMD指令从新设计的算法,例如Swiss Table哈希表,simdjson解析库,base64编解码库等,在各自的畛域都带来了倍数级的晋升,而这一类算法适应性革新,就曾经齐全脱离了主动通明所能涉及的范畴。能够预知近些年,尤其随着先进工艺下AVX512降频问题的逐步解决,还会/也须要涌现出更多的传统根底算法的SIMD革新。而纯熟使用SIMD指令优化技术,也将成为C++工程师的一项必要技能。 3.2 OoOE另一个重要的单线程内并行能力就是乱序执行OoOE(Out of Order Execution)。经典教科书上的CPU流水线机制个别形容如下(经典5级RISC流水线)。 指令简化表白为取指/译码/计算/访存/写回环节,当执行环节遇到数据依赖,以及缓存未命中等场景,就会导致整体进展的产生。其中MEM环节的影响尤其显著,次要也是因为缓存档次的深入和多外围的共享景象,带来单次访存所需周期数参差不齐的景象越来越重大。上图中的流水线在多层缓存下的体现,可能更像下图所示: 为了加重进展的影响,古代面向性能优化的CPU个别引入了乱序执行联合超标量的技术。也就是一方面,对于重点执行部件,比方计算部件,访存部件等,减少多份来反对并行。另一方面,在执行部件前引入缓冲池/队列机制,通用更长的预测执行来尽可能打满每个部件。最终从流水线模式,转向了更相似『多线程』的设计模式: 乱序执行零碎中,个别会将通过预测保护一个较长的指令序列,并构建一个指令池,通过解析指令池内的依赖关系,造成一张DAG(有向无环图) 组织的网状结构。通过对DAG关系的计算,其中依赖就绪的指令,就能够进入执行态,被提交到理论的执行部件中解决。执行部件相似多线程模型中的工作线程,依据个性细分为计算和访存两类。计算类个别有绝对固定可预期的执行周期,而访存类因为指令周期差别较大,采纳了异步回调的模型,通过Load/Store Buffer反对同时发动数十个访存操作。 乱序执行零碎和传统流水线模式的区别次要体现在,当一条访存指令因为Cache Miss而无奈立刻实现时,其后无依赖关系的指令能够插队执行(相似于多线程模型中某个线程阻塞后,OS将其挂起并调度其余线程)。插队的计算类指令能够填补空窗充分利用计算能力,而插队的访存指令通过更早启动传输,让访存进展期尽量重叠来减小整体的进展。因而乱序执行零碎的效率,很大水平上会受到窗口内指令DAG的『扁平』水平的影响,依赖深度较浅的DAG能够提供更高的指令级并发能力,进而提供更高的执行部件利用率,以及更少的进展周期。另一方面,因为Load/Store Buffer也有最大的容量限度,解决较大区域的内存拜访负载时,将可能带来更深层穿透的访存指令尽量凑近排布,来进步访存进展的重叠,也可能无效缩小整体的进展。 尽管实践比拟清晰,可是在实践中,仅仅从内部指标观测到的性能体现,往往难以定位乱序执行零碎外部的热点。最直白的CPU利用率其实只能表白线程未受阻塞,实在在应用CPU的工夫周期,然而其实并不能体现CPU外部部件真正的利用效率如何。略微进阶一些的IPC(Instruction Per Cyc le),能够绝对深刻地反馈一些利用效力,然而影响IPC的因素又多种多样。是指令并行度有余?还是长周期ALU计算负载大?又或者是访存进展过久?甚至可能是分支预测失败率过高?实在程序中,这几项问题往往是并存的,而且繁多地统计往往又难以对立比拟,例如10次访存进展/20次ALU 未打满/30个周期的页表遍历,到底意味着瓶颈在哪里?这个问题繁多的指标往往就难以答复了。 ...

June 17, 2021 · 2 min · jiezi

关于c++:VisualStudio-2019-C单元测试框架CppUnitTest配置说明

问题形容:在开发过程中,咱们须要对本人写的算法进行测试,应用应用调试工具、或者运行起来调会存在测试不到位,测试效率低下等问题,应用单元测试会好很多,它效率高、容易了解,并且更合乎基于TDD(测试驱动开发)的思维,这里将Vs 下C++单元测试框架CppUnitTest的配置过程记录如下。 注释内容:首先,单元测试我的项目在Visual Studio中会随着装置各种不同的语言环境默认装置,比方装置了.net 开发环境时会装置NUnit MSTest等测试框架。这里咱们简略介绍一下C/C++开发时Visual Studio能够为咱们提供的便当之处。 装置Visual Studio2019在首次装置时只有抉择了”应用C++的桌面开发”,这个时候就会默认装置google test 模块和Boost Test模块,如图:应用,首先咱们创立一个空解决方案,而后在空解决方案下建设一个基于C++的空我的项目,咱们命名为”ProjForUnittest”咱们简略创立一个C++的类,并创立一个返回值为int的函数,用作单元测试的解说。这里咱们创立了一个叫做Calc的类,而后创立并实现了一个名称为Add的函数,其作用为将x,y两个参数相加并返回这个后果。创立测试项目CppUnittest鼠标点选解决方案右键->增加->新建我的项目,咱们在我的项目模板搜寻栏中输出Test,会呈现如下界面咱们能够看到标注语言为C++的两个单元测试我的项目模板,一个是Google Test,另一个是本机单元测试我的项目,其中本机单元测试我的项目源自于微软,绝对简略,咱们这里抉择它进行创立,创立好之后,目录如下我的项目设置(1) 将测试指标我的项目的配置类型变更为动静库 .dll 或动态库 .lib点选测试指标我的项目右键->属性->惯例->配置类型->动态库(.lib) (2) 将测试指标我的项目和测试项目的输入目录都批改为ProjectDir(默认设置是SolutionDir)属性->惯例->输入目录,将SolutionDir替换为ProjectDir(3) 将测试指标我的项目增加至单元测试我的项目援用中选中单元测试我的项目下的“援用”节点右键->增加援用->抉择测试指标我的项目点击确定(4) 将测试指标我的项目中公开的头文件所在目录增加至单元测试我的项目的附加蕴含目录选中单元测试我的项目右键->C/C++->惯例->附加蕴含目录->编辑点击增加目录按钮,抉择测试目标目录的头文件所在目录。(5) 将测试指标我的项目的.lib 或 .dll 文件的输入目录增加至单元测试文件的附加库目录,并增加.lib文件名(为测试指标我的项目的名称)至附加依赖库。1 增加附加库目录测试项目右键属性->链接器->惯例->附加库目录(同上第4条操作)将lib文件的输入目录增加到列表中(个别测试时应用的是我的项目目录下的Debug目录)2 增加库文件至附加依赖库测试项目右键属性->链接器->输出->附加依赖库在随后关上的文本框中输出.lib(指代指标测试项目输入的lib文件名。)以上就是C++单元测试我的项目之间的配置过程。

June 15, 2021 · 1 min · jiezi

关于c++:Markdown语法学习

Markdown语法学习1题目设置二级题目三级题目 四级题目 <!--题目 # + 空格 题目名称--> 2字体Hello World <!-- 加粗 字体 --> Hello World<!-- 斜体 字体 --> Hello World<!--斜体加粗 字体 --> Hello World <!--删除 字体--> 3援用good good study,day day up <!-- >援用内容 -->4分隔号<!-- --- 或 * --> 5图片![截图]() <!-- 本地图片 ctrl + shift + i --> 6超链接点击跳转到百度 7 列表无序列表AB <!-- 数字 + . + 空格 -->无序列表AB <!-- - + 空格 + 数字 -->8表格 <!-- 举荐应用鼠标右键增加啊表格 --> ...

June 13, 2021 · 1 min · jiezi

关于c++:C内存管理14SBH行为分析分配释放之连续动作图解

第一次,调配 知识点补充LPVOID VirtualAlloc{ LPVOID lpAddress, // 要调配的内存区域的地址 (当实参为0时,由操作系统指定地址) DWORD dwSize, // 调配的大小 DWORD flAllocationType, // 调配的类型 DWORD flProtect // 该内存的初始爱护属性};1. virtualAlloc 是一个 Window API 函数,该函数的性能是在调用过程的虚拟地址空间预约或者提交一部分页2. flAllocationType : MEM_RESERVE 保留调配地址,不调配物理内存。这样能够阻止其它调配函数 malloc 和 LocalAlloc 等再应用已保留的内存范畴,直到它被开释 MEM_COMMIT 为指定地址空间提交物理内存。这个函数初始化外在为零typedef struct tagGroup { int cntEntries; struct tagListHead listHead[64];}GROUP, *PGROUP;1. int cntEntries, 累计量,内存调配时+1,内存开释时-1。当 cntEntries 为 0 ,示意 8 page 全副发出,就能够将此内存块归还给操作系统typedef unsigned int BITVEC;typedef struct tagRegion { int indGroupUes; ...... BITVEC bitvGroupHi[32]; BITVEC bitvGroupLo[32]; struct tagGroup grtHeadList[32];}1. indGroupUes, 定位以后正在应用的 Group 索引2. 32 组 GROUP 对应 32 * 64 bit,当 bitvGroup[i][j] (第 i 个 GROUP 中的第 j 条双向链表)的 bit 位为 1 示意链表有可用内存块, 为 0 示意链![image.png](/img/bVcSzQZ)typedef struct tagEntry{ int sizeFront; struct tagEntry *pEntryNext; struct tagEntry *pEntryPrev;}ENTRY, *PENTRY;1. pEntryNext、pEntryPrev 为嵌入式指针,在内存块调配前后调配后有不同的解释流程形容1. 由 ioinit.c, line#18 申请 100h,区块大小 130h (debugheader、cookie、16字节对齐调整)2. 应用 Group[indGroupUes] => Group[0] ; bitvGroup[indGroupUes] [130h = 304 * 16 - 1] => bitvGroup[0] [18] bit 为 0,表明对应 Group[0][18] (listHead[18])链表中无可用区块,于是持续向右查找,Group[0][63] 最初一条链表有可用区块3. 进行内存切割(参见上节文章流程)第二次,调配__crtGetEnvironmentStringsA() 发动 ...

June 11, 2021 · 2 min · jiezi

关于c++:性能工具之代码级剖析工具

上次有人提到说下分析工具。所以再来聊聊代码级分析工具。不管怎么吹,代码级分析工具对性能自身的损耗都是存在的。并且损耗还不小。即便是在偏底层做,也照样有很大的损耗。20-30%损耗都是失常的。 要找好代码级工具的切入点,一开始就用必定是不理智。只有剖析到了某一个具体的过程或线程,或者曾经有了可疑代码的具体方法,再上代码级分析工具就更有目的性了。 JAVA方向:对JAVA来说,代码级的分析工具有好多。自带的就有不少,像当初SUN JDK中的jvirtualVM就能够实时看CPU和内存在一个办法和对象上的耗费。还有jstack/jmap等工具可辅助。如果不想实时看,做下dump也能够看内存的占用。然而要想看办法调用工夫就比拟吃力一点。不过当初有不少的商业工具,比如说jprofiler,这工具直到现在还是我所见到的在java分析中性能最全面的工具(它是商业的)。不仅有树结构,还有调用图。倡议大家尽量找到可代替的适宜的开源工具。 C/C++方向:在这个方向上,其实不止有专门的代码级分析工具,像valgrind, google perftools。也有零碎级的调试工具能够用。各种的trace工具,像perf/systemtap/oprofile之类的也都可用,并且内核级工具损耗要小一些。在solaris上有Dtrace,那本《性能之颠》的书里简直全是Dtrace工具的例子。 并且这些工具还能生成火焰图、热力求之类的。 在其余语言上也有相应的分析工具可用。像PHP有 Xdebug、xhprof;python有cprofile、memoryprofiler、lineprofiler;.net有CLR profiler;Go语言有pprof(这个是移植过去的,google perf中的工具更多)。不论是什么语言,简直相似的工具都存在的。有了这些工具,再加上零碎级的调试工具,找到代码级性能问题就是分分钟的事。 当然,还是要强调人的思考能力在社会提高中的重要性,千万不要拿着榔头打枣,够不够得着不说,举一会也够累的。适宜的工具最重要。

June 10, 2021 · 1 min · jiezi

关于c++:Qt-自定义组件动态曲线

自定义组件_滚动横幅&弹窗&对话框&字体图标等自定义组件_圆弧进度条自定义组件_水波进度条自定义组件_多彩仪表盘自定义组件_通用仪表盘自定义组件_网格组件(GirdWidget)自定义组件_动静曲线 仓库 个性可设置 Y 轴范畴、标签格局、tick 数量可设置 X 轴时间跨度、工夫格局、tick 数量可显示任意多条曲线、设置对应曲线色彩及数值点是否显示可设置曲线更新工夫距离可抉择暗藏曲线自适应窗体拉伸,图表主动缩放#ifndef DYNAMICLINE_H#define DYNAMICLINE_H#include <QChart>#include <QChartView>#include <QDateTime>#include <QDateTimeAxis>#include <QLineSeries>#include <QTimer>#include <QValueAxis>#include <QVector>#include <QWidget>using namespace QtCharts;/* 动静曲线 * 1. 可设置 Y 轴范畴、标签格局、tick 数量 * 2. 可设置 X 轴时间跨度、工夫格局、tick 数量 * 3. 可显示任意多条曲线、设置对应曲线色彩及数值点是否显示 * 4. 可设置曲线更新工夫距离 * 5. 可抉择暗藏曲线 * 6. 自适应窗体拉伸,图表主动缩放 */class DynamicLine : public QWidget{ Q_OBJECTpublic: explicit DynamicLine(QWidget *parent = nullptr); ~DynamicLine(); void start(int intervalMsec = 1000); // 开始更新图表 void stop(); // 进行更新图表 int count() const; // 曲线数量 qint64 timeAxisXSpanSecs() const; // X 轴时间跨度 void addSplineSeries(const QString &name = "", const QPen &pen = QPen(), bool pointsVisible = false); // 增加一条新的曲线public slots: void setSeriesValues(int index, int value); // 设置曲线值 void setSeriesVisible(int index, bool visible); // 设置曲线是否可见 void setChartTitle(const QString &title); // 设置图表题目 void setTimeAxisXSpanSecs(qint64 secs); // 设置 X 轴时间跨度 void setTimeAxisXFormat(const QString &format = "HH:mm"); // 设置 X 轴工夫格局 void setTimeAxisXTickCount(int tickCount); // 设置 X 轴 tick 数量 void setAxisYRange(qreal min, qreal max); // 设置 Y 轴范畴 void setpAxisYTickCount(int count); // 设置 Y 轴 tick 数量 void setAxisYLabelFormat(const QString &format); // 设置 Y 轴标签格局private: void initUi(); void initCtrl(); QLineSeries *createSeries(QChart *chart, const QString &name, const QPen &pen, bool pointsVisible = false);private slots: void updateChart();private: QVector<QLineSeries*> m_series; QChartView* m_pChartView = nullptr; QChart* m_pChart = nullptr; QDateTimeAxis* m_pTimeAxisX = nullptr; QValueAxis* m_pAxisY = nullptr; qint64 m_spanSecs = 60; QVector<int> m_lastValues; bool m_isFirstTime = false; QTimer m_timer;};#endif // DYNAMICLINE_H

June 9, 2021 · 2 min · jiezi

关于c++:千万不要错过的后端纯干货面试知识点整理-I

C++面试题 语言相干根底题对象复用的理解,零拷贝的理解 对象复用 指得是设计模式,对象能够采纳不同的设计模式达到复用的目标,最常见的就是继承和组合模式了。 零拷贝: 零拷贝次要的工作就是防止CPU将数据从一块存储拷贝到另外一块存储,次要就是利用各种零拷贝技术,防止让CPU做大量的数据拷贝工作,缩小不必要的拷贝,或者让别的组件来做这一类简略的数据传输工作,让CPU解脱进去专一于别的工作。这样就能够让系统资源的利用更加无效。 零拷贝技术常见linux中,例如用户空间到内核空间的拷贝,这个是没有必要的,咱们能够采纳零拷贝技术,这个技术就是通过mmap,间接将内核空间的数据通过映射的办法映射到用户空间上,即物理上共用这段数据。 介绍C++所有的构造函数默认构造函数、个别构造函数、拷贝构造函数 默认构造函数(无参数):如果创立一个类你没有写任何构造函数,则零碎会主动生成默认的构造函数,或者写了一个不带任何形参的构造函数个别构造函数:个别构造函数能够有各种参数模式,一个类能够有多个个别构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)拷贝结构函数参数为类对象自身的援用,用于依据一个已存在的对象复制出一个新的该类的对象,个别在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中。参数(对象的援用)是不可变的(const类型)。此函数常常用在函数调用时用户定义类型的值传递及返回。为什么要内存对齐? 平台起因(移植起因):不是所有的硬件平台都能拜访任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异样。性能起因:数据结构(尤其是栈)应该尽可能地在天然边界上对齐。起因在于,为了拜访未对齐的内存,处理器须要作两次内存拜访;而对齐的内存拜访仅须要一次拜访。成员初始化列表的概念,为什么用成员初始化列表会快一些? 类型一 : 内置数据类型,复合类型(指针,援用) 类型二 : 用户定义类型(类类型) 对于类型一,在成员初始化列表和构造函数体内进行,在性能和后果上都是一样的 对于类型二,后果上雷同,然而性能上存在很大的差异 因为类类型的数据成员对象在进入函数体是曾经结构实现,也就是说在成员初始化列表处进行结构对象的工作,这是调用一个构造函数, 在进入函数体之后,进行的是 对曾经结构好的类对象的赋值,又调用个拷贝赋值操作符能力实现(如果并未提供,则应用编译器提供的默认按成员赋值行为) 简略的来说: 对于用户定义类型: 如果应用类初始化列表,间接调用对应的构造函数即实现初始化如果在构造函数中初始化,那么首先调用默认的构造函数,而后调用指定的构造函数所以对于用户定义类型,应用列表初始化能够缩小一次默认结构函数调用过程 c/c++ 程序调试办法 printf 大法(日志)本人封装宏函数,进行打印出错地位的文件,行号,函数 通过gcc -DDEBUG_EN 关上调试信息输入 #ifdefine DEBUG_EN#define DEBUG(fmt, args...) \do { \printf("DEBUG:%s-%d-%s "fmt, __FILE__, __LINE__, __FUNCTION__, ##args);\}while(0) #define ERROR(fmt, args...) \do { \printf("ERROR:%s-%d-%s "fmt, __FILE__, __LINE__, __FUNCTION__, ##args);\}while(0)#else#define DEBUG(fmt, args) do{}while(0)#define ERROR(fmt, args) do{}while(0)#endifcore-dump/map 调试当程序运行的过程中异样终止或解体,操作系统会将程序过后的内存状态记录下来,保留在一个文件中,这种行为就叫做Core Dump. MAP 文件是程序的全局符号、源文件和代码行号信息的惟一的文本示意办法,是整个程序工程信息的动态文本,通常由linker生成。 gdb通过运行程序,打断点、单步、查看变量的值等形式在运行时定位bug。 file <文件名>加载被调试的可执行程序文件b <行号>/<函数名称>在第几行或者某个函数第一行代码前设置断点r运行s单步执行一行代码n执行一行代码,执行函数调用(如果有)c持续运行程序至下一个断点或者完结p<变量名称>查看变量值q退出援用是否能实现动静绑定,为什么援用能够实现 因为对象的类型是确定的,在编译期就确定了,指针或援用是在运行期依据他们绑定的具体对象确定。 ...

June 8, 2021 · 2 min · jiezi

关于c++:C类的多态性一

目标把握运算符重载的应用办法 内容编程题1.(1)以成员函数的形式,实现运算符“+”的重载,程序运行后果放弃不变; (2)以友元函数的形式,实现运算符“+”的重载,程序运行后果放弃不变。代码:(1) #include<iostream.h>class Box{public: Box(){} Box(int l,int b, int h) { length=l; breadth=b; height=h; } Box operator+(Box& b) { Box box; box.length=length+b.length; box.breadth=breadth+b.breadth; box.height=height+b.height; return box; } void print() { cout<<"length:"<<length<<endl; cout<<"breadth:"<<breadth<<endl; cout<<"height:"<<height<<endl; }private: double length; double breadth; double height;};int main(){Box Box1(1,2,3);Box Box2(4,5,6);Box Box3;Box3=Box1+Box2;Box3.print();return 0;}后果:(2) #include<iostream.h>class Box{public: Box(){} Box(int l,int b, int h) { length=l; breadth=b; height=h; } friend Box operator+(Box& b,Box& b1); void print() { cout<<"length:"<<length<<endl; cout<<"breadth:"<<breadth<<endl; cout<<"height:"<<height<<endl; }private: double length; double breadth; double height;}; Box operator+(Box& b,Box& b1) { Box box; box.length=b1.length+b.length; box.breadth=b1.breadth+b.breadth; box.height=b1.height+b.height; return box; }int main(){Box Box1(1,2,3);Box Box2(4,5,6);Box Box3;Box3=Box1+Box2;Box3.print();return 0;}后果:2.把握以类的成员函数重载运算符的应用办法代码: ...

June 7, 2021 · 2 min · jiezi

关于c++:C内存管理13VC6-内存分配

VC6_SBH 概述SBH 是 Small Block Heap 的缩写,进行操作系统之上的小区块内存的治理。在 VC6 中可找到源码实现,降级版本 VC10 中对立应用零碎API进行内存申请, SBH 被整合到了操作系统外部。 VC6 局部实现 VC10 局部实现 留神: __heap_init 和 __ioinit 在 VC6 和 VC10 中都存在 VC6_SBH 合成heap_init(...)_heap_init(...) 、__sbh_heap_init() 阐明 :CRT 会先为本人创立一个 _ctrheap "独特"内存(HeapCreate), 而后从中配置 SBH 所需的 headers, regions(__sbh_heap_init).应用程序内存申请时如果 size > threshold 就以 HeapAlloc() 从 _crtheap 取.若size <= thread 就从 SBH 取(理论区块来自 VirtualAlloc) 1. 操作系统内存治理的一些概念:可创立一块独特的空间并给其命名,之后相干操作所需的内存都取自这里【逻辑上分类】1.1 HeapCreate 要求操作系统调配一块内存1.2 __crtheap 全局指针变量,指向调配的内存空间,专为 CRT(C Run Time) 应用2. __sbh_heap_init,到 __ctrheap 指向的内存获取 16 * sizeof(Header) 空间2.1 每个 SBH 中还有 16 个HEADERheader 构造剖析 ...

June 6, 2021 · 2 min · jiezi

关于c++:多线程使用libevent那些花里胡哨的技巧

原文 前言libevent 封装了底层多路复用接口,让咱们能够更不便地跨平台应用异步网络IO。同时, libevent 还实现了定时工作,应用它咱们就不必本人实现一遍了,还是比拟不便。 libevent 官网提供了 libevent的教程、libevent的例子 以及libevent的接口文档,写得 相当好。我在浏览过一遍之后,开始尝试应用它实现一个负责与物联网设施通信的接入程序, 也就是一般的TCP/UDP服务端,承当接管连贯申请、接收数据、下发数据、验证身份、转发 设施申请、治理连贯超时、以及实现一些简略的接口,当然还有其它懒得说的性能。这个程 序跟 nginx 是很像的,之前我间接用 epoll 实现过很多个相似的程序,最近看到 libevent 开发的程序很多,于是开始尝试应用它。 而后遇到了问题。我尝试创立多个IO线程,然而事件并不是我设想的那样, event_del() 阻塞了。libevent 的事件操作只能在 dispatch 循环同一个线程中执行,也就是循环退 出后,或者在回调函数中。 一番调试后有了这个echo-server 例子,以及这篇阐明,记录我调试的过程。 libevent 入门libevent 有两个概念,event_base 和 event。 event 是事件,能够设定触发条件(可读/可写/超时/信号),以及条件登程后须要 执行的函数。event 相当于 epoll 中的 epoll_event。 事件循环在 event_base 上执行,event_base 里记录了所有事件的触发条件,循环中查看 条件,如果条件满足,则调用 event 中指定的函数。event_base 相当于 epoll 中 epoll_create() 创立的构造。 例如,要读取一个文件描述符 fd ,能够创立一个读事件,在事件的回调函数中读 fd : // 事件的回调函数void event_cb(evutil_socket_t fd, short what, void* arg) { // 在这里读 fd // ...}void* arg = NULL;// 创立 event_basestruct event_base* ev_base = event_base_new();// 创立 event, 能够从一个event_base中创立多个eventstruct event* ev = event_new(ev_base, fd, EV_READ, event_cb, arg);// 把事件注册到循环中event_add(ev, NULL);// 开始事件循环,如果事件的条件满足,则调用事件的回调函数event_base_dispatch(ev_base);设计构造有两种形式构造能达到我的目标,一种是一个线程监听事件,线程池处理事件;第二种是多 个线程监听事件,事件登程后间接在本线程中执行。我应用的是第二种。 ...

June 4, 2021 · 1 min · jiezi

关于c++:C多线程强制终止

摘要:实际上,没有任何语言或操作系统能够为你提供异步忽然终止线程的便当,且不会正告你不要应用它们。本文分享自华为云社区《如何编写高效、优雅、可信代码系列(1)——C++多线程强制终止》,原文作者:我是一颗大西瓜 。 故事的起因来源于我在优化别人c++源码的时候,想通过多线程的形式晋升程序的运算效率,次要存在以下需要和难点: 多个线程并行跑模型,看哪个模型跑的快,跑进去后完结其余线程,线程间独立运行无通信过程源码模型很简单,函数调用较多,不好改变,因而不太适宜通过信号或标记进行通信终止网上搜寻了一下线程完结的几种形式: 1. 线程函数的return返回(倡议)。这种退出线程的形式是最平安的,在线程函数return返回后, 会清理函数内申请的类对象, 即调用这些对象的析构函数.。而后会主动调用 _endthreadex()函数来清理 _beginthreadex()函数申请的资源(次要是创立的tiddata对象)。2. 同一个过程或另一个过程中的线程调用TerminateThread函数(应防止应用该办法)。TerminateThread可能吊销任何线程,其中hThread参数用于标识被终止运行的线程的句柄。当线程终止运行时,它的退出代码成为你作为dwExitCode参数传递的值。同时,线程的内核对象的应用计数也被递加。留神TerminateThread函数是异步运行的函数,也就是说,它通知零碎你想要线程终止运行,然而,当函数返回时,不能保障线程被吊销。如果须要确切地晓得该线程曾经终止运行,必须调用WaitForSingleObject或者相似的函数,传递线程的句柄。3. 通过调用ExitThread函数,线程将自行吊销(最好不应用该办法)。该函数将终止线程的运行,并导致操作系统革除该线程应用的所有操作系统资源。然而,C++资源(如C++类对象)将不被析构。4. ExitProcess和TerminateProcess函数也能够用来终止线程的运行(应防止应用该办法)。 选项2和3可能会导致内存透露,实际上,没有任何语言或操作系统能够为你提供异步忽然终止线程的便当,且不会正告你不要应用它们。所有这些执行环境都强烈建议开发人员,甚至要求在合作或同步线程终止的根底上构建多线程应用程序。 现有的线程完结函数,包含linux零碎的pthread.h中的pthread_exit()和pthread_cancel(),windows零碎的win32.h中的ExitThread()和TerminateThread(),也就是说,C++没有提供kill掉某个线程的能力,只能被动地期待某个线程的天然完结,析构函数~thread()也不能进行线程,析构函数只能在线程静止时终止线程joinable,对于连贯/拆散的线程,析构函数根本无法终止线程。 要终止与OS /编译器相干的函数的线程,咱们须要晓得如何从C++获取本机线程数据类型std::thread。侥幸的是,在调用或之前std::thread提供了一个API native_handle()以获取线程的本机句柄类型。并且能够将此本地句柄传递给本地OS线程终止函数,例如join() detach() pthread_cancel()。 以下代码用于显示std::thread::native_handle(),std::thread::get_id()并pthread_self()返回雷同的代码pthread_t来解决Linux / GCC的C++线程 #include <mutex>#include <iostream>#include <chrono>#include <cstring>#include <pthread.h> std::mutex iomutex;void f(int num){ std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lk(iomutex); std::cout << "Thread " << num << " pthread_t " << pthread_self() << std::endl;} int main(){ std::thread t1(f, 1), t2(f, 2); //t1.join(); t2.join(); ----------------pos 1 //t1.detach(); t2.detach(); -------------pos 2 std::cout << "Thread 1 thread id " << t1.get_id() << std::endl; std::cout << "Thread 2 thread id " << t2.get_id() << std::endl; std::cout << "Thread 1 native handle " << t1.native_handle() << std::endl; std::cout << "Thread 2 native handle " << t2.native_handle() << std::endl; t1.join(); t2.join(); //t1.detach(); t2.detach();}运行后能够失去后果 ...

June 4, 2021 · 2 min · jiezi

关于c++:思否发文停更

在这里发文有一段时间啦,浏览量和互动太少,决定停更啦,后续有须要的能够关注公众号哦

June 3, 2021 · 1 min · jiezi

关于c++:c中typenametypedef以及using关键字用法

在c++的规范库中,因为类继承关系比较复杂和模板应用比拟多的起因,源代码中充斥着typename、typedef和using这三个关键字,所以在持续分析规范库源码之前,明天就来介绍一下这三个关键字的作用。 一、typename关键字typename的第一个作用是用作模板外面,来申明某种类型,比方这样的: template<typename _Tp, typename _Alloc> struct _Vector_base;最开始的时候申明模板形参,也会应用class,但咱们都晓得class总要是用来指定一个类名,据说是为了防止混同,所以起初减少了typename这个关键字,它通知编译器,跟在它前面的字符串是一个不确定的类型,而不是变量或者其余什么货色。 typename在stl中还有另外一种作用,假如有这样一段代码: //test.cpp#include <ext/alloc_traits.h>using namespace std;template<typename _Tp, typename _Alloc>class AA{typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;};这里顺便说一下rebind后面为啥要放一个template,它是为了通知编译器前面的<>是用于指定模板参数,而进行比拟。这个时候咱们应用g++ -c test.cpp -o test.o是能够编译通过的,但如果咱们去掉第三个typename看,会产生什么呢? 再次编译,报错如下: test.cpp:8:10: 谬误:‘typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Tp>::other’之前须要‘typename’,因为‘typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Tp>’是一个有依赖的作用域 typedef __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;编译器间接指明了须要一个typename,实际上typename在这里也是指定它前面的字符串为类型,这是因为对于形如AA::BB这样的模式,它有可能是一个类型,也有可能是类的动态成员,这个时候加上typename就是为了通知编译器,它前面的一大串字符串都是一个类型。 二、typedef关键字还是这段代码,咱们增加一行: #include <ext/alloc_traits.h>using namespace std;template<typename _Tp, typename _Alloc>class AA{ typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type; _Tp_alloc_type tp;};这个typedef实际上就是给类型取了一个别名,将__gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other这么一长串的类型取了一个简略的别名,要是不取别名,这样长的类型真的是不忍直视。 当然啦,typedef除了这种模式以外,其实很多时候也会给函数指针取别名哦,如下: typedef int (*func)(int a, int b);这个时候实际上就是给int * (int a, int b)这个函数指针取了一个别名func。 三、using关键字对于using关键字,最开始晓得是因为这行代码: using namespace std;所以它的第一个作用就是申明命名空间,应用形如using namespace 命名空间名;这样的模式通知编译器,后续应用该命名空间外面的变量或者类型都无需再加上std的前缀,这个是对于命名空间整体的申明。 ...

June 3, 2021 · 1 min · jiezi

关于c++:超详细STL之基于源码剖析vector实现原理及注意事项

本篇文章基于源码来分析规范模板库中vector容器的实现原理及一些非凡注意事项。 阐明一下,我用的是gcc7.1.0编译器,规范库源代码也是这个版本的。多年以前面试的时候第一次被问到stl中vector的底层实现,那个时候的我真的很low,基本答复不上来,起初面试回来,在网络上搜寻了一些vector底层实现,晓得了它的底层是动静数组,但光晓得动静数组是不够的,进一步的,动静数组写满了怎么办,它的实现用了c++的什么技术,一些非凡场景下怎么应用vector更有效率等等,这些极少有人讲清楚,明天我基于gcc外面的源码来分析一下这些比拟深刻的问题。 先来看一下本篇文章思维导图,如下: 一. vector的实现原理1. vector的基类介绍先看一下class vector的申明,截取头文件stl_vector.h中局部代码,如下: //两个模板参数,第一个是数据类型,第二个std::allocator是规范库中动态内存分配器,最终其实是调用了new运算符template<typename _Tp, typename _Alloc = std::allocator<_Tp> > class vector : protected _Vector_base<_Tp, _Alloc> {...};从源码的实现来看,其实vector是一个模板派生类,也就是说,它首先是一个模板类,这一点咱们应该都猜得到,毕竟咱们应用的时候都是应用形如vector<int>这样的模式来进行申明一个vector对象的,其次它是一个派生类,它的基类是_Vector_base,所以咱们首先来看一下这个基类的实现。 能够看到这里vector继承基类时是protected,这个过程咱们称为爱护继承,爱护继承的特点是:基类的私有成员在派生类中也成为了爱护成员,基类的爱护成员和公有成员在派生类中应用权限与基类统一,放弃不变。还是头文件stl_vector.h,截取这个基类的一段实现代码,如下: template<typename _Tp, typename _Alloc> struct _Vector_base { typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type; typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer; struct _Vector_impl : public _Tp_alloc_type { pointer _M_start;//容器开始地位 pointer _M_finish;//容器完结地位 pointer _M_end_of_storage;//容器所申请的动态内存最初一个地位的下一个地位 _Vector_impl() : _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage() { } ... //局部代码没截取的以省略号代替,后续同理 }; public: typedef _Alloc allocator_type; ...//此处省略局部源代码 _Vector_base() : _M_impl() { } _Vector_base(size_t __n) : _M_impl() { _M_create_storage(__n); } ...//此处省略局部源代码 public: _Vector_impl _M_impl; pointer _M_allocate(size_t __n) { typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer(); } void _M_deallocate(pointer __p, size_t __n) { typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; if (__p) _Tr::deallocate(_M_impl, __p, __n); } private: void _M_create_storage(size_t __n) { this->_M_impl._M_start = this->_M_allocate(__n); this->_M_impl._M_finish = this->_M_impl._M_start; this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; } };这样看,这个基类的性能就很清晰了,它申明了一个构造体struct _Vector_impl,同时以这个构造体申明了一个私有成员变量_M_impl,对于基类的无参构造函数,它也只是调用了struct _Vector_impl的构造函数,进而调用了struct _Vector_impl的各个成员变量的构造函数。 ...

June 2, 2021 · 3 min · jiezi

关于c++:音视频编解码之路JPEG编码

音视频编解码之路:JPEG编码本文首发于音视频编解码之路:JPEG编码 前言本篇是新开坑的 音视频编解码之路 的第一篇,这个系列次要通过书籍、网上的博文/代码等渠道,整顿与各编码协定相干的材料和本人的了解,同时手撸下对应格局的“编解码器”,造成对真正编解码器的原理的根底意识,从而后续能够进一步钻研真正意义上的编解码器如libx264的逻辑与优化。 之前在查找编解码的学习材料时,看到了韦神的经验之谈,因而就以JPEG的编码来开篇吧。 本篇整体脉络来自于手动生成一张JPEG图片,不过针对文章中的诸多细节做了补充和材料汇总,另外把代码也用C++和OOP的形式批改了下。范例工程位于avcodec_tutorial。 编码步骤根本零碎的 JPEG 压缩编码算法一共分为 10 个步骤: 色彩模式转换分块离散余弦变换(DCT)量化Zigzag 扫描排序DC 系数的差分脉冲调制编码(DPCM)DC 系数的两头格局计算AC 系数的游程编码(RLE)AC 系数的两头格局计算熵编码接下去咱们将逐个介绍上述的各个步骤,并在其中交叉波及的一些概念与理论代码。 色彩模式转换JPEG 采纳的是 YCbCr 色彩空间,这里不再赘述为啥抉择YUV等等反复较多的内容,之前没有接触过的能够看下一文读懂 YUV 的采样与格局和其余材料来补补课。 色彩模式从RGB转为YUV的过程中能够把采样也一起做了,这里Demo采样依照YUV444也就是全采样不做额定解决的形式简略实现,代码如下: uint8_t bound(uint8_t min, int value, uint8_t max) { if(value <= min) { return min; } if(value >= max) { return max; } return value;}bool JpegEncoder::rgbToYUV444(const uint8_t *r, const uint8_t *g, const uint8_t *b, const unsigned int &w, const unsigned int &h, uint8_t *const y, uint8_t *const u, uint8_t *const v) { for (int row = 0; row < h; row++) { for (int column = 0; column < w; column++) { int index = row * w + column; // rgb -> yuv 公式 // 这里在实现的时候踩了个坑 // 之前间接将cast后的值赋值给了y/u/v数组,y/u/v数组类型是uint8,计算出来比方v是256间接越界数值会被转成其余如0之类的值 // 导致最初色彩成果谬误 int yValue = static_cast<int>(round(0.299 * r[index] + 0.587 * g[index] + 0.114 * b[index])); int uValue = static_cast<int>(round(-0.169 * r[index] - 0.331 * g[index] + 0.500 * b[index] + 128)); int vValue = static_cast<int>(round(0.500 * r[index] - 0.419 * g[index] - 0.081 * b[index] + 128)); // 做下边界容错 y[index] = bound(0, yValue, 255); u[index] = bound(0, uValue, 255); v[index] = bound(0, vValue, 255); } } return true;}分块因为前面的 DCT 变换须要对 8x8 的子块进行解决,因而在进行 DCT 变换之前必须把源图像数据进行分块。源图象通过下面的色彩模式转换、采样后变成了 YUV 数据,所以须要别离对 Y U V 三个重量进行分块。具体分块形式为由左及右,由上到下顺次读取 8x8 的子块,寄存在长度为 64 的数组中,之后再进行 DCT 变换。 ...

June 1, 2021 · 13 min · jiezi

关于c++:http请求那点事

前言这次我的项目应用了angular + 第三方c++http服务对接。没有了脱离了相熟的springboot,刚加靠近原生。也遇到了很多问题。 回绝连贯照着第三方库启动c++服务后,在本机测试能够申请到 然而应用其余电脑,把localhost改成服务器ip就无奈申请到通过去看github我的项目上的issue看到,大家也遇到了如此问题,最初大家的解决办法是以管理员身份运行vs并且将代码从 web::http::experimental::listener::http_listener getStatusListener(L"http://127.0.0.1:8015/getStatus");改成 web::uri_builder uri; uri.set_scheme(U("http")); uri.set_host(U("+")); uri.set_port(U("8015")); uri.set_path(U("/getStatus")); web::http::experimental::listener::http_listener getStatusListener(uri.to_uri());具体起因也没有具体阐明(或者我没有看懂)。问了老师后,老师倡议配置一下nginx解决。通过这次配置nginx,了解了nginx实质上还是服务器,原来认为nginx只负责端口转发,springboot起服务作用的是tomcat。就如thinphp的apache一样。 通过nginx对申请的转发,对于c++服务来说nginx对他的申请就是localhost的地址。从而解决问题。在后盾增加了一个post接口,用于启动捕捉数据。应用API Tester插件测试接口。然而在启动前台单元测试进行对接的时候,申请同样的地址,产生了申请谬误。更加奇怪的是,他间断对同一地址申请了两次,而我只操作了一次。第二次返回了200,然而服务器端也没有响应打印信息。第一次申请的CORS error报错在写上一个GET申请接口的时候也遇到过,这是因为前后台不同源,违反了同源策略,解决办法是在相应头上退出Access-Control-Allow-Origin:*字段,容许跨域拜访。 // 响应web::http::http_response response(web::http::status_codes::OK);response.headers().add(U("Access-Control-Allow-Origin"), U("*"));response.set_body(jsonResponseFinal);request.reply(response);然而再遇到雷同问题,这个解决办法没有胜利。当初的问题是1.为什么同样的谬误解决办法只实用于GET申请而不实用与POST申请?2.并且为什么会申请了两次?3.为什么API Tester测试没有问题?带着这些问题问了学长。学长看了当前发现第二次返回200的申请其实是OPTIONS申请。什么是OPTIONS申请呢。咱们能够把OPTIONS申请当做先遣队。OPTIONS申请的主要用途有两个一是获取服务器反对的HTTP申请办法;二是用来查看服务器的性能。 那些可能会操作数据库的申请(除GET申请外),都会应用 OPTIONS 发动一个预检申请(preflight request),从而获知服务端是否容许该跨域申请。服务器确认容许之后,才发动理论的 HTTP 申请。Preflighted Requests是CORS中一种通明服务器验证机制。预检申请首先须要向另外一个域名的资源发送一个 HTTP OPTIONS 申请头,其目标就是为了判断理论发送的申请是否是平安的。上面的状况须要进行预检:非简略申请,比方应用Content-Type 为 application/xml 或 text/xml 的 POST 申请;(什么是简略申请,什么是非简略申请,请移步阮一峰的跨域资源共享 CORS 详解)上面借用MDN的图来更直观的看一下 所以解决也就是在options相应头退出容许申请。 web::http::experimental::listener::http_listener startCaptureListener(L"http://127.0.0.1:8015/startCapture");startCaptureListener.support(web::http::methods::POST, [&](web::http::http_request request) { this->startCapture(request);});startCaptureListener.support(web::http::methods::OPTIONS, [&](web::http::http_request request) { this->allow(request);});void YzHttp::HttpService::allow(web::http::http_request request) { web::http::http_response response(web::http::status_codes::OK); response.headers().add(U("Access-Control-Allow-Origin"), U("*")); response.headers().add(U("Access-Control-Allow-Methods"), U("POST")); response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")); request.reply(response);}问题解决。最初一个问题,为什么用API Tester测试能通过呢。可能无奈模仿真正的浏览器拜访吧。 ...

May 29, 2021 · 1 min · jiezi

关于c++:如何使用VS2017编译64位PG2库

Parser Generator 2是Windows下YACC和LEX的实现,是由英国Bumble-Bee Software公司开发。下载网址:http://www.bumblebeesoftware....官网只提供了32位的编译脚本,没有64位的编译脚本,依据网友在VS2008上的编译教训及本人的摸索,钻研了如何应用VS2017编译64位库。 文档具体内容分享在百度云盘上了,须要的能够下载: 链接:https://pan.baidu.com/s/1X94Z... 提取码:mvad 复制这段内容后关上百度网盘手机App,操作更不便哦--来自百度网盘超级会员V6的分享

May 28, 2021 · 1 min · jiezi

关于c++:题解5道c面试题第一期含解题思路答案解析和实现代码

本篇文章送上5道c/c++面试题目,并附上答案、解题思路以及扩大常识。 1. 求上面函数的返回值#include <stdio.h>int func(int x){ int iCnt = 0; while(x) { iCnt++; x = x&(x-1); } return iCnt;}int main(){ printf("cnt = %d\n", func(9999)); return 0;}这题问的是函数的返回值,而通过代码咱们能看到返回值的多少取决于x什么时候变为0,而x的值又取决于x&(x-1)这个表达式,在c++中有一个规定,但凡看到&或者|这样的符号,那就把它左右两边的值转换为二进制去计算,假如x是7,转换为二进制是00000111,x-1那就是00000110,那x&(x-1)就变成00000110了,再减一个1,变成00000101,那x&(x-1)就是00000100,所以实际上这个表达式每执行一次,二进制就少一个1,这样的话,这篇题目就转换成了,输出的数字转换为二进制有多少个1,那么返回值就是多少。 9999转换为二进制是10011100001111,所以本道题目答案:cnt = 8。 2. 上面的代码输入是什么?给一段代码,如下: #include <stdio.h>void testputs(){ unsigned int a = 6;//无符号整型 int b = (-20);//有符号整型 (a+b) > 6 ? puts(">6"):puts("<6");}int main(){ testputs(); return 0;}初一看,6+(-20)应该是-14,那就应该输入<6,然而这么简略的话,就不会有这么一道题了,咱们编译后实际上输入了>6的后果,这是为什么呢,因为在c语言中,无符号和有符号进行运算或者比拟的时候,都会间接把有符号的转换为无符号,而后再进行运算或者比拟。 当初让咱们减少一行代码,看看输入后果,如下: #include <stdio.h>void testputs(){ unsigned int a = 6; int b = (-20); (a+b) > 6 ? puts(">6"):puts("<6"); printf("%u\n", b);//%u输入无符号整型}int main(){ testputs(); return 0;}编译后输入如下后果: ...

May 28, 2021 · 1 min · jiezi

关于c++:windows系统如何在C项目中使用第三方库

要应用第三方库,首先须要进行装置。在没有vcpkg以前,装置第三方库须要在本地进行编译与链接,而如果咱们是老手,则必然会遇到这样或那样难以解决的问题。但有了vcpkg当前就不一样,vcpkg会主动的替咱们实现这所有。 装置vcpkg以管理员权限运行powershell,执行进行clone我的项目、运行批处理文件、运行集成装置命令: PS C:\Users\panjie\github> git clone https://github.com/microsoft/vcpkg --depth=1PS C:\Users\panjie\github> cd .\vcpkg\PS C:\Users\panjie\github\vcpkg> .\bootstrap-vcpkg.bat稍等一会,待装置胜利的提醒。vcpkg应该是vc++ package manager的简称,即vc++包管理器,它的作用同其它的包管理器。但可能是因为c++呈现的比拟早,所以其包管理器做的没有npm这样的管理器那么优良。 装置第三方包应用vcpkg装置第三方包非常简单,只须要执行vcpkg install 包的名称即可。如果咱们不晓得包的具体名称,还能够应用vcpkg search 包的名称来进行搜寻,比方咱们想实现websocket性能,则能够执行: .\vcpkg.exe search websocket。 PS C:\github\vcpkg> .\vcpkg.exe search websocketbeast 0 HTTP/1 and WebSocket, header-only using Boost.Asio and C++11brynet 1.11.0 A C++ header only cross platform high performance tcp network library, and sup...bsio 1.0.0 networking library, ans support HTTP/WebSocket, based on asio.cpprestsdk[websockets] Websockets supportixwebsocket 11.2.6 Lightweight WebSocket Client and Server + HTTP Client and Server...uwebsockets 19.0.0.5 Simple, secure & standards compliant web I/O for the most demanding of applica...websocketpp 0.8.2#1 Library that implements RFC6455 The WebSocket Protocol或者也能够关上https://vcpkg.io/en/packages.html进行搜寻。 ...

May 27, 2021 · 2 min · jiezi

关于c++:手写strcpy和memcpy代码实现

本篇文章聊一下strcpy和memcpy的代码实现,这两个也是c和c++面试中常考的问题点。 1. 手写strcpy首先看一下,一份规范的strcpy的实现如下: char *strcpy(char* strDest, const char* strSrc){ assert( (strDest != NULL) && (strSrc != NULL)); char *address = strDest; while((*strDest++ = *strSrc++) != '\0'); return address;}这里有如下几点须要留神: 源字符串要应用const类型,防止在程序中被批改;在函数入口处要加上断言,查看源字符串指针和指标字符串指针是否有为空的,否则会产生不可意料的谬误;应用while循环要简略而清晰,应用尽量精简的代码;返回值要是char*,且返回了指标字符串指针的原值,使得函数能够反对链式表达式,减少了函数的附加值。以上这些点不只实用于strcpy这里,而是咱们任何时候写代码都尽量遵循这些规定,这样能力写出高可用、高健壮性的代码。 对于以上代码,咱们能够看进去,它是存在隐患的,当源字符串的长度超出指标字符串时,会导致把数据写入到咱们无法控制的地址中去,存在很大的危险,所以就有了strncpy,上面也给一个strncpy的实现,如下: char *strncpy(char* strDest, const char* strSrc, size_t n){ assert( (strDest != NULL) && (strSrc != NULL)); char *address = strDest; while ( n-- && (*strDest++ = *strSrc++) != '\0'); return address;}要依据输出的长度做一个管制,而往往咱们应用的时候,输出的长度都是指标字符串的长度减1,因为要留一个地位给结束符'\0'。 2. memcpy的实现memcpy的实现其实能够参考strncpy的实现,比方咱们把指针类型转换成char*来实现拷贝,这种形式就是依照一个字节一个字节来进行拷贝了,首先还是一睹代码为快,如下: #include <stdio.h>#include <string.h>struct people{ int iAge; char szName[12]; char szSex[3];};//模仿memcpy的实现void * mymemcpy(void *dest, const void *src, size_t n){ if (dest == NULL || src == NULL) return NULL; char *pDest = static_cast <char*>(dest); const char *pSrc = static_cast <const char*>(src); if (pDest > pSrc && pDest < pSrc+n) { for (size_t i=n-1; i != -1; --i) { pDest[i] = pSrc[i]; } } else { for (size_t i= 0; i < n; i++) { pDest[i] = pSrc[i]; } } return dest;}int main(){ people stPeople1, stPeople2; memset((void*)&stPeople1, 0x00, sizeof(stPeople1)); memset((void*)&stPeople2, 0x00, sizeof(stPeople2)); stPeople1.iAge = 32; mymemcpy(stPeople1.szName, "li lei", sizeof(stPeople1.szName)); mymemcpy(stPeople1.szSex, "man", sizeof(stPeople1.szSex)); mymemcpy((void*)&stPeople2, (void*)&stPeople1, sizeof(stPeople2)); printf("this people age is %d, name is %s, sex is %s\n", stPeople2.iAge, stPeople2.szName, stPeople2.szSex); return 0;}咱们看mymemcpy的实现,此时是一个字节的实现,但它与strncpy实现不能一样,看一下memcpy实现的留神点: ...

May 26, 2021 · 2 min · jiezi

关于c++:C内存管理12G49-pool-allocator-观察

前提阐明留神比照 G2.9 #207 和 G4.9 #97 行, 新版本中,应用 ::operator new 进行内存申请,意味着咱们能够对其进行重载后做一些察看统计 G2.9 chunk_alloc 的实现留神:start_free = (char *)malloc(bytes_to_get); template <bool threads, int inst>char *default_alloc_template<threads, inst>::chunk_alloc(size_t size, int &nobjs){ char *result; size_t total_bytes = size * nobjs; size_t bytes_left = end_free - start_free; if (bytes_left > total_bytes) { result = start_free; start_free += total_bytes; return result; } else if (bytes_left >= size) { nobjs = bytes_left / size; total_bytes = size * nobjs; result = start_free; start_free += total_bytes; return result; } else { size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); if (bytes_left > 0) { obj **my_free_list = free_list + FREELIST_INDEX(bytes_left); ((obj*)start_free)->free_list_link = *my_free_list; *my_free_list = (obj*)start_free; } start_free = (char *)malloc(bytes_to_get); if (0 == start_free) { int i; obj **my_free_list; obj *p; for (i=size+__ALIGN; i<=__MAX_BYTES; i+=__ALIGN) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (0 != p) { *my_free_list = p->free_list_link; start_free = (char*)p; end_free = start_free + i; return chunk_alloc(size, nobjs); } } } heap_size += bytes_to_get; end_free = start_free + bytes_to_get; return chunk_alloc(size, nobjs); }}G4.9 chunk_alloc 的实现留神:_S_start_free = static_cast<char*>(::operator new(__bytes_to_get)); ...

May 24, 2021 · 9 min · jiezi

关于c++:C内存管理11G29-stdalloc-概念大整理

概念大整顿 补充阐明list 节点向分配器申请的内存大小: sizeof(Foo) + sizeof(node<Foo>*) x 2批斗大会 学习应用: "常量 == 变量" 格局, 当漏泄等号时编译器会收回编译谬误提醒注:较新的编译器在 "常量 = 变量" 时通常也会收回编译正告 不举荐应用:对象的定义与应用不应距离太远,而应做到尽量靠近(距离中途可能被批改,尤其是指针时) 不举荐应用:可读性不高,应该尽量分行书写 不举荐应用:可读性不高模式雷同 : 在同一个多过程的零碎中,竭泽而渔会对其它过程产生灾难性影响对应到前一章最初的纳闷问题 2 : system heap 手中还剩多少资源? 10000 - 9688 = 312.可不可以将失败的那次索取折半...再折半...再折半...最终当索取量 <= 312 便能失去满足 缺点:内存未偿还零碎应用 malloc 在操作系统中进行内存申请,申请的内存会携带 cookie 进行标记,以辅助后续 free 进行内存开释在下图可见, 标注的起始内存块已不被自在链表治理,同时也无奈确定对应 cookie 的内存块都间断闲暇

May 22, 2021 · 1 min · jiezi

关于c++:QT5写Tetris之AI机器人玩游戏

背景应用Qt5.12.9的QGraphicsItem来实现俄罗斯方块,应用简略的评估函数,实现AI机器人玩俄罗斯方块游戏。这是AI机器人的第一步,这个算法很简略,但很无效,大多数状况能消5百层以上,最近的为数不多的测试中,最高纪录曾经消了超过2500层。在这个根底上,能够不便的积攒原始数据,我心愿能抽取模式,进行模式识别及至机器学习。 思路在手动游戏根底上进行革新,借鉴回放的教训,只须要退出一个评估算法,为每一个新方块找出一个搁置的姿势(旋转次数)和最终地位坐标就能够了。我的算法设计也很简略,就是为每一个方块穷举其搁置办法,应用一个严密水平的评估算法进行评分,取出最高分的操作,若有雷同得分的操作,用随机数二一添做五。 效果图 要害代码剖析流程管制界面操作控制变量,做到随时能够在手动与主动两种模式之间进行切换。 if (isAutoRunning) { //主动模式 autoProcessCurBlock(); //解决以后方块,应用评估函数确定方块的最终姿势与地位 block->relocate(curPos); //搁置 block->setBlockNotActive(); //固定方块 generateNextBlock(); //取下一个方块,游戏持续 }else //手动模式 this->moveBlockDown(); ...方块搁置评分函数我的设计思维很直观,俄罗斯方块就是要尽量严密的沉积在一起,所以对每一个组成方块的block都检测一个它四周的四个地位,看是否有block(包含边界)存在,若有就加1分,没有不加分。这块的加分,并没有区别组成方块本身的block和外界的block,因为每个方块都是与本人进行比拟,所以辨别与不辨别成果是一样的。起始分由深度确定,越深我认为成果越好。另个,block的垂直下方最好不要有空洞,若有会减分。 int Game::evaluate(Tetris* t){ QPoint pos = t->getPos(); int ct = pos.y(); //深度为根底分 int cct = t->cleanCount(); if (cct > 1) //能消层,加分 ct += 10 * (cct - 1); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (t->data[i][j]) { ct += t->hasTetrisBlock(pos.x() + j + 1, pos.y() + i) ? 1 : 0; //检测block左边的地位 ct += t->hasTetrisBlock(pos.x() + j - 1, pos.y() + i) ? 1 : 0; //检测block右边的地位 ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1) ? 1 : 0; //检测block下方的地位 ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i - 1) ? 1 : 0; //检测block上方的地位 if (i == 3 || t->data[i + 1][j] == 0) { if (!t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1)) { //block下方的紧临空洞 ct -= 4; } else { int k = 2; while (pos.y() + i + k <= 19) { if (!t->hasTetrisBlock(pos.x(), pos.y() + i + k)) { //block下方的非紧临空洞 ct -= 1; break; } k++; } } } } } } return ct;}穷举方块的所有搁置形式一个方块最多只有四种姿势,把方块的每一种姿势都从左到右moveDownEnd一次,进行评分,获得分最高的计划。 ...

May 22, 2021 · 2 min · jiezi

关于c++:C内存管理10G29-stdalloc-源码刨析

std::alloc 分两级层进行内存治理,第一级在接下来的学习中是主要的,次要内容都集中在第二级里。在 G4.9 版本中,第一级已被删除G2.9 中的一级内存治理 补充阐明class semple_alloc :应用层内存调配的根本单位是元素个数[ n] ,但底层实现中二级调配的单位是字节,此处便实现元素个数到字节数的转换[ n * sizeof(T) ]G2.9 中的二级内存治理【重点】片段一 补充阐明图片中仅保留了内存调配中最原汁原味的局部,其它内容已被剔除不便学习 bool threads, int inst 仅保留接口,实现中已剔除实现中全副的成员函数和成员变量都是动态的,因而非常容易扩大为 C 版本ROUND_UP : 将参数值“上调”整为 8 的倍数(计算内存申请追加量会应用)union obj *free_list_link : 嵌入式指针,连贯可用内存块volatile : 多线程时应用,此处可暂疏忽free_list[_NFREELISTS] : 蕴含 16 个元素,每个元素都是指针,指向自在链表FREELIST_INDEX : 依据所用内存大小计算对应自在链表下标值(“上调”到8的倍数对应的下标值)refill : 当自在链表为空时调用start_free、end_free : 指向战备池heap_size : 调配累计总量(关系到追加量)片段二 补充阐明deallocate :当内存块小于 128 字节时,内存再无奈归还给操作系统(free),自在链表将增长至顶峰内存偿还难以实现:存在多条自在连链表且链表可能会很长,链表中的内存块通过调配、偿还,已无奈高效的去判断链表中的哪些内存块是地址上是间断的(cookie)此种实现不算内存泄露,或者称之为”王道“。会影响多任务零碎中的其它过程if (n > (size_t)__MAX_BYTES) : 超过 128 字节时应用一级内存治理(malloc、free)片段三 for(i=1; ;++i) : 循环从 1 开始,因为第 0 个内存块返回给了客户应用片段三 ...

May 22, 2021 · 1 min · jiezi

关于c++:QT5写Tetris之使用Sqlite3实现游戏回放

背景应用Qt5.12.9的QGraphicsItem来实现俄罗斯方块,应用Sqlit3存储数据来进行游戏的回放,既然曾经应用QT,就尽量用其组件,重写了原来的JSON封装及数据库操作接口实现。 思路尽量复用曾经实现的代码,所以只记录了每个方块的形态与姿势(旋转次数)及最终地位。与实在游戏的区别只是在于方块的起源一个是随机生成,一个是数据库。记录的ID我援用了原来应用的snowflake模型,但却应用了QString类型,无它,只是长整型在编程的过程中总是不好管制,莫名的被改成迷信计数法或溢出。数据库操作应用C++对sqlit3库进行封装并联合Qjson实现ORM主动操作。Sqlit3的动态链接库,在windows、linux、mac各平台下须要从新编译。 效果图 要害代码剖析cmake之操作系统抉择if(MSVC) #windows set(EnclibName Sqlit3.dll)elseif(APPLE) #mac set(EnclibName sqlite3.o)elseif(UNIX) #linux set(EnclibName libsqlite3.so)endif()Qjson.h - json操作封装我的数据操作实现中的信息传递,都是以json对象模式进行的,封装QJsonObject、QJsonArray等,提供方便的json操作接口,实现参数传递与SQL主动生成。我的实现Object是一等公民,Array是二等公民只作为Qjson的一个子项。这样既能满足利用又把设计大大的简化了,标准应用,防止误用。 class Qjson {private: QJsonObject* json; //实在的json对象,我只是对其封装,简化操作或转化成简略的操作 bool _IsObject_; //是否是正确的json对象,构造函数中对其进行判断,示意json对象的有效性public: Qjson(); Qjson(const Qjson& origin); //复制构造函数 QString operator[](QString key); //下标操作,取特定key对应的值,应用QString返回,能够不便进行类型转换 Qjson& operator = (const Qjson& origin); //赋值构造函数 bool HasMember(QString key) ; Qjson ExtendObject(Qjson obj); //合并两个Object,第一个中同名key会被笼罩 template<typename T> void AddValueBase(QString k, T v); //key - value 插入模板函数,根底类型插入它就能搞定 void AddValueObjectsArray(string k, QVector<Qjson>& arr) ; //Array类型值插入 QString GetJsonString(); //获得json的字符串 void GetValueAndTypeByKey(QString key, QString* v, int* vType); //取值的真正操作函数 QStringList GetAllKeys(); //获得json对象的所有key,用于对象遍历 bool IsObject();private: QJsonObject* GetOriginRapidJson(); //获得实在的json对象,类外部应用};数据库通用接口 - Idb.h经实际总结,数据库操作有以下接口,百分之九十以上的需要就都能满足。 ...

May 22, 2021 · 2 min · jiezi

关于c++:C内存管理9stdalloc-运行模式详解

从以下间断步骤中,咱们能够理解到 alloc 工作时的根本流程。其中蕴含战备池、自在链表每次最多新增20个区块、追加量、碎片解决、内存不足时的解决等概念起始 free_list 数组蕴含16个元素,子元素别离治理不同内存大小的自在链表(单链表)第一次内存申请分配器的客户是容器,即分配器服务于容器应用 malloc 申请的内存大小可能不同,因而须要借助 cookie 记录大小信息以进行后续的内存开释动作容器的所有元素大小已知且统一,因而能够不应用 malloc(不应用 cookie )在 alloc 工作时,总是先把可用内存放到战备池,再从战备池切割适当的内存到 free_list 治理的链表 补充形容容器申请 32 bytes, 因为 pool(战备池)为空,故应用 malloc(蕴含 cookie) 索取内存并胜利向 pool 加注 32 x 20 x 2 + RoundUp(0>>4) = 1280 bytes, 从中切出 1 个区块返回给容器, 19 个区块给 list#3, 残余 640 bytes 备用(战备池)战备池:由 start_free、 end_free 指针形容RoundUp (0>>4) : 追加量,会越来越大RoundUp : 是一个函数,将一个数值(累计申请总量)调整到 16 的边界0 >> 4 : 0(目前的申请总量,首次值 0) / 16无文档可阐明为什么须要应用追加量,且每次追加量值是累计申请量除以16,或者为经验值第二次内存申请 补充形容圆滑连接线示意图中内存块在地址上间断直角连接线示意图中内存块在自在链表中间断第三次内存申请 第四次内存申请 补充形容通过以上操作,代码中曾经创立了 4 种容器,每个容器大小各不相同,由图中的 4 条链表进行别离治理总计应用两次 malloc第五次内存申请 ...

May 22, 2021 · 1 min · jiezi

关于c++:leetcode二叉树遍历的一系列衍生题

二叉树开展为链表题目形容题目链接:https://leetcode-cn.com/probl... 给你二叉树的根结点 root ,请你将它开展为一个单链表: 开展后的单链表应该同样应用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。开展后的单链表应该与二叉树 先序遍历 程序雷同。 后序遍历原地批改法思路:因为程序必须依照先序遍历,为了不便进行结点的记录和左右子树链接的批改,能够用后序遍历的办法,如果用先序遍历,则以后结点的下一结点较难判断,将以后结点传至下一次递归中的做法也很麻烦。而后续遍历中,只需用一个last结点记录以后结点的下一个结点,按后序遍历记录,能够使得代码很清晰。 TreeNode* last = nullptr; void flatten(TreeNode* root) { if(!root)return; flatten(root->right); flatten(root->left); root->right = last; root->left = nullptr; last = root; } 二叉树最大门路和题目形容题目链接:https://leetcode-cn.com/probl...门路 被定义为一条从树中任意节点登程,沿父节点-子节点连贯,达到任意节点的序列。同一个节点在一条门路序列中 至少呈现一次 。该门路 至多蕴含一个 节点,且不肯定通过根节点。 门路和 是门路中各节点值的总和。 给你一个二叉树的根节点 root ,返回其 最大门路和 。 示例1: 输出:root = [1,2,3]输入:6解释:最优门路是 2 -> 1 -> 3 ,门路和为 2 + 1 + 3 = 6 递归法思路二叉树的题,其中一个较惯例的思路就是递归法。尤其是这种算最大最小值的题,非常适合用递归来解决。但这题非凡的一个点在于:门路并不仅限于从根到子节点,而能够从一个节点到另一个节点。初看起来非常复杂,用递归思路又不可行了,但当你画一棵较为简单的树,本人比划比划其中可能的门路时就会发现,事实上可能存在的门路并没有那么多。这题最困扰人的一点就是门路能够从一个节点的左子树走到该结点的右子树,因而使人感觉可能性太多,极难穷举。但本人画过一遍后能够发现,一旦你所画的门路中同时蕴含了一个节点的左子树和右子树及其自身,这条门路就没法回溯到上一层了;如果想要回溯到上一层,就只能是走其中一个子树。看清了这一点,就能够得出一个论断:对于任意一个节点, 如果最大和门路蕴含该节点, 那么只可能是两种状况: 其左右子树中所形成的和门路值较大的那个加上该节点的值后向父节点回溯形成最大门路左右子树都在最大门路中, 加上该节点的值形成了最终的最大门路这样,递归法就很好做了: class Solution {public: int ans = INT_MIN; int countSum(TreeNode* root) { if(!root) return 0; int leftMax = max(countSum(root -> left),0); int rightMax = max(countSum(root -> right),0); ans = max(ans, leftMax+rightMax+root->val); return max(leftMax,rightMax) + root->val; } int maxPathSum(TreeNode* root) { countSum(root); return ans; }};

May 21, 2021 · 1 min · jiezi

关于c++:超详细STL之array容器使用及实现原理解析

阐明一下,我用的是gcc7.1.0编译器,规范库源代码也是这个版本的。本篇文章讲述STL中array的应用及原理。 导读array其实是一个固定大小的数组,元素类型及大小在申明的时候指定,原型如下: template<typename _Tp, std::size_t _Nm> struct array { ... };有些书上说array也是一个class,然而我这个版本看到的是struct,不过没有关系,除了一些轻微的方面,struct和class并无太大的区别,这里能够看到array其实就是一个模板类。 array的初步应用应用array要蕴含头文件<array>,并申明std命名空间才可应用。 如下是一个简略的案例: #include <array>#include <iostream>int main(){ std::array<int,5> a = {1,2,3,4,5}; for(auto i:a) { std::cout << "value is " << i << std::endl; } return 0;}fill()和swap()的应用先看下他们的原型,如下: //fill函数是把以后array外面所有元素都填充为入参__uvoid fill(const value_type& __u);//swap是替换两个array数据void swap(array& __other) noexcept(_AT_Type::_Is_nothrow_swappable::value);看一下应用案例: #include <array>#include <iostream>int main(){ std::array<int,5> arr1; arr1.fill(5); for(auto i:arr1) { std::cout << "arr1 value is " << i << std::endl; } std::array<int,5> arr2 = {1,2,3,4,5}; arr2.swap(arr1); for(auto i:arr1) { std::cout << "arr1 value is " << i << std::endl; } for(auto i:arr2) { std::cout << "arr2 value is " << i << std::endl; } return 0;}这里要留神的一个点是,arr1和arr2的元素类型和大小都必须要完全一致,才能够应用swap函数,因为应用swap的前提就是类型要完全一致,而array容器的类型是包含两个模板参数:元素类型和元素个数,如果不统一,编译时没有方法通过的。 ...

May 21, 2021 · 3 min · jiezi

关于c++:C内存管理8stdalloc-运行模式

概述free_list 链表总计蕴含 [0 - 15] 16个元素,其中每个元素别离对应一条子 单 链表(embedded pointers 组织治理)每条子链表别离对应治理多个内存块(内存块大小从8字节到128字节)。如,其中free_list[0]治理8字节链表,之后子链表治理的空间大小顺次减少 8 字节当使用者申请内存空间不是8的整数倍时,大小会被调整为8的整数倍再用对应的子链表进行治理当使用者申请内存大于128字节时,调用 malloc 进行治理内存调配(malloc 意味着 cookie)示例详解 第一次申请客户申请30字节空间,std::alloc调整8字节对齐到32字节,对应 free_list[3] 子链表free_list[3] 为空,未指向可用内存块节点,调用 malloc 进行大的内存块申请(蕴含 cookie) malloc 申请时失去的内存空间:20 x 32 字节内存块 + 20 x 32 字节备用内存块(20数量内存块可能为经验值,由embedded pointers 组织成单链表)将申请失去的第一个小内存块交给客户进行应用第二次申请客户申请72字节空间,atd::alloc 在 free_list[3] 中找到前次申请的 20 x 32 字节备用空间可用,此空间被从新72字节宰割,将第一块传给客户应用第三次申请客户申请96字节空间,std::alloc 查看 free_list 无备用内存可用,于是为 free_list[11] 子链表调用 malloc 进行大的内存块申请【20 x 96 + 20 x 96(对应图中 memory pool)】,将第一块内存块传给客户应用内存回收依据回收的内存大小,从新挂载到对应的子链表上(embedded pointers 组织治理)embedded pointers下图对应上图某一子链表 union obj { union obj *free_list_link; char client_data[1]; // 源码中并未应用 client_data, 可疏忽了解}嵌入式指针,借用内存块前 4 个字节治理可用内存造成单链表【无需占用额定空间,间接阐明obj必须 ≥ 4 字节(地址宽度)以用来被指针借用】容器每次动态分配失去的是一个指针,并不知道此内存是否都带有 cookie(即外部的内存治理形式并不影响客户的应用)

May 20, 2021 · 1 min · jiezi

关于c++:c中lambda表达式用法

阐明一下,我用的是gcc7.1.0编译器,规范库源代码也是这个版本的。本篇文章解说c++11中lambda表达式用法。 首次接触lambda这个关键字,记得还是在python外面,但其实,早在2011年c++11推出来的时候咱们c++就有了这个关键字啦。lambda表达式是C++11中引入的一项新技术,利用lambda表达式能够编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。 所谓函数对象,其实就是对operator()进行重载进而产生的一种行为,比方,咱们能够在类中,重载函数调用运算符(),此时类对象就能够间接相似函数一样,间接应用()来传递参数,这种行为就叫做函数对象,同样的,它也叫做仿函数。 如果从狭义上说,lambda表达式产生的是也是一种函数对象,因为它也是间接应用()来传递参数进行调用的。 1 lambda表达式根本应用lambda表达式根本语法如下: [ 捕捉 ] ( 形参 ) -> ret { 函数体 };lambda表达式个别都是以方括号[]结尾,有参数就应用(),无参就间接省略()即可,最初完结于{},其中的ret示意返回类型。 咱们先看一个简略的例子,定义一个能够输入字符串的lambda表达式,残缺的代码如下: #include <iostream>int main(){ auto atLambda = [] {std::cout << "hello world" << std::endl;}; atLambda(); return 0;}下面定义了一个最简略的lambda表达式,没有参数。如果须要参数,那么就要像函数那样,放在圆括号外面,如果有返回值,返回类型则要放在->前面,也就是尾随返回类型,当然你也能够疏忽返回类型,lambda会帮你主动推导出返回类型,上面看一个较为简单的例子: #include <iostream>int main(){ auto print = [](int s) {std::cout << "value is " << s << std::endl;}; auto lambAdd = [](int a, int b) ->int { return a + b;}; int iSum = lambAdd(10, 11); print(iSum); return 0;}lambAdd有两个入参a和b,而后它的返回类型是int,咱们能够试一下把->int去掉,后果是一样的。 ...

May 20, 2021 · 3 min · jiezi

关于c++:C内存管理7VC6BC5G29-的标准分配器实现

VC6 下的malloc 内存块布局 对应图中自上而下的内存耗费:malloc(0x0c) ==>4 + (4 * 8) + 0x0C + 4 + (2 * 4) + 4 = 0x40VC6 规范分配器的实现VC6 的 allocator 只是以 ::operator new 和 ::operator delete 实现 allocate() 和 deallocate(), 没有任何非凡设计VC6 所附的规范库,其 std::allocator 实现如下(<xmemory>) BC5 规范分配器的实现BC5 的 allocator 只是以 ::operator new 和 ::operator delete 实现 allocate() 和 deallocate(), 没有任何非凡设计 BC5 所附的规范库,其 std::allocator 实现如下(memory.stl) G2.9 规范分配器的实现G2.9 的 allocator 只是以 ::operator new 和 ::operator delete 实现 allocate() 和 deallocate(), 没有任何非凡设计G2.9 所附的规范库,其 std::allocator 实现如下(<defalloc.h>) ...

May 18, 2021 · 1 min · jiezi

关于c++:C内存管理7new-handler

当 operator new 没有能力为调配出咱们所申请的 memory,会抛出一个 std::bad_alloc exception。某些老编译器则是返回 0 ,古代编译器依然能够这样做:new (nothrow) Foo; 抛出 exception 之前会先(不止一次)调用一个可有 client 指定的 handler, 以下是 new handler 的模式和设定办法: typedef void (*new_handler)();new_handler set_new_handler(new_handler p) throw();设计良好的 new_handler 只有两个抉择: 让更多的 memory 可用调用 abort() 或 exit()void *operator_new(size_t size, const std::nothrow_t &_THROW0()){ // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) { // buy more memory or return null pointer _TRY_BEGIN if (_callnew_h(size) == 0) break; _CATCH(std::bad_alloc) return 0; _CATCH_END } return (p);}#include <new>#include <iostream>#include <cassert>using namespace std;void onMoreMemory(){ cerr << "out of memory" << endl; abort();}int main(){ set_new_handler(onMoreMemory); int *p = new int[10000]; assert(p); cout << p << endl; p = new int[100000000000000]; assert(p); cout << p << endl; return 0;}输入[gcc version 7.5.0] ...

May 17, 2021 · 2 min · jiezi

关于c++:C内存管理6static-allocator

上一章实现的两个 allocator 必须为不同的 classes 重写一遍简直雷同的 member operator new 和 member operator delete,应该有办法将一个总是调配特定尺寸块的 memory allocator 概念包装起来,使它容易被重复使用。以下展现一种形式,每个 allocator object 都是个分配器,它保护一个 free-list;不同的 allocator objects 保护不同的 free-list。 #include <iostream>#include <cstdlib>#include <string>#include <complex>using std::string;using std::complex;using std::cout;using std::endl;class allocator{private: struct obj { struct obj *next; // embedded pointer };public: void *allocate(size_t); void deallocate(void*, size_t);private: obj *freeStore = nullptr; const int CHUNK = 5; // 小一些不便察看};// 操作系统会尽量保障每次申请 CHUNK * size 内存时是间断的, 但两次之间无此承诺void *allocator::allocate(size_t size){ obj *p; if (!freeStore) { // linked list 为空,于是申请一大块内存 size_t chunk = CHUNK * size; freeStore = p = static_cast<obj*>(malloc(chunk)); // 将调配得来的一大块当作 linked list 般,小块小块串起来 for (int i=0; i<(CHUNK-1); ++i) { p->next = reinterpret_cast<obj*>((char*)p + size); p = p->next; } } p = freeStore; freeStore = freeStore->next; return p;}void allocator::deallocate(void* p, size_t){ // 将 *p 发出插入 free list 前端 static_cast<obj*>(p)->next = freeStore; freeStore = static_cast<obj*>(p);}//=========================class Foo {public: long L; static allocator myAlloc;public: Foo(long l) : L(l) { } static void *operator new(size_t size) { return myAlloc.allocate(size); } static void operator delete(void *pdead, size_t size) { return myAlloc.deallocate(pdead, size); }};allocator Foo::myAlloc;class Goo {public: complex<double> c; string str; static allocator myAlloc;public: Goo(const complex<double> &x) : c(x) { } static void *operator new(size_t size) { return myAlloc.allocate(size); } static void operator delete(void *pdead, size_t size) { return myAlloc.deallocate(pdead, size); }};allocator Goo::myAlloc;void func_1(){ Foo *p[100]; cout << "sizeof(Foo) = " << sizeof(Foo) << endl; for (size_t i=0; i<23; ++i) { if (i != 0 && i % 5 == 0) cout << endl; p[i] = new Foo(i); cout << p[i] << ' ' << p[i]->L << endl; } for (int i=0; i<23; ++i) delete p[i];}void func_2(){ Goo *p[100]; cout << "sizeof(Foo) = " << sizeof(Goo) << endl; for (size_t i=0; i<17; ++i) { if (i != 0 && i % 5 == 0) cout << endl; p[i] = new Goo(complex<double>(i, i)); cout << p[i] << ' ' << p[i]->c << endl; } for (int i=0; i<17; ++i) delete p[i];}int main(){ func_1(); cout << "============" << endl; func_2(); return 0;}输入:[留神察看每五次输入之间,地址的连续性] ...

May 16, 2021 · 2 min · jiezi

关于c++:C内存管理5Perclass-allocator

自定义内存操作的意义: 升高 malloc 调用次数,进步内存空间利用率(每次 malloc 会携带高低 cookies[8bytes]标记)升高 malloc 调用次数,进步内存治理速度实现一 [ref. C++ Primer 3/e,p.765]#include <cstddef>#include <iostream>using namespace std;class Screen {public: Screen(int x) : i(x) { } int get() { return i; } // 默认 static void *operator new(size_t); // 默认 static void operator delete(void*, size_t);private: Screen *next; // 这种设计会引发多耗用一个 next 的疑虑,下种实现更好 static Screen *freeStore; static const int screenChunk;private: int i;};Screen *Screen::freeStore = 0;const int Screen::screenChunk = 24;void *Screen::operator new(size_t size){ Screen *p; if (!freeStore) { // linked list 是空的,所以申请一大块 size_t chunk = screenChunk * size; freeStore = p = reinterpret_cast<Screen*>(new char[chunk]); // 将一大块宰割,当作 linked_list 串起来 for (; p!= &freeStore[screenChunk-1]; ++p) p->next =p + 1; p->next = 0; } p = freeStore; freeStore = freeStore->next; return p;}// 并为将内存归还给零碎,任由 Screen 接管(不算是内存泄露)void Screen::operator delete(void* p, size_t){ // 讲 deleted object 插回 free list 前端 (static_cast<Screen*>(p))->next = freeStore; freeStore = (static_cast<Screen*>(p));}void func_1(){ cout << "==== " << "Screen::operator new" << " ====" << endl; cout << sizeof(Screen) << endl; size_t const N = 100; Screen *p[N]; for (size_t i=0; i<N; ++i) p[i] = new Screen(i); for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) delete p[i];}void func_2(){ cout << "==== " << "::operator new" << " ====" << endl; cout << sizeof(Screen) << endl; size_t const N = 100; Screen *p[N]; for (size_t i=0; i<N; ++i) p[i] = ::new Screen(i); for (size_t i=0; i<10; ++i) cout << p[i] << endl; for (size_t i=0; i<N; ++i) :: delete p[i];}int main(){ func_1(); func_2(); return 0;}输入:【以下输入证实自定义内存治理进步了空间利用率】 ...

May 16, 2021 · 3 min · jiezi

关于c++:最全面的c中类的构造函数高级使用方法及禁忌

阐明一下,我用的是gcc7.1.0编译器,规范库源代码也是这个版本的。本篇文章解说c++中,构造函数的高级用法以及非凡应用状况。 1. 拷贝结构和挪动结构区别对于拷贝结构和挪动结构,还是看一下这段代码: #include <iostream>#include <string.h>using namespace std;class CPtr{ private: char *m_pData; int m_iSize; public: //without param constructors CPtr() { m_iSize = 1024; m_pData = new char[m_iSize]; } ~CPtr() { if ( m_pData != nullptr ) { delete []m_pData; m_pData = nullptr; } } //with param constructors CPtr(const int p_iSize) { m_iSize = p_iSize; m_pData = new char[p_iSize]; } //copy constructors CPtr(const CPtr& ptr) { if (ptr.m_pData != nullptr) { m_iSize = strlen(ptr.m_pData)+1; m_pData = new char[m_iSize]; strncpy(m_pData, ptr.m_pData, m_iSize-1); } } //move constructors CPtr(CPtr&& ptr) { m_pData = ptr.m_pData; m_iSize = ptr.m_iSize; ptr.m_pData = nullptr; ptr.m_iSize = 0; } //赋值构造函数 CPtr& operator=(const CPtr& ptr) { if (ptr.m_pData != nullptr) { m_iSize = strlen(ptr.m_pData)+1; m_pData = new char[m_iSize]; strncpy(m_pData, ptr.m_pData, m_iSize-1); } return *this; } //挪动赋值构造函数 CPtr& operator=(CPtr&& ptr) { m_pData = ptr.m_pData; m_iSize = ptr.m_iSize; ptr.m_pData = nullptr; ptr.m_iSize = 0; return *this; } void setData(const char* str) { if ( str == nullptr) { cout << "str is nullptr" << endl; return; } if ( m_iSize == 0) { cout << "the memory is nothing" << endl; return; } int iSize = strlen(str); if ( iSize < m_iSize ) { strncpy(m_pData, str, iSize); } else { strncpy(m_pData, str, m_iSize-1); } } void print(const char* object) { cout << object << "'s data is " << m_pData << endl; }};int main(){ CPtr p1(1024); p1.setData("lilei and hanmeimei"); p1.print("p1"); CPtr p2(p1); p2.print("p2"); CPtr p3 = p1; p3.print("p3"); CPtr p4(move(p1)); p4.print("p4"); CPtr p5 = move(p2); p5.print("p5"); return 0;}依据以上代码,咱们能够总结出如下两点: ...

May 14, 2021 · 4 min · jiezi

关于c++:c类的构造函数不显式声明会自动生成吗

阐明一下,我用的是g++7.1.0编译器,规范库源代码也是这个版本的。本篇文章解说c++11中,类的构造函数品种,以及不显式申明的状况下是否会主动生成。 1. 类的构造函数类别在我刚接触c++的时候,我始终晓得类能够有四种模式的构造函数,即无参构造函数、有参构造函数、拷贝构造函数、赋值运算符构造函数,最近看规范IO源代码,发现又多了一种,那就是挪动构造函数,这是c++11中补充进来的,所以当初c++能够领有四种模式的构造函数,即无参构造函数、有参构造函数、拷贝构造函数、赋值构造函数、挪动构造函数、挪动赋值构造函数。 阐明以下:赋值运算符operator=到底算不算构造函数,这个集体有集体的认识,不多探讨,然而单就阐明构造函数的时候把它漏掉的话,我感觉有点耍流氓了,所以也要把它列进来。一个残缺的申明了这六种构造函数以及应用的案例如下: #include <iostream>#include <string.h>using namespace std;class CPtr{ private: char *m_pData; int m_iSize; public: //without param constructors CPtr() { m_iSize = 1024; m_pData = new char[m_iSize]; } ~CPtr() { if ( m_pData != nullptr ) { delete []m_pData; m_pData = nullptr; } } //with param constructors CPtr(const int p_iSize) { m_iSize = p_iSize; m_pData = new char[p_iSize]; } //copy constructors CPtr(const CPtr& ptr) { if (ptr.m_pData != nullptr) { m_iSize = strlen(ptr.m_pData)+1; m_pData = new char[m_iSize]; strncpy(m_pData, ptr.m_pData, m_iSize-1); } } //move constructors CPtr(CPtr&& ptr) { m_pData = ptr.m_pData; m_iSize = ptr.m_iSize; ptr.m_pData = nullptr; ptr.m_iSize = 0; } //赋值构造函数 CPtr& operator=(const CPtr& ptr) { if (ptr.m_pData != nullptr) { m_iSize = strlen(ptr.m_pData)+1; m_pData = new char[m_iSize]; strncpy(m_pData, ptr.m_pData, m_iSize-1); } return *this; } //挪动赋值构造函数 CPtr& operator=(CPtr&& ptr) { m_pData = ptr.m_pData; m_iSize = ptr.m_iSize; ptr.m_pData = nullptr; ptr.m_iSize = 0; return *this; } void setData(const char* str) { if ( str == nullptr) { cout << "str is nullptr" << endl; return; } if ( m_iSize == 0) { cout << "the memory is nothing" << endl; return; } int iSize = strlen(str); if ( iSize < m_iSize ) { strncpy(m_pData, str, iSize); } else { strncpy(m_pData, str, m_iSize-1); } } void print(const char* object) { cout << object << "'s data is " << m_pData << endl; }};int main(){ CPtr p1(1024); p1.setData("lilei and hanmeimei"); p1.print("p1"); CPtr p2(p1); p2.print("p2"); CPtr p3 = p1; p3.print("p3"); CPtr p4(move(p1)); p4.print("p4"); CPtr p5 = move(p2); p5.print("p5"); return 0;}这里move是规范库的一个函数,返回一个右值援用,也就是CPtr &&类型。这里咱们是显示申明了所有的构造函数,接下来看看编译器对于class构造函数的隐式生成规定。 ...

May 13, 2021 · 6 min · jiezi

关于c++:C常见面试题之基本语言

title: C++常见面试题之根本语言categories: [C++]tags:[面试题]date: 2021/05/11 作者:hackett 微信公众号:加班猿 一、根本语言1、基本知识1 说下C++和C的区别C++是面向对象的语言(有重载、继承和多态三种个性,减少了类型平安性能,比方强制类型转换,反对范式编程,比方模板类、函数模板等) C是面向过程的结构化编程语言 2 说一下C++中static关键字的作用动态全局变量: 全局数据区分配内存,程序运行期间始终存在未初始化主动初始化为0申明它的整个文件可见,文件之外不可见动态局部变量: 该对象的申明处时被首次初始化,即当前的函数调用不再进行初始化作用域仍为部分作用域,当定义它的函数或者语句块完结的时候,作用域完结动态函数: 只在申明的文件中可见,不可被其余文件调用其它文件中能够定义雷同名字的函数,不会发生冲突静态数据成员: 静态数据成语在程序中只有一个拷贝,由该类型所有对象共享拜访,只调配一次内存存储在全局数据区,静态数据成员定义时要调配空间,所以不能在类申明中定义动态成员函数: 它为类的全副服务而不是为某一个类的具体对象服务它不具备this指针,无法访问属于类对象的非静态数据成员,也无法访问非动态成员函数3 说一说C++中四种cast转换const_cast 用于将const变量转为非const static_cast 用于各种隐式转换,比方非const转const,void*转指针等, static_cast能用于多态向上转化,如果向下转能胜利然而不平安,后果未知; dynamic_cast 用于动静类型转换。只能用于含有虚函数的类,用于类档次间的向上和向下转化。只能转指针或援用。向下转化时,如果是非法的对于指针返回NULL,对于援用抛异样。要深刻理解外部转换的原理。 向上转换:指的是子类向基类的转换 向下转换:指的是基类向子类的转换 它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否雷同来判断是否可能进行向下转换。 reinterpret_cast 简直什么都能够转,比方将int转指针,可能会出问题,尽量少用; 4 说一下C/C++中指针和援用的区别1.指针有本人的一块空间,而援用只是一个别名; 2.应用sizeof看一个指针的大小是4,而援用则是被援用对象的大小; 3.指针能够被初始化为NULL,而援用必须被初始化且必须是一个已有对象 的援用; 4.作为参数传递时,指针须要被解援用才能够对对象进行操作,而间接对援用的批改都会扭转援用所指向的对象; 5.能够有const指针,然而没有const援用; 6.指针在应用中能够指向其它对象,然而援用只能是一个对象的援用,不能被扭转; 7.指针能够有多级指针(**p),而援用只有一级; 8.指针和援用应用++运算符的意义不一样; 9.如果返回动态内存调配的对象或者内存,必须应用指针,援用可能引起内存泄露。 5 说一下指针和数组的次要区别指针和数组的次要区别如下: 指针数组保留数据的地址保留数据间接拜访数据,首先取得指针的内容,而后将其作为地址,从该地址中提取数据间接拜访数据,通常用于动静的数据结构通常用于固定数目且数据类型雷同的元素通过Malloc分配内存,free开释内存隐式的调配和删除通常指向匿名数据,操作匿名函数本身即为数据名6 说一下野指针是什么?野指针就是指向一个已删除的对象或者未申请拜访受限内存区域的指针。 7 说一下C++中的智能指针share_ptr:申请堆内存初始化为1,应用时+1,开释时-1,为0时堆内存开释 unique_ptr:指向的堆内存空间的援用计数,都只能为 1,放弃所指空间,堆内存空间开释回收 weak_ptr:须要搭配share_ptr应用,指针被开释所指堆内存的援用计数不会-1 8 说一下智能指针有没有内存泄露的状况当两个对象互相应用一个shared_ptr成员变量指向对方,会造成循环援用,使援用计数生效,从而导致内存透露 9 说一下智能指针内存泄露如何解决为了解决循环援用导致的内存透露,引入了weak_ptr弱指针,weak_ptr的构造函数不会批改援用计数的值,从而不会对对象的内存进行治理,其相似一个一般指针,但不指向援用计数的共享内存,然而其能够检测到所治理的对象是否曾经被开释,从而防止非法拜访。 10 说一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数1、将可能会被继承的父类的析构函数设置为虚函数,能够保障当咱们new一个子类,而后应用基类指针指向该子类对象,开释基类指针时能够开释掉子类的空间,避免内存透露。 2、C++默认的析构函数不是虚函数是因为虚函数须要额定的虚函数表和虚表指针,占用额定的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会节约内存。因而C++默认的析构函数不是虚函数,而是只有当须要当作父类时,设置为虚函数。 11 说一下函数指针定义:函数指针是指向函数的指针变量。 用处:调用函数和做函数的参数,比方回调函数。 12 说一下fork函数fork( )会创立一个新的过程,它简直与调用fork( )的过程截然不同 13 说一下C++析构函数的作用1、析构函数与构造函数对应,当对象完结其生命周期,如对象所在的函数已调用结束时,零碎会主动执行析构函数 2、应用的过程中动静的申请了内存,那么最好显示结构析构函数在销毁类之前,开释掉申请的内存空间,防止内存透露 14 说一下动态函数和虚函数的区别动态函数在编译的时候就曾经确定运行机会,虚函数在运行的时候动静绑定。虚函数因为用了虚函数表机制,调用的时候会减少一次内存开销 ...

May 11, 2021 · 2 min · jiezi

关于c++:C面试题收集自程序喵大人

C语言const的作用有哪些,谈一谈你对const的了解?形容char、const char、char const、const char const的区别?指针常量和常量指针有什么区别?static的作用是什么,什么状况下用到static?全局变量与局部变量的区别?宏定义的作用是什么?内存对齐的概念?为什么会有内存对齐?inline 内联函数的特点有哪些?它的优缺点是什么?如何用C 实现 C++ 的面向对象个性(封装、继承、多态)memcpy怎么实现让它效率更高?typedef和define有什么区别?extern有什么作用,extern C有什么作用?如何防止野指针?如何计算构造体长度?sizeof和strlen有什么区别?晓得条件变量吗?条件变量为什么要和锁配合应用?C++根底C语言和C++有什么区别?struct和class有什么区别?extern "C"的作用?函数重载和笼罩有什么区别?谈一谈你对多态的了解,运行时多态的实现原理是什么?对虚函数机制的了解,单继承、多继承、虚继承条件下虚函数表的构造如果虚函数是无效的,那为什么不把所有函数设为虚函数?构造函数能够是虚函数吗?析构函数能够是虚函数吗?面试系列之C++的对象布局【倡议珍藏】什么场景须要用到纯虚函数?纯虚函数的作用是什么?理解RAII吗?介绍一下?RAII妙用之计算函数耗时RAII妙用之ScopeExit类的大小怎么计算?volatile关键字的作用?什么时候须要应用volatile关键字如何实现一个线程池?C++线程池的实现之格局修订版理解各种强制类型转换的原理及应用?指针和援用有什么区别?什么状况下用指针,什么状况下用援用?个别什么状况下会呈现内存透露?怎么用C++在编码层面尽量避免内存透露。unique_ptr如何转换所有权?谈一谈你对面向对象的了解什么场景下应用继承形式,什么场景下应用组合? new和malloc有什么区别?malloc的内存能够用delete开释吗? malloc进去20字节内存,为什么free不须要传入20呢,不会产生内存透露吗? new[]和delete[]肯定要配对应用吗?new[]和delete[]为何要配对应用? C++11新个性你都理解多少?理解auto和decltype吗?一文吃透C++11中auto和decltype知识点 谈一谈你对左值和右值的理解,理解左值援用和右值援用吗? 理解挪动语义和完满转发吗?左值援用、右值援用、挪动语义、完满转发,你晓得的不晓得的都在这里 理解列表初始化吗?学会C++11列表初始化 平时会用到function、bind、lambda吗,都什么场景下会用到?搞定c++11新个性std::function和lambda表达式 对C++11的mutex和RAII lock有过理解吗?c++11新个性之线程相干所有知识点 对C++11的智能指针理解多少,能够本人实现一个智能指针吗?c++11新个性之智能指针 源码剖析shared_ptr实现之修订版 enum 和 enum class有什么区别? STLC++间接应用数组好还是应用std::array好?std::array是怎么实现的?std::vector最大的特点是什么?它的外部是怎么实现的?resize和reserve的区别是什么?clear是怎么实现的? deque的底层数据结构是什么?它的外部是怎么实现的? map和unordered_map有什么区别?别离在什么场景下应用? list的应用场景?std::find能够传入list对应的迭代器吗? string的罕用函数 设计模式别离写出饿汉和懒汉线程平安的单例模式说出观察者模式类关系和长处说出代理模式类关系和长处说出工厂模式概念和长处说出结构者模式概念说出适配器模式概念 操作系统过程和线程的区别?深度好文|面试官:过程和线程,我只问这19个问题操作系统是怎么进行过程治理的?操作系统是如何做到过程阻塞的?过程之间的通信形式有哪些?什么是上下文切换,操作系统是怎么做的上下文切换?线程是如何实现的?线程之间公有和共享的资源有哪些?个别应用程序内存空间的堆和栈的区别是什么?过程虚拟空间是怎么布局的?10张图22段代码,万字长文带你搞懂虚拟内存模型和malloc外部原理虚拟内存是如何映射到物理内存的?理解分页内存治理吗?操作系统内存治理,你能答复这8个问题吗?产生死锁的必要条件有哪些?如何防止死锁?什么是大端字节,什么是小端字节?如何转换字节序?信号和信号量的区别是什么?锁的性能开销,锁的实现原理?理解CPU的Cache吗?如何写一个高效的多维矩阵乘法?如何利用CPU Cache写出高性能代码,看这些图就够了! 编译原理gcc hello.c 这行命令具体的执行过程,外部到底做了什么?gcc a.c 到底经验了什么?程序肯定会从main函数开始运行吗?如何确定某个函数有被编译输入?动态链接库和动态链接库的区别是什么?Linux 为什么要动静链接?与动态链接的区别是什么?

May 11, 2021 · 1 min · jiezi

关于c++:C-STL-set插入数据

一、办法1、insert1)间接将键的值插入set容器格局阐明pair<iterator,bool> insert (const value_type& val);一般援用形式传参pair<iterator,bool> insert (value_type&& val);右值援用形式传参以上 2 种语法格局的 insert() 办法,返回的都是 pair 类型的值,其蕴含 2 个数据,一个迭代器和一个 bool 值: 当向 set 容器增加元素胜利时,该迭代器指向 set 容器新增加的元素,bool 类型的值为 true; 如果增加失败,即证实原 set 容器中已存有雷同的元素,此时返回的迭代器就指向容器中雷同的此元素,同时 bool 类型的值为 false。 std::set<std::string> myset1;//格局1pair<set<std::string>::iterator, bool> ret;string str = "i am lin";ret = myset1.insert(str);cout << "one iter->" << *(ret.first) << " , " << "bool = " << ret.second << endl;//格局2ret = myset1.insert("i am huang");cout << "two iter->" << *(ret.first) << " , " << "bool = " << ret.second << endl;//插入失败ret = myset1.insert("i am huang");cout << "failed iter->" << *(ret.first) << " , " << "bool = " << ret.second << endl;std::cout << "myset1 size: " << myset1.size() << std::endl;std::set<std::string>::iterator setIter = myset1.begin();for (; setIter != myset1.end(); setIter++){ std::cout << "myset1 :" << *setIter << std::endl;}后果如下: ...

May 10, 2021 · 3 min · jiezi

关于c++:c-STL-set容器迭代器

一、前言set 容器类模板中未提供 at() 成员函数,也未对 [] 运算符进行重载。C++ STL 规范库为 set 容器配置的迭代器类型为双向迭代器,则set容器的迭代器反对++p、p++、--p、p--、*p 操作,并且 2 个双向迭代器之间做比拟,只能应用 == 或者 != 运算符。 1、迭代器办法办法性能begin()返回指向容器中第一个(留神,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器end()返回指向容器最初一个元素(留神,是已排好序的最初一个)所在位置后一个地位的双向迭代器,通常和 begin() 联合应用。如果 set 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器rbegin()返回指向最初一个(留神,是已排好序的最初一个)元素的反向双向迭代器。如果 set 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器rend()返回指向第一个(留神,是已排好序的第一个)元素所在位置前一个地位的反向双向迭代器。通常和 rbegin() 联合应用。如果 set 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器cbegin()和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值cend()和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值crbegin()和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值crend()和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的元素值find(val)在 set 容器中查找值为 val 的元素,如果胜利找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 办法一样的迭代器。另外,如果 set 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器lower_bound(val)返回一个指向以后 set 容器中第一个大于或等于 val 的元素的双向迭代器。如果 set 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器upper_bound(val)返回一个指向以后 set 容器中第一个大于 val 的元素的迭代器。如果 set 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器equal_range(val)该办法返回一个 pair 对象(蕴含 2 个双向迭代器),其中 pair.first 和 lower_bound() 办法的返回值等价,pair.second 和 upper_bound() 办法的返回值等价。也就是说,该办法将返回一个范畴,该范畴中蕴含的值为 val 的元素(set 容器中各个元素是惟一的,因而该范畴最多蕴含一个元素)以上成员函数返回的迭代器,指向的只是 set 容器中存储的元素,而不再是键值对。以上成员办法返回的迭代器,无论是 const 类型还是非 const 类型,都不能用于批改 set 容器中的值。begin和end办法在这里不再阐明。equal_range(val) 函数的返回值是一个 pair 类型数据,其蕴含 2 个迭代器,示意 set 容器中和指定参数 val 相等的元素所在的区域,但因为 set 容器中存储的元素各不相等,因而该函数返回的这 2 个迭代器所示意的范畴中,最多只会蕴含 1 个元素。 ...

May 10, 2021 · 2 min · jiezi

关于c++:C-STL-set容器

一、前言和 map、multimap 容器不同,应用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等。如下: {<'a', 'a'>, <'b', 'b'>, <'c', 'c'>}不反对存储键和值不相等的键值对。因而在应用set容器时,只须要为其提供各键值对中的value值即可。set容器和map容器一样,会自行依据键的大小对存储的键值对进行排序,在set容器中,实际上也是依据value值进行排序。set 容器存储的各个元素的值必须各不相同。须要留神的是:在语法上set容器并没有强制对存储元素的类型做const润饰,因而set容器中存储的元素的值是能够批改的。然而,C++ 规范为了避免用户批改容器中元素的值,对所有可能会实现此操作的行为做了限度,使得在失常状况下,用户是无奈做到批改 set 容器中元素的值的。留神:间接批改set容器中的已存储的元素的值,可能会毁坏set容器中元素的有序性。最正确的批改 set 容器中元素值的做法是:先删除该元素,而后再增加一个批改后的元素。应用set容器,须要 #include <set>1、set容器类模板的定义template < class T, // 键 key 和值 value 的类型 class Compare = less<T>, // 指定 set 容器外部的排序规定 class Alloc = allocator<T> // 指定分配器对象的类型 > class set;因为键和值的类型是一样的,因而这里只有3个参数,大多数状况下,主须要用到其中的前2个参数。 二、创立set容器的办法常见的创立 set 容器的办法,大抵有以下 5 种。 ①std::set<std::string> myset;②std::set<std::string> myset{"1","2","3"};③std::set<std::string> copyset(myset);④std::set<std::string> myset{"1","2","3"};std::set<std::string> copyset(++myset.begin(), myset.end());⑤std::set<std::string,std::greater<string> > myset{"1","2","3"};①默认构造函数,创立空的set容器,会对存储的 string 类型元素做升序排序②在创立 set 容器的同时,对其进行初始化③通过拷贝(复制)构造函数,实现在创立新 set 容器的同时,将已有 set 容器中存储的所有元素全副复制到新 set 容器中,等价于std::set<std::string> copyset = myset;C++ 11 规范还为 set 类模板新增了挪动构造函数,其性能是实现创立新 set 容器的同时,利用长期的 set 容器为其初始化,如下: ...

May 10, 2021 · 2 min · jiezi

关于c++:C-STL中的Binary-search二分查找

左闭右开写法查找某个元素是否呈现。int binarySearch(vector<int>& nums, int target){ int left = 0; int right= nums.size(); int mid = 0; //[left, mid) mid [mid+1, right) while(left< right) { mid = (right - left) / 2 + left; if(nums[mid] == target) return mid; if(nums[mid] < target) left = mid + 1; if(nums[mid] > target) right = mid; } return -1; //未找到target}查找第一个大于或等于某个元素的地位int lowerBound(vector<int> &nums, int target) { int left = 0; int right = nums.size(); int mid = 0; while(left < right) { mid = (right - left) / 2 + left; if (nums[mid] >= target) { right = mid; } else { left = mid + 1; } } return left;}查找第一个大于某个元素的地位。int upperBound(vector<int> &nums, int target) { int left = 0; int right = nums.size(); int mid = 0; while(left < right) { mid = (right - left) / 2 + left; if (nums[mid] > target) { right = mid; } else { left = mid + 1; } } return left;}

May 10, 2021 · 1 min · jiezi

关于c++:探究一下c标准IO的底层实现

阐明一下,我用的是g++7.1.0编译器,规范库源代码也是这个版本的。本篇文章解说c++规范IO的底层实现构造,以及cin和cout的具体实现。 在看本文之前,倡议先看一下之前的一篇文章,至多要晓得规范IO外面各个类之间的关系: c++规范输入输出流关系梳理 1. 规范IO的底层构造通过通读c++规范IO的源代码,我总结出了它的底层实现构造,如图: 它分为三层构造:外部设备、缓冲区、程序,阐明如下: 外部设备是指键盘、屏幕、文件等物理或者逻辑设备;缓冲区是指在数据没有同步到外部设备之前,存放数据的一块内存;程序就是咱们代码生成的过程了。上面咱们首先以输入一个字符为例来看一下它的实现过程,这个过程是由ostream::put函数实现,上面就探索一下put函数的具体实现。 1.1 先探探底层实现的底小贴士:tcc是指template cc,cc是c++实现文件的后缀,加上t示意是模板的实现,所以tcc就是一个模板的实现文件,用于跟其余非模板的实现文件辨别开来。在ostream.tcc中找到put函数的实现代码: template<typename _CharT, typename _Traits> basic_ostream<_CharT, _Traits>& basic_ostream<_CharT, _Traits>:: put(char_type __c) { sentry __cerb(*this); if (__cerb) { ios_base::iostate __err = ios_base::goodbit; __try { const int_type __put = this->rdbuf()->sputc(__c); if (traits_type::eq_int_type(__put, traits_type::eof())) __err |= ios_base::badbit; } __catch(__cxxabiv1::__forced_unwind&) { this->_M_setstate(ios_base::badbit); __throw_exception_again; } __catch(...) { this->_M_setstate(ios_base::badbit); } if (__err) this->setstate(__err); } return *this; }以输入一个字符为例,put函数是调用了缓冲区基类basic_streambuf的sputc成员函数,而sputc成员函数实现如下: int_type sputc(char_type __c) { int_type __ret; //pptr返回一个指向缓冲区下一地位的指针,epptr返回一个指向缓冲区完结地位的指针 if (__builtin_expect(this->pptr() < this->epptr(), true)) { *this->pptr() = __c; //pbump是把缓冲区下一地位加1 this->pbump(1); __ret = traits_type::to_int_type(__c); } else //overflow会进行缓冲区溢出解决 __ret = this->overflow(traits_type::to_int_type(__c)); return __ret; }那么这样看来sputc函数的作用就很显著了,它有两个分支: ...

May 10, 2021 · 2 min · jiezi

关于c++:C-STL-multimap容器

一、前言multimap容器和map容器根本相似,在这里只阐明map容器没有的内容,或者与map容器的区别。和 map 容器的区别在于:multimap 容器中能够同时存储多(≥2)个键雷同的键值对。 二、办法和 map 容器相比,multimap 未提供 at() 成员办法,也没有重载 [] 运算符。因而这里说一下multimap容器获取值的办法。 1、获取值1)办法1std::multimap<int, string> multimap{ {1,"lin"},{1,"wen"},{1, "kai"},{2,"li"},{2,"wu"},{3,"huang"} }; int nCount = multimap.count(1);std::cout << "nCount: " << nCount << std::endl;std::multimap<int, string>::iterator mtmapIter = multimap.begin();for (int i = 0; i < nCount; i++){ std::cout << mtmapIter->first << " " << mtmapIter->second << std::endl; ++mtmapIter;}2)办法2std::multimap<int, string> multimap{ {1,"lin"},{1,"wen"},{1, "kai"},{2,"li"},{2,"wu"},{3,"huang"} }; int nCount = multimap.count(1);std::cout << "nCount: " << nCount << std::endl;std::multimap<int, string>::iterator mtmapBeginIter = multimap.lower_bound(1);for (; mtmapBeginIter != multimap.upper_bound(1); mtmapBeginIter++){ std::cout << mtmapBeginIter->first << " " << mtmapBeginIter->second << std::endl;}3)办法3std::multimap<int, string> multimap{ {1,"lin"},{1,"wen"},{1, "kai"},{2,"li"},{2,"wu"},{3,"huang"} }; int nCount = multimap.count(1);std::cout << "nCount: " << nCount << std::endl;pair<std::multimap<int, string>::iterator, std::multimap<int, string>::iterator> iter = multimap.equal_range(1);for (; iter.first != iter.second; iter.first++){ std::cout << iter.first->first << " " << iter.first->second << std::endl;}后果如下: ...

May 8, 2021 · 1 min · jiezi

关于c++:C-STL-map插入数据

一、前言后面曾经说过,能够通过[]运算符批改或者增加键值对,在这里就不说这种用法了。 二、办法1、insertinsert办法是专门用来向 map 容器中插入新的键值对的。这里的"插入"指的是 insert() 办法能够将新的键值对插入到 map 容器中的指定地位。如果毁坏了map容器的有序性,map容器会对新键值对的地位进行调整,也就是说,尽管insert能够将键值对插入指定的地位,然而插入之后map容器会查看插入的键值对是否合乎有序性,不合乎的话insert指定的地位就不是插入键值对真正的地位了。 1)不指定地位,直接插入格局阐明pair<iterator,bool> insert (const value_type& val);援用传递一个键值对template <class P> pair<iterator,bool> insert (P&& val);以右值援用的形式传递键值对区别:传递参数的形式不同。无论是部分定义的键值对变量还是全局定义的键值对变量,都采纳一般援用传递的形式;而对于长期的键值对变量,则以右值援用的形式传参。 std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };//格局1std::pair<int, string> mapData = { 4, "wu" };std::pair<std::map<int, string>::iterator, bool> ret;ret = mapInfo.insert(mapData);std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;//格局2ret = mapInfo.insert({ 5,"ouyang" });//等价于//ret = mapInfo.insert(pair<int, string>{5, "ouyang"});//ret = mapInfo.insert(make_pair(5, "ouyang"));std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl;//插入失败ret = mapInfo.insert({ 1,"lu" });std::cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << std::endl; std::map<int, string>::iterator mapIter = mapInfo.begin();for (; mapIter != mapInfo.end(); mapIter++){ std::cout << mapIter->first << " " << mapIter->second << std::endl;} 后果如下:由后果可知:①返回值是一个 pair 对象,其中 pair.first 示意一个迭代器,pair.second 为一个 bool 类型变量: 如果胜利插入 val,则该迭代器指向新插入的 val,bool 值为 true; 如果插入 val 失败,则表明以后 map 容器中存有和 val 的键雷同的键值对(用 p 示意),此时返回的迭代器指向 p,bool 值为 false。 ...

May 8, 2021 · 3 min · jiezi

关于c++:C-STL-map获取键对应的值

一、办法1、通过[]获取相似于拜访数组元素的形式。 std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };string strData = mapInfo[1]; std::cout << "strData: " << strData << std::endl;后果如下:留神:1)只有当 map 容器中的确存有蕴含该指定键的键值对,借助重载的 [ ] 运算符能力胜利获取该键对应的值2)若以后 map 容器中没有蕴含该指定键的键值对,则此时应用 [ ] 运算符将不再是拜访容器中的元素,而变成了向该 map 容器中削减一个键值对 std::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };mapInfo[5] = "li";std::map<int, string>::iterator mapIter = mapInfo.begin();for (; mapIter != mapInfo.end(); mapIter++){ std::cout << "key: " << mapIter->first << " value: " << mapIter->second << std::endl;}后果如下: 3)其中,该键值对的键用 [ ] 运算符中指定的键,其对应的值取决于 map 容器规定键值对中值的数据类型,如果是根本数据类型,则值为 0;如果是 string 类型,其值为 "",即空字符串(即应用该类型的默认值作为键值对的值)4)[]具备增加新的键值对的前提是:以后map容器中不存在新增加的键5)如map容器中已存在对应键,执行map[key] = value是批改键key的值,而不是为 map 容器增加新键值对 ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-map迭代器

一、前言stl规范库为map容器装备的是双向迭代器(bidirectional iterator),因而map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭代器之间只能应用 == 或者 != 运算符进行比拟。 二、迭代器办法办法性能begin()返回指向容器中第一个(留神,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器end()返回指向容器最初一个元素(留神,是已排好序的最初一个)所在位置后一个地位的双向迭代器,通常和 begin() 联合应用。如果 map 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器rbegin()返回指向最初一个(留神,是已排好序的最初一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器rend()返回指向第一个(留神,是已排好序的第一个)元素所在位置前一个地位的反向双向迭代器。如果 map 容器用 const 限定,则该办法返回的是 const 类型的反向双向迭代器cbegin()和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的键值对cend()和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的键值对crbegin()和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的键值对crend()和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改容器内存储的键值对。这个的具体性能不再阐明,和序列化容器是一样的性能,惟一不同的就是这里的数据是“键值对”。对于迭代器的应用,曾经有很多的实例,这里就不再阐明了。

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-map容器

一、前言在应用 map 容器存储多个键值对时,该容器会主动依据各键值对的键的大小,依照既定的规定进行排序。默认状况下,会依据键的大小对所有键值对做升序排序。留神点:应用 map 容器存储的各个键值对,键的值既不能反复也不能被批改,即键的类型会用 const 润饰,且是一对一的关系。应用map容器应蕴含头文件: #include <map>using namespace std; //不是必须的1、map容器的模板定义template < class Key, // 指定键(key)的类型 class T, // 指定值(value)的类型 class Compare = less<Key>, // 指定排序规定 class Alloc = allocator<pair<const Key,T> > // 指定分配器对象的类型 > class map;尽管map的模板有4个参数,然而大多数状况下只须要设置前2个参数即可。 二、创立map容器办法①std::map<std::string, std::string> myMap;②std::map<std::string, std::string> myMap{ {"1","lin"},{"2","wei"} };③std::map<std::string, std::string> newMap(myMap);④std::map<std::string, std::string> newMap(myMap.begin(), myMap.end());⑤std::map<std::string, std::string, std::less<std::string> > myMap{ {"1","lin"},{"2","wei"} };三、map容器办法此处不列举迭代器、插入和删除相干办法 办法性能find(key)在 map 容器中查找键为 key 的键值对,如果胜利找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 办法一样的迭代器。另外,如果 map 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器lower_bound(key)返回一个指向以后 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器upper_bound(key)返回一个指向以后 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该办法返回的是 const 类型的双向迭代器equal_range(key)该办法返回一个 pair 对象(蕴含 2 个双向迭代器),其中 pair.first 和 lower_bound() 办法的返回值等价,pair.second 和 upper_bound() 办法的返回值等价。也就是说,该办法将返回一个范畴,该范畴中蕴含的键为 key 的键值对(map 容器键值对惟一,因而该范畴最多蕴含一个键值对)empty()若容器为空,则返回 true;否则 falsesize()返回以后 map 容器中存有键值对的个数max_size()返回 map 容器所能包容键值对的最大个数,不同的操作系统,其返回值亦不雷同operator[]map容器重载了 [] 运算符,只有晓得 map 容器中某个键值对的键的值,就能够向获取数组中元素那样,通过键间接获取对应的值at(key)找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异样count(key)在以后 map 容器中,查找键为 key 的键值对的个数并返回。留神,因为 map 容器中各键值对的键的值是惟一的,因而该函数的返回值最大为 1四、实例1、lower_bound、upper_bound和equal_rangestd::map<int, string> mapInfo{ {1,"test"},{2,"lin"},{3,"wei"} };std::map<int, string>::iterator mapIter = mapInfo.lower_bound(1);std::cout << "lower_bound key: " << mapIter->first << " value: " << mapIter->second << std::endl;mapIter = mapInfo.upper_bound(1);std::cout << "upper_bound key: " << mapIter->first << " value: " << mapIter->second << std::endl;pair<map<int, string>::iterator, map<int, string>::iterator> iters = mapInfo.equal_range(3);std::map<int, string>::iterator beginIter, endIter;beginIter = iters.first;endIter = iters.second;for (beginIter; beginIter != endIter; beginIter++){ std::cout << "equal_range key: " << beginIter->first << " value: " << beginIter->second << std::endl;}后果如下: ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-关联式容器

一、前言关联式容器在存储元素值的同时,还会为各元素额定再装备一个值(即是键,实质也是一个C++根底数据类型或自定义类型的元素),它的性能是在应用关联式容器的过程中,如果已知指标元素的键的值,则间接通过该键就能够找到指标元素,而无需再通过遍历整个容器的形式,提高效率。关联式容器和序列化容器的最大区别是:关联式容器存储的元素是“键值对<key,value>”,而且默认会依据各元素的键值的大小做升序排序。关联式容器所具备的这些个性,归咎于 STL 规范库在实现该类型容器时,底层选用了红黑树这种数据结构来组织和存储各个键值对。 二、关联式容器品种名称特点map定义在 <map> 头文件中,应用该容器存储的数据,其各个元素的键必须是惟一的(即不能反复),该容器会依据各元素键的大小,默认进行升序排序(调用 std::less<T>)set定义在 <set> 头文件中,应用该容器存储的数据,各个元素键和值完全相同,且各个元素的值不能反复(保障了各元素键的唯一性)。该容器会主动依据各个元素的键(其实也就是元素值)的大小进行升序排序(调用 std::less<T>)multimap定义在 <map> 头文件中,和 map 容器惟一的不同在于,multimap 容器中存储元素的键能够反复multiset定义在 <set> 头文件中,和 set 容器惟一的不同在于,multiset 容器中存储元素的值能够反复(一旦值反复,则意味着键也是反复的)阐明:此处不退出C++11新增的4种哈希容器:unordered_map、unordered_multimap 以及 unordered_set、unordered_multiset,这4种也属于关联式容器,只是哈希容器底层采纳的是哈希表,不是红黑树。留神的是:关联式容器键值对写入的程序不肯定和存储的程序是一样的。 三、pair用法因为“键值对”不是一般类型数据,因而stl规范库提供了pair类模板,专门用来将2个一般元素first和second创立成一个新的元素<first,second>。pair类模板定义在<utility>中,因而应用该类模板之前,须要引入该头文件,C++11之前,pair类模板提供了3种构造函数: ①默认构造函数,即创立空的 pair 对象pair();②间接应用 2 个元素初始化成 pair 对象pair (const first_type& a, const second_type& b);③拷贝(复制)构造函数,即借助另一个 pair 对象,创立新的 pair 对象template<class U, class V> pair (const pair<U,V>& pr);C++11中,引入右值援用后,减少了2个构造函数: ④ 挪动构造函数template<class U, class V> pair (pair<U,V>&& pr);⑤ 应用右值援用参数,创立 pair 对象template<class U, class V> pair (U&& a, V&& b);C++11中还有一种pair类模板的构造函数: pair (piecewise_construct_t pwc, tuple<Args1...> first_args, tuple<Args2...> second_args);然而这种办法不罕用,因而不做阐明。 ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-forwardlist容器

一、前言forward_list 是 C++ 11 新增加的一类容器,其底层实现和 list 容器一样,采纳的也是链表构造,只不过 forward_list 应用的是单链表,而 list 应用的是双向链表。单链表只能从前向后遍历,而不反对反向遍历,因而 forward_list 容器只提供前向迭代器,而不是双向迭代器。因而forward_list 容器不具备 rbegin()、rend() 之类的成员函数。存储雷同个数的同类型元素,单链表耗用的内存空间更少,空间利用率更高,并且对于实现某些操作单链表的执行效率也更高。 二、forward_list容器的创立在应用时,需增加头文件: #include <forward_list>using namespace std;一共有5种形式 ①std::forward_list<int> forwardListInt;②std::forward_list<int> forwardListInt(10);③std::forward_list<int> forwardListInt(10, 5);④std::forward_list<int> forwardListInt2(forwardListInt);⑤//拷贝一般数组,创立forward_list容器int a[] = { 1,2,3,4,5 };std::forward_list<int> values(a, a+5);//拷贝其它类型的容器,创立forward_list容器std::array<int, 5> arrayInt{ 11,12,13,14,15 };std::forward_list<int> forwardListInt(arrayInt.begin()+2, arr.end());形式与list容器相似,在这里不再阐明 三、反对的办法不阐明迭代器、插入和删除等办法 函数阐明empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 falsemax_size()返回容器所能蕴含元素个数的最大值,个别是 232-1front()返回第一个元素的援用assign()用新元素替换容器中原有内容swap(x,y)替换两个容器中的元素,必须保障这两个容器中存储的元素类型是雷同的resize()调整容器的大小merge()合并两个当时已排好序的 forward_list 容器,并且合并之后的 forward_list 容器仍然是有序的sort()通过更改容器中元素的地位,将它们进行排序reverse()反转容器中元素的程序这些办法的应用在list容器中曾经阐明过,在这里不再反复。 四、实例1、获取forward_list 容器的元素个数forward_list 容器中不提供size()办法,想要获取forward_list 容器的存储的元素个数能够应用头文件 <iterator> 中的 distance() 函数。 std::forward_list<int> listInt1{ 72,73,100,72,44,48,109,92,671,109,15,671 }; **int nCount = std::distance(std::begin(listInt1), std::end(listInt1));** std::cout << " forward_list listInt1 size: " << nCount << std::endl;后果如下: ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-list删除元素

一、办法函数阐明pop_front()删除位于 list 容器头部的一个元素pop_back()删除位于 list 容器尾部的一个元素erase()该成员函数既能够删除 list 容器中指定地位处的元素,也能够删除容器中某个区域内的多个元素。clear()删除 list 容器存储的所有元素remove(val)删除容器中所有等于 val 的元素unique()删除容器中相邻的反复元素,只保留一份remove_if()删除容器中满足条件的元素1、erase格局阐明iterator erase (iterator position);删除 list 容器中 position 迭代器所指地位处的元素iterator erase (iterator first, iterator last);删除 list 容器中 first 迭代器和 last 迭代器限定区域内的所有元素(包含 first 指向的元素,但不包含 last 指向的元素)2、unique格局阐明void unique()去除 list 容器中相邻反复的元素void unique(BinaryPredicate)去除 list 容器中相邻反复的元素,仅保留一份二、实例这里次要是unique()和remove_if()的应用 1、unique() std::list<int> listInt1{ 16,72,72,100,72,109,203,671,109,192,671 }, listInt2{9,201,94,43,67,81,901}; **listInt1.unique();** int i = 0; std::list<int>::iterator listIter1 = listInt1.begin(); for (; listIter1 != listInt1.end(); listIter1++) { std::cout << " unique listInt1[" << i++ << "]=" << *listIter1 << std::endl; }后果如下:由后果可知:①只能比拟相邻两个元素,若间断三个或以上元素值雷同也实用 ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-list-插入元素

一、插入方法函数性能push_front()向 list 容器首个元素前增加新元素push_back()向 list 容器最初一个元素后增加新元素emplace_front()在容器首个元素前间接生成新的元素emplace_back()在容器最初一个元素后间接生成新的元素emplace()在容器的指定地位间接生成新的元素insert()在指定地位插入新元素splice()将其余 list 容器存储的多个元素增加到以后 list 容器的指定地位处1、insert办法格局阐明iterator insert(pos,elem)在迭代器 pos 指定的地位之前插入一个新元素 elem,并返回示意新插入元素地位的迭代器iterator insert(pos,n,elem)在迭代器 pos 指定的地位之前插入 n 个元素 elem,并返回示意第一个新插入元素地位的迭代器iterator insert(pos,first,last)在迭代器 pos 指定的地位之前,插入其余容器(例如 array、vector、deque 等)中位于 [first,last) 区域的所有元素,并返回示意第一个新插入元素地位的迭代器iterator insert(pos,initlist)在迭代器 pos 指定的地位之前,插入初始化列表(用大括号 { } 括起来的多个元素,两头有逗号隔开)中所有的元素,并返回示意第一个新插入元素地位的迭代器2、splice办法格局阐明void splice (iterator position, list& x);单元 2单元 3position 为迭代器,用于指明插入地位;x 为另一个 list 容器。此格局的 splice() 办法的性能是,将 x 容器中存储的所有元素全副挪动以后 list 容器中 position 指明的地位处void splice (iterator position, list& x, iterator i);position 为迭代器,用于指明插入地位;x 为另一个 list 容器;i 也是一个迭代器,用于指向 x 容器中某个元素。此格局的 splice() 办法的性能是将 x 容器中 i 指向的元素挪动到以后容器中 position 指明的地位处。void splice (iterator position, list& x, iterator first, iterator last);position 为迭代器,用于指明插入地位;x 为另一个 list 容器;first 和 last 都是迭代器,[fist,last) 用于指定 x 容器中的某个区域。此格局的 splice() 办法的性能是将 x 容器 [first, last) 范畴内所有的元素挪动到以后容器 position 指明的地位处。splice() 成员办法挪动元素的形式将存储该元素的节点从 list 容器底层的链表中摘除,而后再链接到以后 list 容器底层的链表中。当应用 splice() 成员办法将list1容器中的元素增加到list2容器的同时,该元素会从list1容器中删除。 ...

May 7, 2021 · 2 min · jiezi

关于c++:C-STL-list迭代器

一、list容器迭代器函数函数性能begin()返回指向容器中第一个元素的双向迭代器(正向迭代器)end()返回指向容器中最初一个元素所在位置的下一个地位的双向迭代器。(正向迭代器)rbegin()返回指向最初一个元素的反向双向迭代器rend()返回指向第一个元素所在位置前一个地位的反向双向迭代器cbegin()和 begin() 性能雷同,只不过在其根底上,正向迭代器减少了 const 属性,即不能用于批改元素cend()和 end() 性能雷同,只不过在其根底上,正向迭代器减少了 const 属性,即不能用于批改元素crbegin()和 rbegin() 性能雷同,只不过在其根底上,反向迭代器减少了 const 属性,即不能用于批改元素crend()和 rend() 性能雷同,只不过在其根底上,反向迭代器减少了 const 属性,即不能用于批改元素具体的性能不再阐明,可参考array容器中的阐明。list容器的迭代器和之前的array、vector等最大的不同在于:它的迭代器类型为双向迭代器,而不再是随机拜访迭代器。如果p1,p2都是双向迭代器,那么反对++p1、 p1++、 p1--、 p1++、 *p1、 p1==p2 以及 p1!=p2;不反对p1[i]、p1-=i、 p1+=i、 p1+i 、p1-i、p1<p2、 p1>p2、 p1<=p2、 p1>=p2。 二、实例1、遍历list容器元素i = 0; listIter = listInt.begin(); for (; listIter != listInt.end(); listIter++) { std::cout << " sort listInt[" << i++ << "]=" << *listIter << std::endl; }其余的函数性能和vector等相似,不再阐明应用办法 留神点:1、list 容器不反对随机拜访,未提供下标操作符 [] 和 at() 成员函数,也没有提供 data() 成员函数2、 front() 和 back() 成员函数,能够别离取得 list 容器中第一个元素和最初一个元素的援用模式,必要时还能批改其值3、若心愿拜访list容器其余地位的元素,只能通过list容器的迭代器,也能够通过迭代器对指定元素的值进行批改 ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-list容器

一、前言list容器,又称为双向链表容器,即该容器的底层是以双向链表的模式实现的,因而list容器中的元素能够扩散存储在内存空间里,而不是必须存储在一整块间断的内存空间中。list容器中各个元素的前后程序是靠指针维系的,每个元素都有两个指针,别离指向它的前一个元素和后一个元素。第一个元素的前向指针总为 null,因为它后面没有元素;同样,尾部元素的后向指针也总为 null。长处:能够在序列已知的任何地位疾速插入或删除元素(工夫复杂度为O(1))。并且在 list 容器中挪动元素,也比其它容器的效率高。毛病:不能通过下标拜访元素,只能从容器中第一个元素或最初一个元素开始遍历容器,直到找到对应元素。list 容器以模板类 list<T>(T 为存储元素的类型)的模式在<list>头文件中,并位于 std 命名空间中。应用时需蕴含头文件: #include <list>using namespace std;二、初始化list容器一共有5种形式创立list容器 ①std::list<int> listInt;②std::list<int> listInt(10);③std::list<int> listInt(10, 5);④std::list<int> listInt2(listInt);⑤//拷贝一般数组,创立list容器int a[] = { 1,2,3,4,5 };std::list<int> listInt(a, a+5);//拷贝其它类型的容器,创立 list 容器std::array<int, 5> arrInt{ 11,12,13,14,15 };std::list<int> listInt(arrInt.begin()+2, arr.end());①创立空的list容器②创立一个蕴含10个元素,默认值为0的list容器③创立一个蕴含10个元素,初始值为5的list容器④将以初始化的list容器进行拷贝创立新的list容器,须保障新旧容器存储的元素类型统一⑤通过拷贝其余类型容器(或者一般数组)中指定区域内的元素,创立 list 容器 三、成员函数这里不列举迭代器、增加和删除等相干的函数。 函数性能empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 falsesize()返回以后容器理论蕴含的元素个数max_size()返回容器所能蕴含元素个数的最大值,个别是 232-1front()返回第一个元素的援用back()返回最初一个元素的援用assign()用新元素替换容器中原有内容swap(x,y)替换两个容器中的元素,必须保障这两个容器中存储的元素类型是雷同的resize()调整容器的大小splice()将一个 list 容器中的元素插入到另一个容器的指定地位merge()合并两个当时已排好序的 list 容器,并且合并之后的 list 容器仍然是有序的sort()通过更改容器中元素的地位,将它们进行排序reverse()反转容器中元素的程序四、实例1、创立list容器 std::list<int> listInt; listInt.push_back(31); listInt.push_back(27); listInt.push_back(29); std::cout << " listInt size: " << listInt.size() << std::endl; int i = 0; std::list<int>::iterator listIter = listInt.begin(); for (; listIter != listInt.end(); listIter++) { std::cout << " listInt[" << i++ << "]=" << *listIter << std::endl; } listInt.sort(); i = 0; listIter = listInt.begin(); for (; listIter != listInt.end(); listIter++) { std::cout << " sort listInt[" << i++ << "]=" << *listIter << std::endl; } int nFront = listInt.front(); int nBack = listInt.back(); std::cout << " listInt front: " << nFront << " back: " << nBack << std::endl; std::list<int> listInt1{ 14,25,99 }; listInt1.sort(); listInt.merge(listInt1); i = 0; listIter = listInt.begin(); for (; listIter != listInt.end(); listIter++) { std::cout << " merge listInt[" << i++ << "]=" << *listIter << std::endl; }后果如下: ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-deque添加和删除元素

一、前言deque 容器中,无论是增加元素还是删除元素,都只能借助 deque 模板类提供的成员函数。 二、波及的相干函数函数性能push_back()在容器现有元素的尾部增加一个元素pop_back()移除容器尾部的一个元素push_front()在容器现有元素的头部增加一个元素pop_front()移除容器尾部的一个元素emplace_back()在容器尾部生成一个元素,效率比push_back()高emplace_front()在容器头部生成一个元素,效率比push_front()高insert()在指定的地位间接生成一个元素emplace()在指定的地位间接生成一个元素,效率比insert高erase()移除一个元素或某一区域内的多个元素clear()删除容器中所有的元素insert用法格局性能iterator insert(pos,elem)在迭代器 pos 指定的地位之前插入一个新元素elem,并返回示意新插入元素地位的迭代器iterator insert(pos,n,elem)在迭代器 pos 指定的地位之前插入 n 个元素 elem,并返回示意第一个新插入元素地位的迭代器iterator insert(pos,first,last)在迭代器 pos 指定的地位之前,插入其余容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回示意第一个新插入元素地位的迭代器iterator insert(pos,initlist)在迭代器 pos 指定的地位之前,插入初始化列表(用大括号{}括起来的多个元素,两头有逗号隔开)中所有的元素,并返回示意第一个新插入元素地位的迭代器三、实例 1、增加、删除std::deque<int> dequeInt; dequeInt.push_back(319); std::cout << "push_back dequeInt size: " << dequeInt.size() << std::endl; dequeInt.pop_back(); std::cout << "pop_back dequeInt size: " << dequeInt.size() << std::endl; dequeInt.push_front(31); dequeInt.push_front(571); dequeInt.push_front(910); for (int i = 0; i < dequeInt.size(); i++) { std::cout << "push_front dequeInt[" << i << "]=" << dequeInt[i] << std::endl; } dequeInt.pop_front(); for (int i = 0; i < dequeInt.size(); i++) { std::cout << "pop_front dequeInt[" << i << "]=" << dequeInt[i] << std::endl; } dequeInt.emplace_front(1099); dequeInt.emplace_back(7100); for (int i = 0; i < dequeInt.size(); i++) { std::cout << "emplace_front and emplace_back dequeInt[" << i << "]=" << dequeInt[i] << std::endl; } dequeInt.emplace(dequeInt.begin() + 2, 4301); for (int i = 0; i < dequeInt.size(); i++) { std::cout << "emplace dequeInt[" << i << "]=" << dequeInt[i] << std::endl; } dequeInt.erase(dequeInt.begin() + 2); for (int i = 0; i < dequeInt.size(); i++) { std::cout << "erase appoint dequeInt[" << i << "]=" << dequeInt[i] << std::endl; }后果如下: ...

May 7, 2021 · 2 min · jiezi

关于c++:C-STL-deque迭代器

一、前言deque 容器迭代器的类型为随机拜访迭代器。 二、deque反对的迭代器成员函数函数性能begin()返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器end()返回指向容器最初一个元素之后一个地位的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin() 搭配应用rbegin()返回指向最初一个元素的反向迭代器;如果是 const 类型容器,在该函数返回的是常量反向迭代器rend()返回指向第一个元素之前一个地位的反向迭代器。如果是 const 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 rbegin() 搭配应用cbegin()和 begin() 性能相似,只不过其返回的迭代器类型为常量正向迭代器,不能用于批改元素cend()和 end() 性能雷同,只不过其返回的迭代器类型为常量正向迭代器,不能用于批改元素crbegin()和 rbegin() 性能雷同,只不过其返回的迭代器类型为常量反向迭代器,不能用于批改元素crend()和 rend() 性能雷同,只不过其返回的迭代器类型为常量反向迭代器,不能用于批改元素函数的具体性能和array、vector的相似,这里不再具体阐明。stl反对全局的begin()和end()函数。 三、根本用法1、begin()和end()begin() 和 end() 别离用于指向「首元素」和「尾元素+1」 的地位 2、cbegin()和cend()和 begin()/end() 惟一不同的是:cbegin()/cend() 成员函数返回的是 const 类型的正向迭代器,这样能够用来遍历容器内的元素,也能够拜访元素,然而不能对所存储的元素进行批改。 3、rbegin()和rend()别离示意指向最初一个元素和第一个元素前一个地位的随机拜访迭代器,又常称为反向迭代器。crbegin()/crend() 组合和 rbegin()/crend() 组合惟一的区别在于:前者返回的迭代器为 const 类型迭代器,不能用来批改容器中的元素,除此之外在应用上和后者完全相同。 四、注意事项1、迭代器的性能是遍历容器,在遍历的同时能够拜访(甚至批改)容器中的元素,但迭代器不能用来初始化空的 deque 容器。2、对于空的 deque 容器来说,能够通过 push_back()、push_front() 或者 resize() 成员函数实现向(空)deque 容器中增加元素。3、当向 deque 容器增加元素时,deque 容器会申请更多的内存空间,同时其蕴含的所有元素可能会被复制或挪动到新的内存地址(原来占用的内存会开释),这会导致之前创立的迭代器生效。和vector相似。 五、实例 //全局begin和end i = 0; for (dequeIter = begin(dequeInt); dequeIter < end(dequeInt); dequeIter++) { std::cout << "global begin and end dequeInt[" << i << "]=" << *dequeIter << std::endl; } //cbegin/cend i = 0; std::deque<int>::const_iterator dequeIterC = dequeInt.cbegin(); for (; dequeIterC != dequeInt.cend(); dequeIterC++) { std::cout << "cbegin and cend dequeInt[" << i << "]=" << *dequeIterC << std::endl; } //rbegin/rend i = 0; std::deque<int>::reverse_iterator dequeIterR = dequeInt.rbegin(); for (; dequeIterR != dequeInt.rend(); dequeIterR++) { std::cout << "rbegin and rend dequeInt[" << i << "]=" << *dequeIterR << std::endl; } //crbegin/crend i = 0; std::deque<int>::const_reverse_iterator dequeIterCR = dequeInt.crbegin(); for (; dequeIterCR != dequeInt.rend(); dequeIterCR++) { std::cout << "crbegin and crend dequeInt[" << i << "]=" << *dequeIterCR << std::endl; }后果如下: ...

May 7, 2021 · 1 min · jiezi

关于c++:C-STL-deque容器

一、前言deque 是 double-ended queue 的缩写,又称双端队列容器。deque 容器和 vecotr 容器有很多相似之处:①deque 容器也善于在序列尾部增加或删除元素(工夫复杂度为O(1)),而不善于在序列两头增加或删除元素②deque 容器也能够依据须要批改本身的容量和大小与vector不同的是:deque 还善于在序列头部增加或删除元素,所消耗的工夫复杂度也为常数阶O(1)。deque 容器中存储元素并不能保障所有元素都存储到间断的内存空间中。当须要向序列两端频繁的增加或删除元素时,应首选 deque 容器。deque 容器以模板类 deque<T>(T 为存储元素的类型)的模式在 <deque> 头文件中,并位于 std 命名空间中。因而,在应用该容器之前,代码中须要蕴含上面两行代码: #include <deque>using namespace std;二、详解1、初始化deque容器①std::deque<int> d;②std::deque<int> d(10);③std::deque<int> d(10, 5);④std::deque<int> d2(d);⑤//拷贝一般数组,创立deque容器int a[] = { 1,2,3,4,5 };std::deque<int>d(a, a + 5);⑥//实用于所有类型的容器std::array<int, 5>arr{ 11,12,13,14,15 };std::deque<int>d(arr.begin()+2, arr.end());//拷贝arr容器中的{13,14,15}①创立空的deque容器,和空 array 容器不同,空的 deque 容器在创立之后能够做增加或删除元素的操作②创立一个具备10个元素、元素默认值为0的deque容器③创立一个具备10个元素的deque容器,指定初始值为5的deque容器④拷贝初始化deque容器d2,须要保障新旧容器存储的元素类型统一 2、成员函数函数性能begin()返回指向容器中第一个元素的迭代器end()返回指向容器最初一个元素所在位置后一个地位的迭代器,通常和 begin() 联合应用rbegin()返回指向最初一个元素的迭代器rend()返回指向第一个元素所在位置前一个地位的迭代器cbegin()和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素cend()和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素crbegin()和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素crend()和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素size()返回理论元素个数max_size()返回容器所能包容元素个数的最大值,个别是 232-1resize()扭转理论元素的个数empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 falseshrink _to_fit()将内存缩小到等于以后元素理论所应用的大小at()应用通过边界查看的索引拜访元素front()返回第一个元素的援用back()返回最初一个元素的援用assign()用新元素替换原有内容push_back()在序列的尾部增加一个元素push_front()在序列的头部增加一个元素pop_back()移除容器尾部的元素insert()在指定的地位插入一个或多个元素erase()移除一个元素或一段元素clear()移出所有的元素,容器大小变为 0swap()替换两个容器的所有元素emplace()在指定的地位间接生成一个元素emplace_front()在容器头部生成一个元素。和 push_front() 的区别是,该函数间接在容器头部结构元素,省去了复制挪动元素的过程emplace_back()在容器尾部生成一个元素。和 push_back() 的区别是,该函数间接在容器尾部结构元素,省去了复制挪动元素的过程std::swap(x , y)非成员函数,替换数据阐明:与vector相比,额定减少了实现在容器头部增加和删除元素的成员函数,同时删除了 capacity()、reserve() 和 data() 成员函数。 ...

May 6, 2021 · 1 min · jiezi

关于c++:C-STL-Vector容器

一、前言vector和array的不同之处在于:array 实现的是动态数组(容量固定的数组),而 vector 实现的是一个动静数组。vector 容器以类模板 vector<T>( T 示意存储元素的类型)的模式定义在 <vector> 头文件中,并位于 std 命名空间中。因而,在创立该容器之前,代码中需蕴含如下内容: #include <vector>using namespace std;阐明:std命名空间也可在应用vector容器时额定注明,如: std::vector<double> values;二、创立vector的形式①std::vector<int> vecInt;②std::vector<int> vecInt {1,5,23,45,87};③std::vector<int> vecInt(10);④std::vector<int> vecInt(10, 4);①形式创立一个空的vector容器,因为容器中没有元素,所以没有调配空间,当用户增加元素时,vector会主动分配内存空间。如果创立好的vector容器的容量有余,可通过reserve()减少容器的容量。须要留神的是: 调用 reserve() 不会影响已存储的元素,也不会生成任何元素,即 vecInt 容器内此时依然没有任何元素;如果调用 reserve() 来减少容器容量,之前创立好的任何迭代器(例如开始迭代器和完结迭代器)都可能会生效,因为为了减少容器的容量,vector<T> **容器的元素可能曾经被复制或移到了新的内存地址**。②形式创立一个蕴含有5个元素的vector容器③形式创立一个有10个元素、默认初始值为0的vector容器④形式创立一个有10个元素、指定初始值为4的vector容器 圆括号 () 和大括号 {} 是有区别的,前者示意元素的个数,而后者则示意 vector 容器中的元素值。 三、成员函数成员函数性能begin()返回指向容器中第一个元素的迭代器end()返回指向容器最初一个元素所在位置后一个地位的迭代器,通常和 begin() 联合应用rbegin()返回指向最初一个元素的迭代器rend()返回指向第一个元素所在位置前一个地位的迭代器cbegin()和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素cend()和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素crbegin()和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素crend()和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素size()返回理论元素个数max_size()返回元素个数的最大值,个别是 232-1,所以咱们很少会用到这个函数resize()扭转理论元素的个数capacity()返回以后容量empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 falsereserve()减少容器的容量shrink _to_fit()将内存缩小到等于以后元素理论所应用的大小operator[ ]重载了 [ ] 运算符,能够向拜访数组中元素那样,通过下标即可拜访甚至批改 vector 容器中的元素at()应用通过边界查看的索引拜访元素front()返回第一个元素的援用back()返回最初一个元素的援用data()返回指向容器中第一个元素的指针assign()用新元素替换原有内容push_back()在序列的尾部增加一个元素pop_back()移出序列尾部的元素insert()在指定的地位插入一个或多个元素erase()移出一个元素或一段元素clear()clear()swap()替换两个容器的所有元素emplace()在指定的地位间接生成一个元素emplace_back()在序列尾部生成一个元素std::swap(x , y)非成员函数,替换数据四、迭代器的用法vector的迭代器成员函数和array根本是一样的,如下:begin()end()rbegin()rend()cbegin()cend()crbegin()crend()具体性能图示与https://segmentfault.com/a/11... ...

May 6, 2021 · 5 min · jiezi

关于c++:C-STL标准模板库

一、前言STL:Standard Template Library(规范模板库或泛型库),是C++规范库的组成部分。STL借助模板把罕用的数据结构及其算法实现了一次,并且做到了数据结构和算法的拆散。STL已齐全被内置到反对 C++ 的编译器中,无需额定装置,这可能也是STL被宽泛应用的起因之一。STL是以源代码的模式提供的。基本上来说,STL是一些容器(封装有数据结构的模板类)、算法和其余的一些组件的汇合,根本达到了各种存储办法和相干算法的高度优化。 STL的版本HP STLAlexandar Stepanov(STL 规范模板库之父)与 Meng Lee 单干实现。是开放源码的。 SGI STLHP STL的一个继承版本,开源、可读性好 STLport为了使 SGI STL 的根本代码都实用于 VC++ 和 C++ Builder 等多种编译器而提出的,开源 PL STL参照 HP STL 实现进去的,也是 HP STL 的一个继承版本,因而该头文件中不仅含有 HP STL 的相干受权信息,同时还有 P.J.Plauger 自己的版权信息。非开源。 Rouge Wave STL由 Rouge Wave 公司开发的,也是继承 HP STL 的一个版本,它也不是开源的。 二、STL的根本组成STL是由容器、算法、迭代器、函数对象、适配器、内存分配器6局部形成,其中迭代器、函数对象、适配器、内存分配器是为容器、算法服务。 组成部分含意容器一些封装数据构造的模板类算法STL 提供了十分多(大概 100 个)的数据结构算法,它们都被设计成一个个的模板函数,这些算法在 std 命名空间中定义,其中大部分算法都蕴含在头文件 <algorithm> 中,少部分位于头文件 <numeric> 中迭代器对容器中数据的读和写,是通过迭代器实现的,扮演着容器和算法之间的胶合剂函数对象一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数)适配器能够使一个类的接口(模板的参数)适配成用户指定的模式,从而让本来不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器内存分配器为容器类模板提供自定义的内存申请和开释性能在 C++ 规范中,STL被从新组织为13个头文件,如下: <iterator><functional><vector><deque><list><queue><stack><set><map><algorithm><numeric><memory><utility>留神:或者是为了向下兼容,或者是为了外部组织布局,某些 STL 版本同时存储具备扩展名和无扩展名的两份文件,倡议最好遵循C++标准,应用无扩展名的头文件。 三、容器是什么在理论的开发过程中,存取数据的形式会间接影响到对它们进行增删改查操作的复杂程度和工夫耗费。简略的了解容器,就是一些模板类的汇合,但和一般模板类不同的是,容器中封装的是组织数据的办法(也就是数据结构)。STL 提供有3类规范容器,别离是序列容器、排序容器和哈希容器,其中后两类容器有时也统称为关联容器,如下表: 容器品种性能序列容器次要包含 vector 向量容器、list 列表容器以及 deque 双端队列容器。之所以被称为序列容器,是因为元素在容器中的地位同元素的值无关,即容器不是排序的。将元素插入容器时,指定在什么地位,元素就会位于什么地位。排序容器包含 set 汇合容器、multiset多重汇合容器、map映射容器以及 multimap 多重映射容器。排序容器中的元素默认是由小到大排序好的,即使是插入元素,元素也会插入到适当地位。所以关联容器在查找时具备十分好的性能。哈希容器C++ 11 新退出 4 种关联式容器,别离是 unordered_set 哈希汇合、unordered_multiset 哈希多重汇合、unordered_map 哈希映射以及 unordered_multimap 哈希多重映射。和排序容器不同,哈希容器中的元素是未排序的,元素的地位由哈希函数确定。以上3类容器的存储形式齐全不同,因而应用不同容器实现雷同操作的效率也大不相同。因而在理论应用中,要依据具体的性能抉择最适宜的容器。 ...

May 6, 2021 · 1 min · jiezi

关于c++:使用VS2019开发和调试Linux程序

一、前言目前,越来越多的我的项目有需要在Linux平台上编译运行,为了兼容windows程序员在相熟的开发环境下实现linux的开发,vs2019中提供了对linux开发的原生反对。VS2019反对两种开发方式,一种是传统的sln形式,一种工具链形式,工具链模式不反对autotools工具链,只反对CMake,这个对咱们没有什么本质上的影响,当初很多跨平台开源我的项目都曾经迁徙到CMake上了,以下的例子是应用sln形式进行阐明的,今后咱们能够依据需要抉择应用哪种形式来进行开发。 二、装置vs2019环境1、到https://visualstudio.microsof...2、勾选"持续"3、到vs2019的开发子模块抉择,如下: 勾选对应的内容进行装置4、筹备一个反对ssh的linux真机或者虚拟机 三、步骤1、创立我的项目关上VS2019,执行步骤如下:其余配置抉择默认即可,生成的代码为: 2、配置工程属性次要是配置近程计算机的ip地址、用户、登录明码等。到此其余的配置就和windows上的截然不同了 3、编译工程将须要的命令写入命令行(右键我的项目——属性——连接器——命令行——其余选项),执行编译 4、启动程序编译失常后,即可设置断点,F5运行程序进行调试 四、CMAKE应用sln须要将我的项目相干的文件都退出到sln中来,且win和linux须要两个不同的sln,显然这么做在工程很多的时候会变的很简单和繁琐。因而能够应用一下CMAKE编译。 1、步骤1)在创立新我的项目时,抉择cmake我的项目2)默认只有windows上的编译选项,双击减少linux的编译选项3)近程计算机选中配置的linux机器,参考2、配置工程属性4)点开高级选项,设置一下近程linux上cmake的地位和智能感知的工具集5)编辑一下CMakelists.txt,限度应用std cpp 17,实例代码:https://github.com/ttroy50/cm...6)在linux上和win上别离编译之后跑一下,失常即可 2、总结1、用VS2019+规范库参照肯定的标准开发windows版2、新建linux工程(sln或者CMake),将代码退出工程,编译,实践上此时就能失去一个linux版的二进制了

May 6, 2021 · 1 min · jiezi

关于c++:跨平台字符处理

跨平台字符解决应用计算机的过程中常常会看到一堆莫名其妙的符号(乱码),导致呈现乱码的一个重要起因就是未能依照正确的编码格局对字符串解码。当呈现两种编码方式不兼容的字符时就会呈现乱码,为了正确的显示字符串就必须将其转换为对应的编码。以下介绍了chrome中实现的跨平台编码转换形式。 跨平台字符串解决波及宽字节表示法与UTF-8表示法之间的转换和宽字节表示法与多字节表示法之间的转换。 相干文件base/strings/sys\_string\_conversions.h // 办法定义base/strings/sys\_string\_conversions\_win.cc // windows零碎下字符串解决base/strings/sys\_string\_conversions\_mac.mm // mac零碎下字符串解决base/strings/sys\_string\_conversions\_posix.cc // 兼容posix零碎下字符串解决办法定义首先定义了宽字节与UTF-8之间的转换,紧接着是宽字节与多字节之间的转换。依据不同零碎又别离定义了windows、mac、posix下的转换方法。 应用时不必关系不同零碎下的具体实现形式,只须要在前四个办法中抉择须要的办法即可。chrome的这种形式极大的升高跨平台开发时字符串编码转换难度。 // base/strings/sys_string_conversions.hnamespace base {// Converts between wide and UTF-8 representations of a string. On error, the// result is system-dependent.BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide) WARN_UNUSED_RESULT;BASE_EXPORT std::wstring SysUTF8ToWide(StringPiece utf8) WARN_UNUSED_RESULT;// Converts between wide and the system multi-byte representations of a string.// DANGER: This will lose information and can change (on Windows, this can// change between reboots).BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide) WARN_UNUSED_RESULT;BASE_EXPORT std::wstring SysNativeMBToWide(StringPiece native_mb) WARN_UNUSED_RESULT;// Windows-specific ------------------------------------------------------------#if defined(OS_WIN)// Converts between 8-bit and wide strings, using the given code page. The// code page identifier is one accepted by the Windows function// MultiByteToWideChar().BASE_EXPORT std::wstring SysMultiByteToWide(StringPiece mb, uint32_t code_page) WARN_UNUSED_RESULT;BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide, uint32_t code_page) WARN_UNUSED_RESULT;#endif // defined(OS_WIN)// Mac-specific ----------------------------------------------------------------#if defined(OS_APPLE)// Converts between STL strings and CFStringRefs/NSStrings.// Creates a string, and returns it with a refcount of 1. You are responsible// for releasing it. Returns NULL on failure.BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF8ToCFStringRef(StringPiece utf8) WARN_UNUSED_RESULT;BASE_EXPORT ScopedCFTypeRef<CFStringRef> SysUTF16ToCFStringRef( StringPiece16 utf16) WARN_UNUSED_RESULT;// Same, but returns an autoreleased NSString.BASE_EXPORT NSString* SysUTF8ToNSString(StringPiece utf8) WARN_UNUSED_RESULT;BASE_EXPORT NSString* SysUTF16ToNSString(StringPiece16 utf16) WARN_UNUSED_RESULT;// Converts a CFStringRef to an STL string. Returns an empty string on failure.BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref) WARN_UNUSED_RESULT;BASE_EXPORT std::u16string SysCFStringRefToUTF16(CFStringRef ref) WARN_UNUSED_RESULT;// Same, but accepts NSString input. Converts nil NSString* to the appropriate// string type of length 0.BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref) WARN_UNUSED_RESULT;BASE_EXPORT std::u16string SysNSStringToUTF16(NSString* ref) WARN_UNUSED_RESULT;#endif // defined(OS_APPLE)} // namespace base跨平台实现windowswindows下应用了两个要害的api别离是,MultiByteToWideChar、WideCharToMultiByte。chrome基于这两个函数实现了宽字节与UTF-8、宽字节与多字节,在windows零碎下的转换。 ...

May 6, 2021 · 7 min · jiezi

关于c++:leetcodeJZ31

题面输出两个整数序列,第一个序列示意栈的压入程序,请判断第二个序列是否为该栈的弹出程序。假如压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。 示例 1: 输出:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]输入:true解释:咱们能够按以下程序执行:push(1), push(2), push(3), push(4), pop() -> 4,push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1 示例 2: 输出:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]输入:false解释:1 不能在 2 之前弹出。 提醒: 0 <= pushed.length == popped.length <= 1000 0 <= pushed[i], popped[i] < 1000 pushed 是 popped 的排列。 原题链接 剖析依照出栈序列结构辅助栈,如果辅助栈可能结构胜利,则阐明该出栈序列非法。 (参考《剑指offer》(第二版)170页) 源代码(正文局部即为思路)/*工夫:2021/5/1实现形式:参考《剑指offer》(第二版)170页总体思路:结构辅助栈*/class Solution {public: bool validateStackSequences(vector<int>& pushed, vector<int>& popped) { int push_len = pushed.size(); int pop_len = popped.size(); //此处不能写成pushed==NULL这样的判断条件,pushed和popped不是指针变量 if(push_len==0 || pop_len==0){ if(push_len==0 && pop_len==0){ return true; } else{ return false; } } int i=0; int j=0; vector<int> help; while(i<pop_len){ //顺次寻找弹出序列中的元素 int tmp = popped[i]; int len = help.size(); //辅助栈的栈顶有要弹出的元素 if(len>0 && help[len-1] == tmp){ help.pop_back(); } //辅助栈的栈顶没有要弹出的元素 //依照压入序列向辅助栈内压入元素,直到压入了须要弹出的元素 else{ //while循环条件:j<push_len && pushed[j]!=tmp,程序不能反过来,否则会报越界的谬误 //首先必须保障j在非法范畴内,而后才去取pushed[j]的值 while(j<push_len && pushed[j]!=tmp){ help.push_back(pushed[j]); j++; } if(j<push_len){ help.push_back(pushed[j]); help.pop_back(); j++; } else{ return false; } } i++; } return true; }};

May 1, 2021 · 1 min · jiezi

关于c++:Huffman树实现编码译码数据结构实验

...累了,一会更新,写正文,写思路,最好能画画图 代码#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<vector>#include<algorithm>#include<map>#include <string>using namespace std;typedef struct { int val; int weight; int parent, lchild, rchild;}HuffmanNode;static bool cmp(vector<int> a, vector<int> b) { return a[1] > b[1];}void calculate(vector<vector<int>>& check) { FILE* file; file = fopen("a.txt", "r"); char c; while ((c = fgetc(file)) != EOF) { if (c >= 'a' && c <= 'z') { check[c - 'a'][1]++; } else if (c >= 'A' && c <= 'Z') { check[c - 'A' + 26][1]++; } else if (c == ' ') { check[52][1]++; } else if (c == ',') { check[53][1]++; } else if (c == '.') { check[54][1]++; } } sort(check.begin(), check.end(), cmp);}//统计呈现字母的频率void initHuffmanTree(HuffmanNode* HT, int n, int m, vector<vector<int>>& check) { int j = 1; for (int i = n - 1; i >= 0; i--) { HT[j++] = {check[i][0], check[i][1],0,0,0}; } for (; j <= m; j++) { HT[j] = { 0,0,0,0,0 }; }}//初始化哈夫曼树void select(HuffmanNode* HT,int endLoc, int& node1, int& node2) { int min1 = INT_MAX - 1, min2 = INT_MAX; for (int i = 1; i <= endLoc; i++) { if (HT[i].parent == 0) { if (HT[i].weight < min1) { min1 = HT[i].weight; node1 = i; } else if (HT[i].weight < min2) { min2 = HT[i].weight; node2 = i; } } }}//选出两个最小的节点void createHuffmanTree(HuffmanNode* HT, int n, int m) { int loc; int node1, node2; for (int i = n + 1; i <= m; i++) { select(HT, i - 1, node1, node2); HT[i].lchild = node2; HT[i].rchild = node1; HT[i].weight = HT[node1].weight + HT[node2].weight; HT[node1].parent = HT[node2].parent = i; }}//建设哈夫曼树void encode(HuffmanNode* HT, int n, map<int, string>& huffmanCode) { int par; //父节点 int son; //子节点地位 for (int i = 1; i <= n; i++) { son = i; par = HT[i].parent; string code = ""; while (par != 0) { if (HT[par].lchild == son) { code.insert(code.begin(), '0'); } if (HT[par].rchild == son) { code.insert(code.begin(), '1'); } son = par; par = HT[par].parent; }//向上找,直到没有parent huffmanCode[HT[i].val] = code; } }//生成哈夫曼码void encodeTxtToHuffmanCode(map<int, string>& huffmanCode) { FILE* readFile = fopen("a.txt", "r"); FILE* writeFile = fopen("b.txt", "w"); char c = fgetc(readFile); while (c != EOF) { int i; if (c >= 'a' && c <= 'z') { i = c - 'a'; } else if (c >= 'A' && c <= 'Z') { i = c - 'A' + 26; } else if (c == ' ') { i = 52; } else if (c == ',') { i = 53; } else if (c == '.') { i = 54; } for (int j = 0; j < huffmanCode[i].size(); j++) { fputc(huffmanCode[i][j], writeFile); } c = fgetc(readFile); } fclose(readFile); fclose(writeFile);}void decode(HuffmanNode* HT, int n) { FILE* readFile = fopen("b.txt", "r"); FILE* writeFile = fopen("c.txt", "w"); char c = fgetc(readFile); int i = 2 * n - 1; while (c != EOF) { if (c == '0') { i = HT[i].lchild; } else if (c == '1') { i = HT[i].rchild; } if (HT[i].lchild == 0 || HT[i].rchild == 0) { char c; if (HT[i].val >= 0 && HT[i].val <= 25) { c = 'a' + HT[i].val; } else if (HT[i].val >= 26 && HT[i].val <= 51) { c = 'A' + HT[i].val - 26; } else if (HT[i].val == 52) { c = ' '; } else if (HT[i].val == 53) { c = ','; } else if (HT[i].val == 54) { c = '.'; } fputc(c, writeFile); i = 2 * n - 1; } c = fgetc(readFile); } fclose(readFile); fclose(writeFile);}//哈夫曼码翻译成文章int main() { vector<vector<int>> check(55,vector<int>(2,0)); for (int i = 0; i < check.size(); i++) { check[i][0] = i; } calculate(check); int n = 0; //叶子个数(呈现的字母个数) for (int i = 0; i < check.size(); i++) { if (check[i][1] != 0) n++; } int m = 2 * n - 1; //Huffman节点 HuffmanNode* HT; HT = (HuffmanNode*)malloc((m + 1) * sizeof(HuffmanNode)); //第0个节点不必 initHuffmanTree(HT, n, m, check); createHuffmanTree(HT, n, m); /*for (int i = 1; i <= m; i++) { cout << HT[i].val << " " << HT[i].weight << " " << HT[i].parent << " " << HT[i].lchild << " " << HT[i].rchild << endl; }*/ map<int, string> huffmanCode; encode(HT, n, huffmanCode); /*for (auto x : huffmanCode) { cout << x.first << " " << x.second << endl; }*/ encodeTxtToHuffmanCode(huffmanCode); decode(HT, n);}

April 30, 2021 · 4 min · jiezi

关于c++:c标准库流状态一览

1. 流状态阐明c++规范库对于流定义了一套它本人的状态变动规定,在ios_base.h申明的ios_base类中,它定义了一个枚举类型_Ios_Iostate来示意流状态,次要有以下四种: 状态阐明badbit在输入输出时遇到了零碎级谬误,会置为badbiteofbit读取文件时读到了文件开端,就会置为eofbitfailbit往流缓冲区写入或者读取数据产生谬误时,会被置为failbitgoodbit下面三种都没有时,就是goodbit另外ios_base另外定义了一个爱护成员iostate _M_streambuf_state;来示意以后流的状态。 2. 流状态操作函数对于流状态操作函数,是定义在类basic_ios类中,它是ios_base的派生类,位于头文件basic_ios.h中,这里不探讨basic_ios类的应用,只阐明它外面定义的状态操作函数. 阐明:枚举类型_Ios_Iostate取了个别名,叫iostate。函数原型如下: //返回以后流状态 iostate rdstate() const { return _M_streambuf_state; }//默认革除所有异样状态,置为goodbit void clear(iostate __state = goodbit);//在以后流状态根底上依据传入状态进行追加 void setstate(iostate __state) { this->clear(this->rdstate() | __state); }//如果以后状态是goodbit,那么返回true,否则返回false bool good() const { return this->rdstate() == 0; }//如果以后流状态是eofbit,那么返回true,否则返回false bool eof() const { return (this->rdstate() & eofbit) != 0; }//如果以后流状态是failbit,那么返回true,否则返回false bool fail() const { return (this->rdstate() & (badbit | failbit)) != 0; }//如果以后流状态是badbit,那么返回true,否则返回false bool bad() const { return (this->rdstate() & badbit) != 0; }所以如果咱们想被动的设置流状态,能够应用setstate函数,想革除所有异样状态,能够应用clear函数,想判断以后流状态是否失常,就应用good函数。 ...

April 30, 2021 · 1 min · jiezi

关于c++:c八股之多态持续更新

c++多态c++的多态,从绑定工夫来看,能够分为动态多态和动静多态,或者说是编译期多态和运行时多态。范型编程和模板编程通过模板的机制实现动态多态对象模型通过重载和虚函数的机制实现动态多态和动静多态1. inliine函数能够是虚函数码?不能够,因为inline函数没有地址,无奈将他寄存到虚函数表中。 2. 动态成员能够是虚函数吗?不能,因为动态成员函数中没有this指针,应用::的调用形式无法访问虚函数表,所以动态成员函数无奈放进虚函数表。 3. 构造函数能够是虚函数吗?不能够,因为对象中的虚函数指针是在对象结构的时候初始化的。 4. 析构函数能够是虚函数吗?什么场景下析构函数是虚函数?cppreference:一条有用的方针是,任何基类的析构函数必须为公开且虚,或受爱护且非虚这个问题也就是说,是否应该容许指向基类的指针进行销毁派生类对象?如果是,则base的析构函数必须是公共的能力被调用,否则虚构调用它会导致未定义的行为。否则,应该对其进行爱护,以便只有派生类能力在本人的析构函数中调用它,这个析构函数也应该是非虚的,因为它不须要虚构地运行。 5. 对象拜访一般函数快还是虚函数快?如果是一般对象,是一样快的,如果是指针对象或者是援用对象,调用一般函数更快一些,因为形成了多态,运行时调用虚函数要先到虚函数表中去查找。这样而后才拿到函数的地址,这样就不如间接能够拿到函数地址的一般函数快。 6.虚函数表指针被编译器初始化的过程怎么了解的?当类中申明了虚函数是,编译器会在类中生成一个虚函数表VS中寄存在代码段,虚函数表实际上就是一个寄存虚函数指针的指针数组,是由编译器主动生成并保护的。虚表是属于类的,不属于某个具体的对象,一个类中只须要有一个虚表即可。同一个类中的所有对象应用同一个虚表,为了让每个蕴含虚表的类的对象都领有一个虚表指针,编译器在每个对象的头增加了一个指针,用来指向虚表,并且这个指针的值会主动被设置成指向类的虚表,每一个virtaul函数的函数指针寄存在虚表中,如果是单继承,先将父类的虚表增加到子类的虚表中,而后子类再增加本人新增的虚函数指针,然而在VS编译器中咱们通常看不到新增加的虚函数指针,是编译器成心将他们暗藏起来,如果是多继承,在子类中新增加的虚函数指针会寄存在第一个继承父类的虚函数表中。 7. 多态的分类动态绑定的多态的是通过函数的重载来实现的。动静绑定的多态是通过虚函数实现的。 8. 为什么要引入抽象类和纯虚函数?在很多状况下由基类生成对象是很不合理的,纯虚函数在基类中是没有定义的,要求在子类必须加以实现,这种蕴含了纯虚函数的基类被称为抽象类,不能被实例化,如果子类没有实现纯虚函数,那么它他也是一个抽象类。 9. 虚函数和纯虚函数有什么区别?纯虚函数不在基类里实现,必须要在派生类里重写。非纯虚函数,能够在基类实现,派生类能够实现,也能够不重写虚函数既继承接口的同时也继承了基类的实现,纯虚函数关注的是接口的统一性,实现齐全由子类来实现。

April 29, 2021 · 1 min · jiezi

关于c++:c中endl操作符以及它的兄弟们

阐明一下,我用的是g++7.1.0编译器,规范库源代码也是这个版本的。始终以来,咱们每次应用cout输入数据的时候,如果要换行,都晓得应用形如cout << endl;这样的模式,那么endl到底是什么呢,它是怎么样实现输入一个换行符的性能的,以前我没有思考过,但当初我想弄懂它,上面就一起看一下吧。 1.endl操作符的实现在规范库头文件<ostream>中,我找到了endl的操作符重载函数,如下: template<typename _CharT, typename _Traits> inline basic_ostream<_CharT, _Traits>& endl(basic_ostream<_CharT, _Traits>& __os) { return flush(__os.put(__os.widen('\n'))); }它是一个内联的函数模板,是一个全局的函数模板,endl正是它的函数名,它的作用是往缓冲区写入一个换行符并且立刻从缓冲区刷新到外部设备中。 那么endl是怎么与<<操作符关联起来的呢,咱们在ostream头文件ostream类的申明中又发现了以下代码: __ostream_type& operator<<(__ostream_type& (*__pf)(__ostream_type&)) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 60. What is a formatted input function? // The inserters for manipulators are *not* formatted output functions. return __pf(*this); }这个操作符的入参是一个__ostream_type& (*__pf)(__ostream_type&)类型的函数指针,这个类型与endl的类型是统一的,从而,咱们当初晓得了endl的实现过程。 与endl同样实现的总共是亲兄弟三个,他们类型一样,且都是对缓冲区进行操作,如下: 操作符阐明endl输入一个换行符到缓冲区,且即时刷新到外部设备ends输入一个空字符到缓冲区flush调用flush函数,把数据从缓冲区刷新到外部设备2. 格式化操作符说完endl的亲兄弟,接下来说一说它的堂兄弟们,那就是格式化操作符,在某些书籍上也叫做操纵算子,操纵算子用法与endl一样,也是形如cout << oct这样的模式,但它不会对缓冲区间接进行操作,它是对后续的数据输入进行格式化,相似c语言的%d一样,且操纵算子的实现形式与endl相似,只是<<的返回类型与参数类型不一样而已,这里就不再多说。 操纵算子分为两类,一类是无参的,定义在ios_base.h头文件中,还有一类是有参的,定义在iomanip头文件中。 2.1 无参操纵算子操纵算子阐明boolalpha针对bool类型变量,不是输入0和1,而是输入true或者falsenoboolalphaboolalpha的反向操作showbase在输入八进制或者十六进制的时候,加上0x这样的前缀,次要它要放在进制操作符的后面noshowbaseshowbase的反向操作showpoint强制打印小数点noshowpointshowpoint的反向操作showpos针对非负的数字,强制加上+号输入noshowposshowpos的反向操作skipws它是一个输出类操作符,作用是在输出时跳过空格,这一点与不应用skipws时是统一的noskipws这里次要是noskipws会扭转>>的默认输出形式,会把空格,制表符等也读入uppercase在输入十六进制这样的数据时,对外面的字母进行大写,留神它对输入字符类型或者字符串类型是不起作用的nouppercaseuppercase的反向操作unitbuf每次输入当前都刷新缓冲区nounitbufunitbuf的反向操作internal在设置了输入宽度的状况下,符号左对齐,值右对齐,两头应用空格填充left在设置了输入宽度的状况下,输入整体左对齐,没有设置输入宽度,说对齐都是耍流氓right在设置了输入宽度的状况下,输入整体右对齐,iostream流默认右对齐dec十进制输入,对浮点数不起成果,只对整型有成果hex十六进制输入,对浮点数不起成果,只对整型有成果oct八进制输入,对浮点数不起成果,只对整型有成果fixed定点十进制进行输入,默认输入6位小数位,小数位有余补0,超出的四舍五入,保留6位scientific迷信计数法输入hexfloat十六进制模式输入浮点数defaultfloat对浮点数输入复原默认状态一个应用案例如下: #include <iostream> using namespace std; int main() { // Initializing the integer double x = 10.2333336; //将浮点数x以十六进制模式输入,且字母都为大写 cout << uppercase << hexfloat << x << endl; cout.width(12); double y = -11.222; //勾销指定的浮点数格局,按默认格局输入 cout << defaultfloat; //符号左对齐,数值右对齐,两头填充空格 cout << internal << y << endl; return 0; }输入后果如下: ...

April 29, 2021 · 1 min · jiezi

关于c++:C-命名空间

一、前言在理论的工作中,咱们不可能一人实现一个我的项目的开发工作,个别都是多人单干。多人单干实现我的项目的性能就可能会呈现变量或者函数的命名抵触。为了解决这个问题,C++ 引入了命名空间的概念。应用命名空间的目标是对标识符的名称进行本地化,以防止命名抵触。在中大型项目中,变量、函数、类、接口等都是大量存在的,如果不应用命名空间,那么这些名称都存在于全局命名空间中,能够引发很多意外的谬误。同理,如果一个我的项目中应用了多个第三方库,这些库中存在同名的变量、函数等,也会引发抵触。引入命名空间后,C++库就被定义到std命名空间中了。 二、阐明1、namespace关键字namespace关键字使得咱们能够通过创立作用范畴来对全局命名空间进行分隔。实质上来讲,一个命名空间就定义了一个范畴。定义命名空间的根本模式如下:namespace 名称{//申明}在命名空间中定义的变量、函数等都属于该命名空间。在命名空间中申明的标识符是能够被间接援用的,不须要任何的命名空间的修饰符,如域解析操作符::。雷同的命名空间名称是能够被屡次申明的,是互相补充的关系。命名空间也能够进行嵌套,即可在一个命名空间外部申明另一个命名空间。 2、域解析操作符命名空间中的变量等的作用范畴被局限在命名空间内,那么内部项应用应该怎么应用呢?这就须要域解析操作符了。一般来讲,在命名空间之外想要拜访命名空间外部的成员须要在成员后面加上命名空间和域解析操作符::。如果申明了类型的对象,那就没有必须在对该对象的任何成员应用域解析操作符::了。3、using关键字这个关键字的作用次要是简化应用域解析操作符指定命名空间的变量等。命名空间简略还好,如果比较复杂,每个成员都应用域解析操作符指定命名空间是一件很麻烦的事。因而引入了using关键字。如下: using namespace 命名空间名称; ①using 命名空间名称::成员; ②①形式将指定命名空间中的所有成员都引入到以后范畴,也就是将其变成以后命名空间(默认是全局命名空间)的一部分,应用的时候就不须要域解析操作符了。②形式让指定的命名空间中的指定成员在以后范畴中变为可见 4、未命名的命名空间简略的说,就是没有名称的命名空间。 namespace{ //申明}这种没有命名的命名空间只有在申明它的文件中才是可见的,即:只有在申明其的文件中,它的成员才是可见的,能被间接应用的。 5、std命名空间次要是C++库的定义,为了咱们在应用相干C++库变量、函数时简化。在引入命名空间之前,代码是没有应用命名空间的,为了兼容这种状况,保留了一份原来的库和头文件,同时将原来的库和头文件赋值一份,在这个根底上批改一些内容,放入std命名空间中,就成了C++的规范库,这样性能类似的库就存在了2份,不影响原有的我的项目。为了防止头文件重名,新版的C++库对头文件的命名去掉了后缀.h,如iostream,而原来C语言的头文件则在文件名前减少一个"c"字母,如cstdio。对于不带.h的头文件,所有的符号都位于命名空间 std 中,应用时须要申明命名空间 std;对于带.h的头文件,没有应用任何命名空间,所有符号都位于全局作用域。然而因为大部分编译器在实现时并没有严格遵循C++规范,导致程序员在代码实现时使不应用std,都能编译胜利。倡议:①代码实现时最好加上命名空间②最好在函数外部应用命名空间,防止抵触 三、总结1、命名空间将具备彼此关联的项归类在同一个命名空间,通过命名空间反馈性能,形成具备高内聚低耦合、模块性很强的命名空间。2、避免命名抵触,仅对编译器有用,对代码可读性没什么作用3、限度作用域在本文件,相似static的作用,没有命名的命名空间4、暗藏具体实现细节

April 29, 2021 · 1 min · jiezi

关于c++:堆与二叉树

堆什么是堆(用数组实现的二叉树)通过有序的key存储value的数据结构依据程序分为大顶堆和小顶堆通常用来实现优先级队列priority_queue(topk)二叉堆key存在二叉树的节点中key必须是可排序的具备堆属性,例如在最大堆中,父节点的值比每一个子节点的值都要大get maximum: O(1) (constant time)remove maximum: O(log N) (logarithmic time)insert: O(log N)increase key: O(log N)用数组示意二叉树满二叉树 共2^h-1个节点齐全二叉树能够被数组示意(Almost full binary trees) ,2^(h-1) -1 ~ 2^h -1 个节点 left_child_index(p) = 2 * p + 1right_child_index(p) = 2 * p + 2堆操作(c++用相似数组的容器示意)cmp 默认是 <make_heap(@b, @e, cmp):将键序列从新排序为二进制堆push_heap(@b, @e, cmp):插入一个新密钥pop_heap(@b, @e, @cmp):删除最大值sort_heap(@b, @e, @cmp):堆→排序数组is_heap(@b, @e, @cmp): 判断是否是heap如果只须要一个优先级队列,应用std::priority_queue

April 29, 2021 · 1 min · jiezi

关于c++:大数相关大数相加相除比较

大数相加(如911111111111111111111111这种数)//#include<iostream>//#include<algorithm>//#include<string>//#include<string.h>//#include<cstdio>//#include<queue>//#include<stack> //#include<set>//#include<map> //#include<vector> //using namespace std;//struct node{// int number[1005];// int len;//}a,b,ans;//a代表第一个大数,b代表第二个大数,ans代表要求得大数的和//char s[1005];//定义一个字符数组(相当于一个字符串(\0结尾)) //int main(){// int i =0;// scanf("%s",s);//把每个数字当做字符串输出 // a.len = (int)strlen(s);// memset(a.number,0,sizeof(a.number));// for(i = 0; i < a.len; i++){// a.number[i] = s[a.len - i - 1] - '0';//将数组倒位赋值给a.number列竖式相加(个位放后面作为第一个,前面顺次倒序) // } // scanf("%s",s);// b.len = (int)strlen(s);// memset(b.number,0,sizeof(b.number));// for(i = 0; i < b.len; i++){// b.number[i] = s[b.len - i - 1] - '0';//将数组倒位赋值给b.number列竖式相加(个位放后面作为第一个,前面顺次倒序) // }// memset(ans.number,0,sizeof(ans.number));// for(i = 0; i < max(a.len,b.len); i++){// ans.number[i] = a.number[i] + b.number[i];//倒位相加:将数a.number与b.number列竖式相加(个位放后面作为第一个,前面顺次倒序相加) // }// for(i = 0; i < max(a.len,b.len) || ans.number[i]; i++){//如果呈现相加后后果>=10,须要进位// // ans.number[i]条件是当最初一位>= 10依然须要向后进一位时,此时i不满足< max(a.len,b.len)// //则用该条件让i++能够继续执行一遍,以便前面输入时不会少一位(仍放弃len-1为最初一位) // //只有最初一位%10 != 0,(如最初一位11 % 10 = 1) // if(ans.number[i] >= 10){// ans.number[i + 1] += ans.number[i] / 10;//原本应该向前进位,当初倒位,故i向i + 1处进位,进的数是num[i]/10的后果,如num[i] = 17时,需向i+1位进17/10 = 1 // ans.number[i] %= 10;//进完位后num[i]自身也只剩下其个位,如17向后退1,而后本人变成7// }// } // ans.len = i;// for(i = ans.len - 1; i >= 0; i--){// printf("%d",ans.number[i]);//因为是倒位相加,所以倒序输入 // }// printf("\n");// return 0; //} ...

April 28, 2021 · 2 min · jiezi

关于c++:简单计算器字符数字转化

简略计算器读入一个只蕴含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。Input测试输出蕴含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输出完结,相应的后果不要输入。Output对每个测试用例输入1行,即该表达式的值,准确到小数点后2位。Sample Input1 + 24 + 2 * 5 - 7 / 110Sample Output3.0013.36 //#include<iostream>//#include<algorithm>//#include<string>//#include<string.h>//#include<cstdio>//#include<queue>//#include<stack> //#include<set> //#include<vector> //using namespace std;//int main(){// double num;// stack<double> st;// while(cin >> num){// char ch;// ch = getchar();//吃掉第一个数前面空格// if(ch != ' ' && num == 0){//如果第一个数前面什么都没有,空格也没有,证实只有1 个零完结循环 // break; // }// st.push(num);// double n;// char c,s;// while(scanf("%c %lf%c",&c,&n,&s) != EOF){//把第一个数前面四位(空格也算)当做一个整体,一直循环输出 // if(c == '+'){// st.push(n);// }else if(c == '-'){// st.push(-1*n);//把负号与数一起入栈,这样就都为正,前面要计算栈外面的值只用相加就行 // }else if(c == '*'){// st.top() *= n;//将栈顶元素与以后输出的值相乘,而后作为新的栈顶元素 // }else if(c == '/'){// st.top() /= n;// } // if(s != ' '){//如果最初一位不是空格(空或换行符'\n'),阐明数据输出实现,完结循环 // break;// }// }// double sum;// sum = 0.00;// while(!st.empty()){// sum += st.top();//将栈中各个元素从栈顶开始相加并出栈// st.pop(); // }// printf("%.2f\n",sum);// }// return 0;//} ...

April 28, 2021 · 2 min · jiezi

关于c++:类和对象

一、前言1、什么是类?在生活中,咱们能够依据事物的个性,将事物进行演绎分类,比方:我、你和她,属于人类;葡萄、枇杷、苹果属于水果等。在代码世界中,也能够将一些有共性的货色抽取进去并实现,这就是C++ 中的类。在C++中,把属性和办法进行封装,同时对属性和计划进行访问控制的数据类型就是类,类是形象的。对类的不同成员设置不同的拜访权限就是进行类的封装,这样能够加强安全性和简化编程,使用者能够不用理解具体的实现细节,间接通过内部接口,以特定的拜访权限应用性能。 2、什么是对象?对象是依据类创立的,申明类的对象和申明根本类型的变量是一样的 二、具体阐明1、类的定义class 类名{public: //成员函数或数据成员的申明protected: //成员函数或数据成员的申明private: //成员函数或数据成员的申明};类的定义能够看成是类的内部接口,定义在.h文件中;类成员函数的定义能够看成类的外部实现,个别写成.cpp文件。成员函数的定义如下: 返回值 类名::函数名(参数列表){ 函数体 return 返回类型值;}如果函数的后面没有类名::时,编译器会认为这是一个一般函数,因为没有阐明这个函数是哪一个类的;类名::同时也阐明了函数的作用域,在类作用域中,一个类的成员函数对同一个类的数据成员具备无限度的拜访权限。 2、类的初始化在申明类的时候不能间接对数据成员进行初始化,因为类是一种形象的类型,不占有空间。如: class CTest{public: int nTime = 1; bool bFlag = false;};类中的所有成员都是public类型的,能够在定义类对象时对数据成员进行初始化,如: class CTest{public: int nTime; bool bFlag;};CTest t1={1,false};在类的构造函数中进行数据成员的初始化,构造函数是一种非凡的成员函数,不须要用户调用,在建设对象时主动执行。分为2种:在类内定义构造函数或者在类内申明,类外定义。在建设对象的时候会为该对象调配存储单元,再执行构造函数,就会把指定的初值设置到对应数据成员的存储单元。构造函数没有返回值,没有类型,只是对对象进行初始化。能够应用一个类对象初始化另一个对象,复制作用,这样就不必再次调用另一个类的构造函数。

April 28, 2021 · 1 min · jiezi

关于c++:链表专题士兵队列训练问题

某部队进行新兵队列训练,将新兵从一开始按程序顺次编号,并排成一行横队,训练的规定如下:从头开始一至二报数,凡报到二的入列,剩下的向小序号方向聚拢,再从头开始进行一至三报数,凡报到三的入列,剩下的向小序号方向聚拢,持续从头开始进行一至二报数。。。,当前从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。Input本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。Output共有N行,别离对应输出的新兵人数,每行输入剩下的新兵最后的编号,编号之间有一个空格。Sample Input22040Sample Output1 7 191 19 37 #include<iostream>#include<algorithm>#include<string>#include<string.h>#include<cstdio>#include<queue>#include<stack> #include<set> #include<map>#include<list>#include<cstdio>using namespace std;//#include<bits/stdc++.h>//万能头文件 int main(){ int t = 0, n = 0; cin >> t; while(t--){//测试组数 cin >> n;//士兵人数 int k = 2;//删除规定的距离数,初始为2 2,3交替 list<int >blist;//创立一个空链表 list<int >::iterator it;//创立一个list迭代器 for(int i = 1; i <= n; i++){//从地位1开始给链表赋初值 blist.push_back(i); } while(blist.size() > 3){//保留最初3个元素 int num;//报数的人 num = 0; for(it = blist.begin();it != blist.end();){//因为找到后要间接删掉链表对应的值,用迭代器遍历 // if(num++ % k == 0){// num++; if(num % k == 0){//这种写法得不出正确答案 it = blist.erase(it);//删除该满足条件的指定元素 }else{ it++;//不能删除的过,it须要自增,要不是死循环 } } if(k == 2){//实现2,3转换 k = 3; continue; }else{ k = 2; continue; } } for(it = blist.begin(); it != blist.end(); it ++){//依照格局遍历剩下的三个数 if(it != blist.begin()){ cout << " "; } cout << *it; } cout << endl; } return 0;} ...

April 28, 2021 · 1 min · jiezi

关于c++:全排列生成BI-生成序列基础上机试题

在计算机科学畛域,如何高效生成指定的序列是一个十分重要的问题。当初给你一个字符串,且这个字符串外部的字符曾经升序有序。请你找出由这些字符形成的所有的序列。输出输出的第一行是一个整数n,示意测试数据组数。接下来n行,每行输出一个字符升序有序的字符串。字符串中只蕴含小写字母,长度不超过8。输入对于每组输出,输入由输出的字符串中的字符形成的所有序列,按字典序升序排列,后果中不能呈现雷同的序列。每组输入前面跟一个空行。样例输出 Copy3ababcbca样例输入 Copyabba abcacbbacbcacabcba abcacbbacbcacabcba next_permutation用法参考https://blog.csdn.net/ac_gibs... //#include<iostream>//#include<string>//#include<string.h>//#include<algorithm>//#include<cstring>//using namespace std;////int main(){// int t = 0;// scanf("%d",&t);// while(t--){// string s;// cin >> s;// if(s.length() <= 8){// sort(s.begin(),s.end());// do//全排列 // {// cout<< s <<endl;// }while(next_permutation(s.begin(),s.end()));// cout << endl;// } // }// return 0;//}////求字符循环流动的算法如下 ////void change(string &s) { //在while循环中会不停调用此函数不停变换短串s2//// char t;//// int i;//// t = s[0];//用哨兵暂存储第一个字符//// for(i = 0; i < s.length() - 1; i++) { //不要超界//// s[i] = s[i + 1];//将前面的字符赋值给后面,不停实现轮换以测验变换后的多个s2......是否会在s1中呈现//// }//// s[i] = t;//将哨兵中的字符赋值给字符串最初一个地位////}////排序形式能够为疾速排序,这里写一遍快排(严蔚敏)////void Quick_Sort(int a[], int low, int high){//// if(low < high){//// int pivot = Partiton(a, low, high);//// Quick_Sort(a, low, pivot - 1);//// Quick_Sort(a, pivot + 1, high);//// }////} ////int Partiton(int a[], int low, int high){//// int pivot = a[low];//// while(low < high){//// while(low < high && a[high] >= pivot){//// --high;//// }//// a[low] = a[high];//// while(low < high && a[low] <= pivot){//// ++low;//// }//// a[high] = a[low];//// }//// a[low] = pivot;//// return low;////} ...

April 28, 2021 · 1 min · jiezi

关于c++:递推专题BE-贴瓷砖-BF-统计方案BG-小明养猪的故事BH-小明的烦恼

本局部有点找法则的感觉,找到数学法则表达式就很容易实现这类题目,所以遇到递推不要急着写代码,先把法则找到! 有一块大小是 2 n 的墙面,当初须要用2种规格的瓷砖铺满,瓷砖规格别离是 2 1 和 2 * 2,请计算一共有多少种铺设的办法。输出输出的第一行蕴含一个正整数T(T<=20),示意一共有T组数据,接着是T行数据,每行蕴含一个正整数N(N<=30),示意墙面的大小是2行N列。输入输入一共有多少种铺设的办法,每组数据的输入占一行。样例输出 Copy32812样例输入 Copy31712731 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<algorithm>//#include<string>//#include<string.h>//using namespace std;////int main(){// int t = 0;// scanf("%d",&t);// long long a[30];// a[1] = 1;// a[2] = 3;// while(t--){// int n = 0;// scanf("%d",&n);// for(int i = 3; i <= n; i++){// a[i] = a[i - 1] + 2 * a[i - 2];// }// cout << a[n] << endl;// }// return 0;//} 在一无限大的二维立体中,咱们做如下假如:1、每次只能挪动一格;2、不能向后走(假如你的目的地是“向上”,那么你能够向左走,能够向右走,也能够向上走,然而不能够向下走);3、走过的格子立刻塌陷无奈再走第二次。求走n步不同的计划数(2种走法只有有一步不一样,即被认为是不同的计划)。输出首先给出一个正整数C,示意有C组测试数据。接下来的C行,每行蕴含一个整数n(n<=20),示意要走n步。输入请编程输入走n步的不同计划总数;每组的输入占一行。样例输出 Copy212样例输入 Copy37 ...

April 28, 2021 · 2 min · jiezi

关于c++:BD-字符串最小表示基础上机试题

把一个长为len的字符串围成一个圈,而后以任意一个字符作为终点,都会产生一个长为len的字符串,字符串的最小示意就是所有字符串中字典序最小的那个。例如字符串alabala,将它围成一个圈后,依据下面的规定会造成以下新的字符串:labalaaabalaalbalaalaalaalablaalabaaalabal在这所有7个字符串中,字典序最小的是aalabal,它的第一个字母在原字符串中的地位是6。(地位从0开始算)当初给定你一个字符串,请你找出其最小示意的第一个字母在原字符串中的地位。如果字符串最小示意有多个,那么输入第一个字母在原字符串中地位最小的。 输出输出的第一行是一个整数t,示意有t组测试数据。接下来t行,每行先输出一个整数l(5<=l<=100000),示意原字符串的长度,而后输出一个字符串,示意原字符串。字符串中只蕴含小写字母。输入对于每组输出,输入原字符串最小示意的第一个字母在原字符串中的地位。样例输出 Copy26 baabaa7 alabala样例输入 Copy16 参考https://www.cnblogs.com/CHAHA... &&https://www.cnblogs.com/jiami... //#include<iostream>//#include<algorithm>//#include<string>//#include<string.h>//using namespace std;//int min_string(char s[]);////int main(){// int t = 0;// char s[100001];// int m = 0;// scanf("%d",&t);// while(t--){// scanf("%d %s",&m,s);// printf("%d\n",min_string(s));// }// return 0;//}////int min_string(char s[]){// int i = 0,j = 1,k = 0;// int n = strlen(s);// while(i < n && j < n && k < n) {//i+k或j+k能够超过len,但i,j,k自身不行,k>=len阐明曾经比照全副(循环一轮) // if(s[(i + k) % n] == s[(j + k) % n]){//此处取余相似于循环队列取下标 // k++;// }else if(s[(i + k) % n] < s[(j + k) % n]) {// j = j + k + 1;//i不动,j间接到j+k+1 // k = 0;// }else {// i = j;//i到j之间的字符均大于i故间接跳到j // j = i + k + 1;// 同上 // k = 0;// }// }//// cout << i << endl;// return min(i,j); //}// ...

April 28, 2021 · 1 min · jiezi

关于c++:cms

讲下 C++ 里虚函数虚函数表 虚函数表指针 函数指针 动静绑定 基类指针指向派生类对象这些,还有接口设计方面在 C++ 外面构造体和类的区别默认拜访权限 + 一点其它本人的应用感觉用过智能指针吗,能不能介绍下它解决的问题和你应用的教训?首先讲了裸指针生命周期治理的艰难,内存透露、野指针这些而后讲了智能指针是如何利用 RAII 来解决的,而后顺便提了那几个智能指针区别讲了本人我的项目中如何利用 shared_ptr 的,还有如何用 weak_ptr 解决环形援用的方才你提到内存透露,那你是如何在 debug 发现或者是定位内存透露的呢?讲了下 Valgrind 套件下的 memcheck那前面用了智能指针之后你再去跑内存透露有缩小吗?嗯,工具检测没有内存透露产生了能够讲下树的深度遍历和广度遍历前 中 后 用栈或者递归档次 用队列讲一下 hash 表具体讲了下 STL unordered_map 底层那哈希表抵触怎么解决?线性探测和平方探测,说了这两个有主汇集和次汇集毛病大多数语言 map 用的是开链法如何判断链表是否有环?说了用 set 和快慢指针两种

April 28, 2021 · 1 min · jiezi

关于c++:c中ifstream及ofstream超详细说明

前文说过,ifstream是继承于istream,ofstream是继承于ostream,fstream是继承于iostream类,而他们应用的缓冲区类是filebuf。 对于这些类之间的关系,有趣味能够去查看我之前的文章:c++规范输入输出流关系梳理 1. filebuf类介绍filebuf类又比stringbuf类要简单一点,毕竟是对文件进行读写,首先在它的成员变量中找到了这样一条申明: __file_type _M_file;_M_file就是它外面的文件操作对象,那么探索一下__file_type到底是什么类型呢,通过跟代码发现它其实是一个类模板__basic_file的char实例,而__basic_file是围绕一个FILE类型的指针来进行操作的,而FILE这个类型大家其实就很相熟啦,它是c语言规范库外面操作文件的规范类型,个别是叫做文件指针,所以从这里就能够看出filebuf最终其实还是基于c语言的fopen等这一套文件操作函数去进行解决的。当然啦,在linux外面fopen其实又是基于它的零碎调用open函数来进行的,这个咱们晓得就好,就不再做开展啦。 当看到fopen的调用时,其实心田是挺惊喜的,因为fstream这一套货色以前也常常应用,然而呢,从来不晓得它的底层到底是怎么实现的,这次总算是晓得了一点。 1.1 filebuf类构造函数和析构函数首先看一下filebuf的构造函数原型,如下: //这里申明了一个无参构造函数basic_filebuf();#if __cplusplus >= 201103L basic_filebuf(const basic_filebuf&) = delete;//这里申明了一个入参为右值援用的挪动构造函数,所谓右值援用,它容许内容从一个filebuf对象挪动到另外一个filebuf对象,挪动实现当前,源filebuf对象将被销毁,不能再被应用,它没有产生任何拷贝的动作 basic_filebuf(basic_filebuf&&);#endif#if __cplusplus >= 201103L basic_filebuf& operator=(const basic_filebuf&) = delete;//同上,这里申明了一个挪动赋值函数 basic_filebuf& operator=(basic_filebuf&&);#endif//析构函数敞开文件virtual ~basic_filebuf() { this->close(); }小贴士:=delete是c++11的用法,在c++11以前要避免类对象被拷贝和赋值,就要把拷贝构造函数和赋值函数申明为private的,到了c++11就间接应用=delete来进行申明,它意味着这个函数不能被调用,否则编译就会报错。从下面咱们能够看到filebuf类是不容许拷贝和赋值的,否则可能会产生多个对象操作同一个IO缓冲,就会导致诸多的问题,它只容许进行挪动,这样能保障任何时候同一个IO缓冲只有一个对象能够操作。 应用例子如下: #include <fstream>using namespace std;int main(){ filebuf buf; filebuf buf2(move(buf));//挪动构造函数,std::move用于生成一个绑定在buf上的filebuf&& filebuf buf3 = move(buf);//挪动赋值函数 return 0;}1.2 open函数函数原型如下: //is_open用于判断文件是否是关上状态,返回true则示意文件是关上状态,否则就是敞开状态 bool is_open() const throw() { return _M_file.is_open(); }//__s示意文件名,__mode示意文件打开方式 __filebuf_type* open(const char* __s, ios_base::openmode __mode);#if __cplusplus >= 201103L//同上,只是文件名应用了string示意而已 __filebuf_type* open(const std::string& __s, ios_base::openmode __mode) { return open(__s.c_str(), __mode); }#endif//敞开文件 __filebuf_type* close();应用案例如下: ...

April 28, 2021 · 2 min · jiezi

关于c++:BC-字符串匹配1基础上机试题

给你一个字符串A和一个字符串B,请你计算字符串B的所有旋转模式在字符串A中的呈现总次数。阐明:如果将字符串B形容成B1B2...Bm的模式(m是B的长度),那么B1B2...Bm-1Bm,B2B3...BmB1,...,BmB1...Bm-2Bm-1就是字符串B的所有旋转模式。输出输出蕴含多组测试数据。每组输出为两行,第一行输出字符串A,第二行输出字符串B。A的长度不超过1000,B的长度不超过100,所有字符串仅蕴含小写字母。输入对于每组输出,输入字符串B的所有旋转模式在字符串A中的呈现总次数。样例输出 Copyabababaaaaaaaaaaa样例输入 Copy343 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//#include<cstring>//using namespace std;//void Find(int i, int n, string &s1,string &s3);//void change(string &s);////int main() {// string s1,s2 = "",s3 = "";// while(getline(cin,s1)) {// cin >> s2;// getchar();//// s3.resize(101);// int n = s2.length();// int k,cnt = 0;// for(int i = 0; (i + n - 1) < s1.length(); i++) {// k = 0;//管制while循环次数,change一遍后break,要不会有限循环!每次i变动后置零// Find(i,n,s1,s3);//利用函数Find()提取s1[]中的子串赋给s3[]//// cout << s3 << endl; 调试用//// while(strcmp(s2.c_str(),s3.c_str()) != 0){// while(s2 != s3) {// change(s2);//该函数使短串变换,并让每次变换后的s2持续与S3进行比拟,看是否相等// k++;//记录翻转次数// if(k >= n) { //管制change次数,change一轮后退出,不要有限循环// break;// }// }//// if(strcmp(s2.c_str(),s3.c_str()) == 0){//两者相等,则呈现一次// if(s2 == s3) {// cnt++; //计数// }// s3.clear();//每次i变换即进行过一次Find函数都要把s3重置,以从新获取s1的子串。// }// cout << cnt << endl;// }// return 0;//}//void Find(int i,int n, string &s1,string &s3) { //此处需将i和n的值都传入函数// int k,l;// for(k = i,l = 0; k < i + n; k++,l++) { //因为在一次接管输出后n不变,而i在for循环中为了管制s1(即长串) 不超限在递增// //故引入k使得k < i +n(而不是间接k < n),则每次循环也可循环n次,给s3[]赋值n次,与将要比照的s2[]长度相等// s3 += s1[k];//当i = 0时,使得s1得前n个字符(从s[i]开始)赋值给s3 ,前面需随着i变动同理提取长串中的相邻字符(引入i的起因)//// s3[l] = s1[k]; //切记这么赋值是谬误的,尽管能够提前开拓s3的空间(下面的s3.resize()),然而会多一个空行// }//}////void change(string &s) { //在while循环中会不停调用此函数不停变换短串s2// char t;// int i;// t = s[0];//用哨兵暂存储第一个字符// for(i = 0; i < s.length() - 1; i++) { //不要超界// s[i] = s[i + 1];//将前面的字符赋值给后面,不停实现轮换以测验变换后的多个s2......是否会在s1中呈现// }// s[i] = t;//将哨兵中的字符赋值给字符串最初一个地位//} ...

April 27, 2021 · 2 min · jiezi

关于c++:BB-统计回文子串基础上机试题

当初给你一个字符串S,请你计算S中有多少间断子串是回文串。输出输出蕴含多组测试数据。每组输出是一个非空字符串,长度不超过5000。输入对于每组输出,输入回文子串的个数。样例输出 Copyabaaa样例输入 Copy43 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//using namespace std;////int main(){// string s;// while(getline(cin,s)){// int len = s.length();// int i,left = 0,right = 0;// int cnt = len;// for(i = 0; i < len; i++){// left = i - 1;//隔了一个字符对称的两个字符进行比拟 // right = i + 1;// while(left >= 0 && right < len){// if(s[left] == s[right]){//与相隔一个字符对称的进行比拟(XYX型,比拟两个XX) ,看是否相等,相等则回文子串加1 // ++ cnt;// -- left;// ++ right;//若合乎则向两边扩散,看更长的子串(隔着3个Y,AXYXA)的两边两个A是否相等,直到越界,相等就加1 // }else{// break;// }// }// left = i - 1;//左右相邻的两个字符进行比拟 // right = i;// while(left >= 0 && right < len){// if(s[left] == s[right]){//与相邻字符进行比拟(XX型,比拟两个XX) ,看是否相等,相等则回文子串加1 // ++ cnt;// -- left;// ++ right;//同上,若合乎向两边扩散(AXXA),看两个边A是否相等,直到遍历残缺个字符串 // }else{// break;// }// }// }// cout << cnt << endl;// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:BA-幂字符串基础上机试题

给你一个字符串,请你判断将此字符串转化成a^n模式的最大的n是多少。例如:abcd=(abcd)^1,则n=1; aaaa=a^4,则n=4; ababab=(ab)^3,则n=3。输出输出蕴含多组测试数据。每组输出为一个字符串,长度不超过100,其中不蕴含空格等空白符。当输出为一个“.”时,输出完结。输入对于每组输出,输入将此字符串转化成a^n模式的最大的n。样例输出 Copyabcdaaaaababab.样例输入 Copy143 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//using namespace std;////int main(){// string s;// while(getline(cin,s)){// int len = s.length();// int i = 0, j = 0, cnt = 0;// if(s[0] == '.' && len == 1){// break;// }// for(i = len; i >= 1; i--){//i作为分母,不能为0(len / i )// if(len % i == 0){//示意可能有len/i个子串组成,不能整除length的先排除 // for(j = i; j < len; j++){//第二个for循环判断该子串是否是循环相等的 // if(s[j] != s[j % i]){//一一比照子串与后续等同长度的字符是否一样 // break;//,相等就j++,不相等就break,阐明目前并不是符合条件的小子串// } // }// cout << j << endl; // if(j == len){//如果上述循环未break则此时该i子串符合条件 // cnt = len / i; //用长度除以子串长度,即失去此时的子串,但此时可能并不是最短的即最多的子串,i持续减少可能能失去更小的子串 // }// }// }// cout << cnt << endl; // } // return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:括号匹配算法基础上机试题

给定一个只包含 '(',')','{','}','[',']' 的字符串,判断字符串是否无效。无效字符串需满足: 1. 左括号必须用雷同类型的右括号闭合。2. 左括号必须以正确的程序闭合。3. 留神空字符串可被认为是无效字符串。//#include <algorithm>//#include <cmath>//#include <iostream>//#include <map>//#include <queue>//#include <stack>//#include <string>//#include <string.h>//#include <vector>//using namespace std;//bool Ispair(char a, char b);// //int main(){// string s = "";// while(getline(cin, s)){// if(s.empty()){// cout << "true" <<endl;// continue;// }else{// stack<char> st;// st.push(s[0]);// for(int i = 1; i < (int)s.size(); i++){// if(!st.empty() && Ispair(st.top(),s[i])){// st.pop();// }else{// st.push(s[i]);// }// }// if(st.empty()){// cout << "true" << endl;// }else{// cout << "false" << endl;// }// }// }// return 0; //}////bool Ispair(char a, char b){// if(a == '(' && b == ')'){// return true;// }// if(a == '[' && b == ']'){// return true;// }// if(a == '{' && b == '}'){// return true;// }// return false;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AZ-相对分子质量基础上机试题

小明最近迷上了化学,简直天天在实验室做试验,然而很多试验生成的化学产物的绝对分子品质令他很困惑,不知如何计算,请你编程帮他计算。输出输出的第一行是一个正整数n,示意有n组测试数据。接下来n行每行输出一个字符串,示意某个分子式,分子式中只蕴含大写字母和数字。留神:输出数据只蕴含8种元素,而这8种元素的绝对原子质量如下:H(1),C(12),N(14),O(16),F(19),P(31),S(32),K(39)。输入对于每组输出,输入绝对分子品质。样例输出 Copy4H2OKOHCH4SO2样例输入 Copy18561664 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//using namespace std;////int main(){// int a[] = {1,12,14,16,19,31,32,39};// char b[] = "HCNOFPSK";// int n = 0,sum = 0;// char s[100];// scanf("%d",&n);// getchar();// while(n--){// scanf("%s",s);// for(int i = 0; i < strlen(s); i++){// int t = 0,c = 0;// for(int j = 0; j < 8; j++){// if(s[i] == b[j]){// c = a[j];// break;// }// }// while((s[i + 1]) <= '9' && s[i + 1] >= '0'){//如果前面跟有字符型数字,计算数字的值 // t = t * 10 + s[i + 1] - '0';// i++;//循环增,遍历其后所有数字(若还有) // }// if(t == 0){//证实s[i]前面的s[i + 1]不是0-9,而是字母元素 // sum += c; // }else{// sum += c * t; // }//// printf("%d\n",sum); // }// printf("%d\n",sum);// sum = 0;// } // return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AY-破译邮件基础上机试题

小明收到了一封很奇怪的邮件,外面全是一些符号和数字,然而信下面给出了破译办法,具体方法如下:(1)将1变为‘A’,2变为‘B’,...,26变为‘Z’;(2)将‘#’变为一个空格;(3)疏忽‘-’,原始函件中‘-’仅仅用来宰割数字。现请你编程帮忙小明破译这封邮件。输出输出的第一行为一个整数C,示意测试数据的组数。接下来C行,每行输出一个待破译的字符串,字符串中只蕴含数字、‘-’和‘#’,长度不超过100。输入对于每组输出,输入破译后的文本。样例输出 Copy49#23-9-12-12#19-20-5-1-12#1-20#12-5-1-19-20#15-14-5#10-5-23-5-121-14-4#12-5-1-22-5#20-8-5#13-21-19-5-21-13#9-14#20#13-9-14-21-20-5-191-6-20-5-18#20-8-5#15-16-5-14-9-14-7#15-6#20-8-5#5-24-8-9-2-9-20-9-15-147-15-15-4#12-21-3-11样例输入 CopyI WILL STEAL AT LEAST ONE JEWELAND LEAVE THE MUSEUM IN T MINUTESAFTER THE OPENING OF THE EXHIBITIONGOOD LUCK 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string.h>//#include<cstdio>//#include<cstring>//#include<algorithm>//using namespace std;//int main()//{// int n = 0;// char s[101],a[101];// scanf("%d",&n);// while(n--){// int i = 0;// int j = 0;// scanf("%s",s);// for(; i < strlen(s); i++){// if(s[i] == '#'){// a[j] = ' ';// j++;// }else if((s[i] <= '9' && s[i] >= '1') && (s[i + 1] < '0'||s[i + 1] > '9')){// a[j] = s[i] - '0' + 64;// j++;// }else if((s[i] <= '9' && s[i] >= '1') && (s[i + 1] >= '0'&& s[i + 1] <= '9')){// a[j] = (s[i] - '0') * 10 + s[i + 1] - '0' + 64;// j++;// i++;//此时已胜利转化第i位和第i+1位为字符(同时转化了2位)故须要让下标i再后退一位 // }// }// a[j] = '\0';//不要遗记在新生成的字符串后补充开端字符'\0' // printf("%s\n",a);// } // return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AX-分割排序基础上机试题

输出一行数字,如果咱们把这行数字中的‘5’都看成空格,那么就失去一行用空格宰割的若干非负整数(可能有些整数以‘0’结尾,这些头部的‘0’应该被疏忽掉,除非这个整数就是由若干个‘0’组成的,这时这个整数就是0)。你的工作是:对这些宰割失去的整数,依从小到大的程序排序输入。输出输出蕴含多组测试数据。每组输出数据只有一行数字(数字之间没有空格),这行数字的长度不大于1000。 输出数据保障:宰割失去的非负整数不会大于100000000,输出数据不可能全由‘5’组成。输入对于每个测试用例,输入宰割失去的整数排序的后果,相邻的两个整数之间用一个空格离开,每组输入占一行。样例输出 Copy0051231232050775样例输入 Copy0 77 12312320 代码示例(本人写的,只能过平台,不完满) //#include <algorithm>//#include <iostream>//using namespace std;//#include <vector>//#include <stack>//#include <queue>//#include <cmath>//#include <string>//#include <string.h>////int main() {// int t = 0;//// cin >> t;//// getchar();// scanf("%d",&t);// getchar();//当输出之后接着要输出字符(串)变量时,须要用getchar()吃掉下面输出之后的空格 // while(t--){// int k = 0;// string str;// getline(cin,str);// for(int i = 0; i < str.size(); i++){// if(str[i] == ' ' ){// for(int j = i - 1; j >= k; j--){// cout << str[j];// }// cout << " ";// k = i + 1;// } // }// for(int l = str.size() - 1; l >= k; l--){// cout << str[l];// }// cout << endl;// }// return 0;//}给的标程是这样的,能够参考一下 ...

April 27, 2021 · 1 min · jiezi

关于c++:AW-字符串反转基础上机试题

小C很喜爱倒着写单词,当初给你一行小C写的文本,你能把每个单词都反转并输入它们吗?输出输出蕴含多组测试样例。第一行为一个整数T,代表测试样例的数量,前面跟着T个测试样例。每个测试样例占一行,蕴含多个单词。一行最多有1000个字符。输入对于每一个测试样例,你应该输入转换后的文本。样例输出 Copy3olleh !dlrowI ekil .bulcmcaI evol .mca样例输入 Copyhello world!I like acmclub.I love acm. 代码示例(本人写的,只能过平台,不完满) //#include <algorithm>//#include <iostream>//using namespace std;//#include <vector>//#include <stack>//#include <queue>//#include <cmath>//#include <string>//#include <string.h>////int main() {// int t = 0;//// cin >> t;//// getchar();// scanf("%d",&t);// getchar();//当输出之后接着要输出字符(串)变量时,须要用getchar()吃掉下面输出之后的空格 // while(t--){// int k = 0;// string str;// getline(cin,str);// for(int i = 0; i < str.size(); i++){// if(str[i] == ' ' ){// for(int j = i - 1; j >= k; j--){// cout << str[j];// }// cout << " ";// k = i + 1;// } // }// for(int l = str.size() - 1; l >= k; l--){// cout << str[l];// }// cout << endl;// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AV-字符串的奇偶性基础上机试题

咱们把只有0和1组成的字符串叫做比特字符串。如果比特字符串中1的个数为奇数,则称这个比特字符串是奇性的。如果比特字符串中1的个数为偶数,则称这个比特字符串是偶性的。留神:(1)0是偶数,所以不蕴含1的比特字符串是偶性的。(2)0的个数不影响比特字符串的奇偶性。输出输出蕴含多组测试数据。每组数据由1~31个0、1组成,最初跟一个小写字母e或o,e示意此比特字符串应为偶性,o示意此比特字符串应为奇性。当输出#时,示意输出完结。输入每组输出对应一个输入,你应该将最初的字母替换成0或1,使得此比特字符串合乎输出时确定的奇偶性。样例输出 Copy101e010010o1e000e110100101o 样例输入 Copy101001001011100001101001010 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//using namespace std;//#include <cstring>////int main(){// string str;// while(getline(cin,str)){// int k = 0;// if(str == "#"){// break;// }// for(int i = 0; i < str.size(); i++){// if(str[i] == '1'){// k++;// }// }// if(k % 2 == 0){// if(str[str.size() - 1] == 'e'){// //// str.pop_back();//删除str字符串最初一个字符//// str.push_back('0');//将字符‘0 ’拼接到str开端// str[str.size() - 1] = '0';// }else{//// str.pop_back();//删除str字符串最初一个字符//// str.push_back('1');//将字符‘0 ’拼接到str开端// str[str.size() - 1] = '1';// }// }else {// if(str[str.size() - 1] == 'o'){// //// str.pop_back();//删除str字符串最初一个字符//// str.push_back('0');//将字符‘0 ’拼接到str开端// str[str.size() - 1] = '0';// }else{//// str.pop_back();//删除str字符串最初一个字符//// str.push_back('1');//将字符‘0 ’拼接到str开端// str[str.size() - 1] = '1';// } // }// cout << str << endl;// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AU-晚餐基础上机试题

小明请好敌人们来家里吃晚饭,然而厨房里的餐具不够了,于是小明到仓库里找新餐具。仓库里的货色都是装在一个个箱子里,箱子下面写着外面装的什么货色,当初小明想请你帮忙找出这些装餐具的箱子。题目中的餐具只蕴含:碗(bowl),刀(knife),叉(fork),筷子(chopsticks)。输出输出蕴含多组测试数据。每组先输出一个整数N,示意仓库里有N个箱子。而后输出N个字符串,别离示意箱子里装的是什么货色。输入对于每组输出,输入仓库里所有餐具的名字。样例输出 Copy3 basketball fork chopsticks2 bowl letter样例输入 Copyfork chopsticksbowl 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//using namespace std;//int main(){// int n = 0;// char s[15];// char exm[4][15] = {"bowl","knife","fork","chopsticks"};//用二维数组存储一个字符串,一行就代表一个字符串!//// string s;//能够用C++的string //// string str[4] = {"bowl","knife","fork","chopsticks"};// while(cin >> n){// int count = 0;// while(n--){// scanf("%s",s);// for(int i = 0; i < 4; i++){// // if(s == exm[i]){C++外面的char类型不能间接比大小,而string类型对象则能够,如定义为string s; // if(!strcmp(s,exm[i])){//strcmp()是C语言函数,实用于char类型,如果想应用strcmp()比拟string类型,能够应用str.c_str()装换成char型 // count++;// if(count == 1){// printf("%s",s);// }else{// printf("%s",s);// }// }// }// }// printf("\n");// } // return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AT-讨厌的小数点基础上机试题

小明始终很厌恶小数点,一看到小数点就头疼。可怜的是,小红给他出了一个题目,问他:给你一个小数x,你能算出小数点后第n位是什么吗?(1<=n<=6)小明看到此题后,霎时头疼晕倒,你能帮帮他吗?输出首先输出一个t,示意有t组数据,跟着t行:每行输出一个小数(输出数据保障肯定是a.b的模式,为了简单化问题,没有循环小数的状况),而后跟一个n,示意小数点后第几位。输入输入一个数示意小数点后第n位的数。样例输出 Copy31.234 12.345 23.456 3样例输入 Copy246 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<cstring>//#include<string.h>//#include<cmath>//using namespace std;////int main(){// int t = 0;// int flag = 0;// scanf("%d",&t);//// char s[100];// string s;// while(t--){// int n = 0;//// scanf("%s %d",&s,&n);// cin >> s >> n;// for(int i = 0; i < s.size(); i++){// if(s[i] == '.'){// flag = i;// break;// }// }// if((flag + n) < s.size()){//// printf("%c\n",s[flag + n]);//应用string时,尽量不要用scanf输出和printf输入 // cout << s[flag + n] <<endl;//此题学习到,string类型变量与cin和cout 对应,而char[] 与scanf("%s"),printf对应 // }else{//// printf("0\n");// cout << "0" << endl;// }// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AS-字母概率基础上机试题

小明最近对概率问题很感兴趣。一天,小明和小红一起玩一个概率游戏,首先小明给出一个字母和一个单词,而后由小红计算这个字母在这个单词中呈现的概率。字母不辨别大小写。例如,给定的字母是a,单词是apple,那么概率是0.20000。输出输出蕴含多组测试数据。每组数据蕴含一个字母和一个单词。单词的长度不超过200。输入对于每一个输出,输入对应的概率,后果保留5位小数。样例输出 Copya applec Candya banana样例输入 Copy0.200000.200000.50000 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// char ch;// string s;// while(cin >> ch >> s ){// int count = 0;// for(int i = 0; i < s.size(); i++){// if(ch == toupper(s[i]) || ch == tolower(s[i])){// count ++;// }// }// double t = count * 1.0/ s.size();// printf("%.5f\n",t);// }// return 0;//}

April 27, 2021 · 1 min · jiezi