关于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:单链表的基本操作c语言章节实验作业

单链表的基本操作(c语言)——章节试验作业#include<stdio.h>#include<stdlib.h>#include<string.h>#include<windows.h>#include<stdbool.h>typedef char ElemType;typedef struct node{ ElemType data; struct node* next;}Node, *LinkList;void Show_meau() //菜单{ printf("**********************************\n"); printf(" WELCOME!\n"); printf("\n"); printf("\t单链表的基本操作\n\n"); printf(" \t 1.查问\t 2.插入\n\n"); printf(" \t 3.删除\t 4.打印\n\n"); printf(" \t 5.计数\t 6.销毁\n\n"); printf(" \t 7.退出\t 8.建表\n\n"); printf("\n"); printf(" 输出相干序号实现相干性能!\n"); printf("**********************************\n");}void InitList(LinkList *L){ *L = (LinkList)malloc(sizeof(Node)); (*L)->next = NULL;}void Create_List(LinkList L) //尾插法{ ElemType c; Node* r, * s; bool flag=true; r = L; printf("提醒:输出$示意建表完结!\n"); while (flag==true) { c = getchar(); if (c != '$') { s = (LinkList*)malloc(sizeof(Node)); s->data = c; r->next = s; r = s; } else { flag = false; r->next = NULL; } } printf("建表实现!\a"); Sleep(2000);}void Search(LinkList L){ int flag=1; Node* p; ElemType e; getchar(); //排汇换行符 p = L->next; printf("请输出要查找的值:"); e = getchar(); while (p != NULL) { if (p->data != e) p = p->next; else { printf("该地址为:%p\n", p); printf("输出0退出!\n"); scanf("%d", &flag); break; } } if (flag == 0) return; printf("查无此值!\a"); Sleep(2000);}void DispList(LinkList L){ int n; LinkList p = L->next; if (p == NULL) { printf("表为空!\a"); Sleep(2000); return; } printf("打印值为:\n"); while (p != NULL) { printf("%c", p->data); p = p->next; } printf("\n\n"); while (1) { printf("输出0退出打印!\n"); scanf("%d", &n); if (n == 0) return; else printf("输出有效,请从新输出!\n"); }}int ListLength(LinkList *L){ int n = 0; LinkList p = L; if (p->next == NULL) { printf("表为空!\a\n"); Sleep(2000); return; } while (p->next != NULL) { n++; p=p->next; } n--; return n;}void Print_Length(LinkList L){ int n = 1; while (1) { if (n == 1) { printf("表长为:%d\n", ListLength(L)); printf("输出0退出打印!\n"); scanf("%d", &n); } if (n == 0) return; }}void ListInsert(LinkList L){ int i,j=0; ElemType e; LinkList p = L, s; if (p->next == NULL) { printf("表为空!\a\n"); Sleep(2000); return; } printf("以后表长为:%d\n", ListLength(L)); //留神指针L while (1) { printf("请输出插入的地位:"); scanf("%d", &i); if (i <= 0 || i > ListLength(L)) { printf("输出谬误!请从新输出!\n"); } else break; } getchar(); printf("请输出插入的值:"); scanf("%c", &e); while (j < i && p != NULL) { j++; p = p->next; } if (p == NULL) { printf("查无此值!\n"); Sleep(2000); return; } else { s = (LinkList*)malloc(sizeof(Node)); s->data = e; s->next = p->next; p->next = s; printf("插入胜利!\a"); Sleep(2000); }}void ListDelete(LinkList L){ int i, j = 0; ElemType e; LinkList p = L, q; if (p->next == NULL) { printf("表为空!\a\n"); Sleep(2000); return; } printf("以后表长为:%d\n", ListLength(L)); //留神指针L while (1) { printf("请输出删除值的地位:"); scanf("%d", &i); if (i <= 0 || i > ListLength(L)) { printf("输出谬误!请从新输出!\n"); } else break; } getchar(); while (j < i && p != NULL) { j++; p = p->next; } if (p == NULL) { printf("查无此值!\n"); Sleep(2000); return; } else { q = p->next; if (p == NULL) { printf("查无此值!\n"); Sleep(2000); return; } e = q->data; p->next = q->next; free(q); printf("删除胜利!\a"); Sleep(2000); }}void DestroyList(LinkList L){ LinkList pre = L, p = L->next; while (p != NULL) //逐个开释 { free(pre); pre = p; p = pre->next; } free(pre); printf("销毁胜利!\a"); Sleep(2000);}int main(){ int n; LinkList L; //头结点应为指针,因为调用DestroyList(L)时由手动开释(free()) InitList(&L); //留神栈区(主动开释)和堆区(手动开释)的销毁区别 while (1) { system("cls"); //清屏函数 Show_meau(); printf("请输出1-8的数:"); scanf("%d", &n); switch (n) { case 1: Search(L); break; case 2: ListInsert(L); break; case 3: ListDelete(L); break; case 4: DispList(L); break; case 5: Print_Length(L); break; case 6: DestroyList(L); //留神栈和堆的销毁的区别 break; case 7: printf("........正在退出中........"); Sleep(3000); system("cls"); printf("\a退出胜利!"), exit(0); break; case 8: Create_List(L); break; default: printf("\a输出谬误!请从新输出(1—8)!"), Sleep(2000); break; } } return 0;}

May 30, 2021 · 3 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#:ASPNET-Core-MVC-入门到精通-3-使用MediatR

ASP.NET Core MVC 入门到精通 - 3. 应用MediatR 环境: .NET 5ASP.NET Core MVC (project)1. MediatRMediatR .NET中的简略中介者模式实现,一种过程内消息传递机制(无其余内部依赖)。反对以同步或异步的模式进行申请/响应,命令,查问,告诉和事件的消息传递,并通过C#泛型反对音讯的智能调度。 Simple mediator implementation in .NETIn-process messaging with no dependencies.Supports request/response, commands, queries, notifications and events, synchronous and async with intelligent dispatching via C# generic variance. 另:中介者模式 - 定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合涣散,且能够独立地扭转它们之间的交互。中介者模式又叫调解模式,它是迪米特法令的典型利用。 2. 装置 & 配置对于.NET5 (.net core), 应用nuget 装置MediatR.Extensions.Microsoft.DependencyInjection. 配置: public void ConfigureServices(IServiceCollection services){ services.AddControllersWithViews(); services.AddMediatR(typeof(Startup));}3. MediatR音讯类型3.1. Notifications 告诉模式Notifications 告诉模式用于生产者发送告诉,消费者(能够多个)接管到告诉后,进行后续解决。例:一个APS.NET 页面,拜访时,发送Notifications告诉;消费者简略记录收到告诉的工夫。 3.1.1. 定义基于INotification的告诉类public class Ping : INotification { }3.1.2. 定义消费者(关注告诉的解决办法)public class Pong1 : INotificationHandler<Ping>{ public Task Handle(Ping notification, CancellationToken cancellationToken) { Debug.WriteLine($"Pong1, {DateTime.Now}"); return Task.CompletedTask; }}public class Pong2 : INotificationHandler<Ping>{ public Task Handle(Ping notification, CancellationToken cancellationToken) { Debug.WriteLine($"Pong2, {DateTime.Now}"); return Task.CompletedTask; }}3.1.3. 发送音讯告诉// 基于dotnet core的依赖注入,注入IMediator对象private readonly IMediator _mediator;public HomeController(ILogger<HomeController> logger, IMediator mediator){ _logger = logger; _mediator = mediator;}public async Task<IActionResult> IndexAsync(){ // e.g. 拜访首页时,发送告诉 await _mediator.Publish(new Ping()); return View();}3.1.4. 输入Pong1, 5/27/2021 4:37:18 PMPong2, 5/27/2021 4:37:18 PM3.2. Request/Response 申请响应模式request/response用于命令和查问的场景。 ...

May 28, 2021 · 2 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:给定两个均不超过9的正整数a和n要求编写函数求aaaaaa⋯aa⋯an个a之和

要求:用两个函数//返回要求的和sumA(int a, int n);//返回n个a组成的数字int fn( int a, int n); 输入输出: main函数实现,如下: int main(){ int a, n; scanf("%d %d",&a,&n); printf("fn(%d , %d) = %d\n", a, n, fn(a, n)); printf("s = %d\n", SumA(a, n)); return 0;} fn函数实现,如下: int fn( int a, int n){ int sum1 = 0; for(int i = 1; i<=n; i++) { sum1 += a; a *= 10; } return sum1;} sumA函数实现,如下: int SumA( int a, int n){ int sum2 = 0; int sign = 0; for(int i = 1; i<=n; i++) { sum2 += a; a *= 10; sign += sum2; } return sign;}

May 25, 2021 · 1 min · jiezi

关于c#:Winform窗体圆角以及描边完美解决方案

圆角我的项目中须要把窗体的四角改为圆角,winform窗体的圆角不是很好设置或者说绘制。在网上查找了很多计划,最终找到了一种完满解决方案。 在网上材料中罕用的是都是重绘窗体四角。然而采纳的形式不一样最初的成果也不一样同时代码量带来的体力劳动也是不一样的。 第一种计划:重写OnPaint或者再窗体的Paint事件中实现重绘。 这种计划有一个显著的毛病是软件运行时会引起窗体的闪动,这种计划绘制的圆角有肯定的纹刺,圆角不润滑。 第二种计划:采纳Win32 API重绘 这种计划是比拟完满的计划,没有计划一中的毛病。代码如下。 public partial class FrmLogin : Form, ILoginView { private ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public FrmLogin() { InitializeComponent(); Load += FrmLogin_Load; SetFormRoundRectRgn(this, 5); //设置圆角 } private void FrmLogin_Load(object sender, EventArgs e) { this.BackColor = ColorTranslator.FromHtml("#FF5DB3AB"); //171, 179, 93 BackgroundImage = ImageHelper.GetImage("Login\\login_bg.png"); }}/// <summary> /// 设置窗体的圆角矩形 /// </summary> /// <param name="form">须要设置的窗体</param> /// <param name="rgnRadius">圆角矩形的半径</param> public static void SetFormRoundRectRgn(Form form, int rgnRadius) { int hRgn = 0; hRgn = Win32.CreateRoundRectRgn(0, 0, form.Width + 1, form.Height + 1, rgnRadius, rgnRadius); Win32.SetWindowRgn(form.Handle, hRgn, true); Win32.DeleteObject(hRgn); }using System;using System.Collections.Generic;using System.Linq;using System.Runtime.InteropServices;using System.Text; namespace UClass.View.Login{ public class Win32 { #region Window Const public const int WM_ERASEBKGND = 0x0014; public const int WM_LBUTTONDOWN = 0x0201; public const int WM_LBUTTONUP = 0x0202; public const int WM_LBUTTONDBLCLK = 0x0203; public const int WM_WINDOWPOSCHANGING = 0x46; public const int WM_PAINT = 0xF; public const int WM_CREATE = 0x0001; public const int WM_ACTIVATE = 0x0006; public const int WM_NCCREATE = 0x0081; public const int WM_NCCALCSIZE = 0x0083; public const int WM_NCPAINT = 0x0085; public const int WM_NCACTIVATE = 0x0086; public const int WM_NCLBUTTONDOWN = 0x00A1; public const int WM_NCLBUTTONUP = 0x00A2; public const int WM_NCLBUTTONDBLCLK = 0x00A3; public const int WM_NCMOUSEMOVE = 0x00A0; public const int WM_NCHITTEST = 0x0084; public const int HTLEFT = 10; public const int HTRIGHT = 11; public const int HTTOP = 12; public const int HTTOPLEFT = 13; public const int HTTOPRIGHT = 14; public const int HTBOTTOM = 15; public const int HTBOTTOMLEFT = 0x10; public const int HTBOTTOMRIGHT = 17; public const int HTCAPTION = 2; public const int HTCLIENT = 1; public const int WM_FALSE = 0; public const int WM_TRUE = 1; #endregion #region Public extern methods [DllImport("gdi32.dll")] public static extern int CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3); [DllImport("user32.dll")] public static extern int SetWindowRgn(IntPtr hwnd, int hRgn, Boolean bRedraw); [DllImport("gdi32.dll", EntryPoint = "DeleteObject", CharSet = CharSet.Ansi)] public static extern int DeleteObject(int hObject); [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); [DllImport("user32.dll")] public static extern bool ReleaseCapture(); #endregion }}窗体和控件描边实现思路:在现有的窗体和控件的根底之上画一个比原来窗体和控件范畴大1的矩形,描边的宽度和色彩能够通过pen设置。具体代码如下 ...

May 25, 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:字符串的输入输出

字符串常识补充:字符串的输出://间接输出字符串且只能输出字符串;空格也被认为是字符串的一部分,只有遇到回车键才会认为字符串输出完。 gets(字符串名称);//通过格局控制符%s输出字符串;遇到空格时会认为字符串到此就完结,空格前面输出的字符都不会被读取到。 scanf("%s",字符串名称);字符串的输入://puts();会主动换行,只能输入字符串 puts(字符串名称);//通过格局控制符%s输入字符串,不能主动换行。 scanf("%s", 字符串名称);

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:函数求水仙花数

要求:1、输出两个数2、用到两个函数://判断number是否是水仙花数,是返回1,否返回0int narcissistic (int number);//打印区间m,n之间的所有水仙花数void PrintN(int m, int n); 输入输出模式: //函数申明 int narcissistic (int number);void PrintN(int m, int n);int main(){ int m, n; scanf("%d %d", &m, &n); if( narcissistic (m)) printf("%d is a narcissistic number\n",m); PrintN(m, n); if( narcissistic(n)) printf("%d is a narcissistic number\n",n); return 0;} //判断number是否是水仙花数,是返回1,否返回0 int narcissistic (int number){ int t = number;//计数 int count = 1;//统计number是几位数 while(t>9){ count++; t/=10; }//设置一个返回值,是水仙花则反judge=1;否则judge=0; int judge = 0; int b = number; int sum = 0; while(b>0){ int a = b%10; b/=10; int p = a;//这一行不会不懂吧->_-> 各个位的位数次方 int j = 1; while(j<count){ p *= a; j++; } sum += p; } if(sum == number){ judge = 1; } return judge;}//打印区间m,n之间所有的水仙花数 void PrintN(int m, int n){ int i; for(i = m+1; i<n; i++){//函数嵌套调用函数 if(narcissistic(i)){ printf("%d\n",i); } } }我犯过谬误的点:(1)遗记申明函数接口了,低级谬误,千万不要忘。不然当前侍奉女友时做事忘东忘西可就有你好受了。。。(2)在统计number是几位数时,判断条件不对。解决:因为我定义的count计数是从1开始,所以只有满足t>9或者t>=10时即可满足判断位数的条件。具体见代码。 ...

May 19, 2021 · 1 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:数字特征值

题目内容:对数字求特征值是罕用的编码算法,奇偶特色是一种简略的特征值。对于一个整数,从个位开始对每一位数字编号,个位是1号,十位是2号,以此类推。这个整数在第n位上的数字记作x,如果x和n的奇偶性雷同,则记下一个1,否则记下一个0。依照整数的程序把对应位的示意奇偶性的0和1都记录下来,就造成了一个二进制数字。比方,对于342315,这个二进制数字就是001101。 这里的计算能够用上面的表格来示意: 你的程序要读入一个非负整数,整数的范畴是[0,1000000],而后依照上述算法计算出示意奇偶性的那个二进制数字,输入它对应的十进制值。 提醒:将整数从右向左合成,数位每次加1,而二进制值每次乘2。 输出格局:一个非负整数,整数的范畴是[0,1000000]。 输入格局:一个整数,示意计算结果。 输出样例:342315 输入样例:13 include<stdio.h>int main() { int num,x,n,t;int i=1;int result=0;scanf("%d",&num);if(num>=0&&num<=1000000){ for(n=1;n<7;n++){ x=num%10; num=num/10; if(x%2==0&&n%2==0){ t=1; }else if(x%2!=0&&n%2!=0){ t=1; }else{ t=0; } t=t*i; i=i*2; result=result+t; }}printf("%d",result);return 0;}

May 14, 2021 · 1 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#:Mybatis配置数据库连接

首先resources下的mybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><!--外围配置文件--><configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/ssms?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="cn/zmxy/dao/UsersMapper.xml"/> </mappers></configuration>pojo实现类层的Java类(对应数据库表),比方Users表public class Users { private int id; private String name; private String pwd; public Users(){}}dao层的映射xml和Interface接口UsersMapper.xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace 命名空间 保定一个对应的dao/mapper接口--><mapper namespace="cn.zmxy.dao.UsersMapper"> <select id="getUserList" resultType="cn.zmxy.pojo.Users"> SELECT * FROM ssms.users </select> <select id="getUserById" resultType="cn.zmxy.pojo.Users" parameterType="int"> SELECT * FROM ssms.users WHERE id = #{id} </select> <insert id="addUser" parameterType="cn.zmxy.pojo.Users"> INSERT INTO ssms.users (id, name, pwd) VALUES (#{id}, #{name}, #{pwd}) </insert> <update id="updateUser" parameterType="cn.zmxy.pojo.Users"> UPDATE ssms.users SET name = #{name}, pwd = #{pwd} WHERE id = #{id} </update> <delete id="deleteUser" parameterType="int"> DELETE FROM ssms.users WHERE id = #{id} </delete></mapper>UsersMapper.javapackage cn.zmxy.dao;import cn.zmxy.pojo.Users;import java.util.List;public interface UsersMapper { // 查问全副用户 public List<Users> getUserList(); // 依据ID查问用户 public Users getUserById(int id); // 增加用户 public int addUser(Users user); // 批改用户 public int updateUser(Users user); // 删除用户 public int deleteUser(int id);}写一个utils类,获取SqlSessionMyBatisUtils.javapackage cn.zmxy.utils;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); }}最初就能够调用了,写一个test类UserMapperTest.javapackage cn.zmxy.dao;import cn.zmxy.pojo.Users;import cn.zmxy.utils.MyBatisUtils;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserDaoTest { @Test public void test() { // 第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); // 第二步,执行SQL UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class); List<Users> userList = usersMapper.getUserList(); // 打印users for (Users users : userList) { System.out.println(users); } // 敞开SqlSession sqlSession.close(); } @Test public void getUserById() { // 第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); UsersMapper mapper = sqlSession.getMapper(UsersMapper.class); Users user = mapper.getUserById(1); System.out.println(user); // 敞开SqlSession sqlSession.close(); } @Test public void addUser() { // 第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); UsersMapper mapper = sqlSession.getMapper(UsersMapper.class); int num = mapper.addUser(new Users(0, "露露", "1234")); System.out.println("受影响行数:" + num); sqlSession.commit(); // 敞开SqlSession sqlSession.close(); } @Test public void updateUser() { // 第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); UsersMapper mapper = sqlSession.getMapper(UsersMapper.class); int num = mapper.updateUser(new Users(3, "露露", "1234")); System.out.println("受影响行数:" + num); sqlSession.commit(); // 敞开SqlSession sqlSession.close(); } @Test public void deleteUser() { // 第一步,获取SqlSession对象 SqlSession sqlSession = MyBatisUtils.getSqlSession(); UsersMapper mapper = sqlSession.getMapper(UsersMapper.class); int num = mapper.deleteUser(11); System.out.println("受影响行数:" + num); sqlSession.commit(); // 敞开SqlSession sqlSession.close(); }}

May 13, 2021 · 2 min · jiezi

关于c#:C-解决httplistener-querystring-中文乱码返回json中文格式乱码

解决httplistener querystring 中文乱码计划:在申请达到时候,获取Request.Url,返回get申请参数 键值对 public class RequestHelper { public static Dictionary<string, string> EncodeQueryString(Uri uri) { var ret = new Dictionary<string, string>(); var q = uri.Query; if (q.Length > 0) { foreach (var p in q.Substring(1).Split('&')) { var s = p.Split(new char[] { '=' }, 2); ret.Add(HttpUtility.UrlDecode(s[0]), HttpUtility.UrlDecode(s[1])); } } return ret; } }解决返回json中文格局乱码:对中午json字符串进行编码 HttpUtility.UrlDecode(“中文”); public class ResponseHelper { public static void Respose(HttpListenerResponse response, string jsonStr = "") { byte[] buffer = Encoding.UTF8.GetBytes(jsonStr); response.ContentLength64 = buffer.Length; response.ContentType = "application/json"; response.ContentEncoding = Encoding.UTF8; response.StatusCode = 200; Stream output = response.OutputStream; output.Write(buffer, 0, buffer.Length); //敞开输入流,开释相应资源 output.Close(); response.Close(); } }转载于:链接 ...

May 13, 2021 · 1 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语言中strstr函数的一个注意点

明天说一个之前工作上遇到过的一个问题,也是之前没留神过的一个点。 先看一段代码: #include <stdio.h>#include <string.h>int main(){ char sz1[16] = {0}; char sz2[10] = {0}; char sz3[3] = {0}; strncpy(sz1, "bbAAcc", sizeof(sz1)-1); strcpy(sz3, "AA"); if ( strstr(sz1, sz2) != NULL ) { printf("sz2 is in sz1\n"); } else { printf("sz2 is not in sz1\n"); } if ( strstr(sz1, sz3) != NULL ) { printf("sz3 is in sz1\n"); } else { printf("sz3 is not in sz1\n"); } return 0;}大家猜一猜这段代码会输入什么呢?第二个strstr答案很明确,然而对于第一个strstr的调用,可能会有一点纳闷。 实际上在遇到这个问题之前,我始终很执著的认为,这段代码应该输入如下答案: sz2 is not in sz1sz3 is in sz1那让咱们编译当前执行一下看看: ...

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程序打印带有星形图案的-锐角三角形

解题思路绿色部份打印右星形直角三角形红色部份打印右倒置星形直角三角形 /* ============================================================================ Name : LearnC.c Author : SpringSongs Version : 0.0.1 Copyright : SpringSongs Description : C程序打印带有星形图案的锐角三角形, Ansi-style ============================================================================ 打印如下: * ** *** ********* **** *** ** * */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 5; i++) { for (j = 0; j < 5 - i; j++) { printf(" "); } for (j = 1; j <= i; j++) { printf("*"); } printf("\n"); } for (i = 1; i <= 5; i++) { for (j = 0 ; j < i; j++) { printf(" "); } for (j = 1; j <= 5-i; j++) { printf("*"); } printf("\n"); }}

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#:cmysql数据库备份还原

1:援用dllMySql.Data.dll, MySqlbackup.dll 2:建一个数据连贯动态类public static class mysql{public static string constr = "database=test;Password=明码;user ID=root;server=ip地址";public static MySqlConnection conn = new MySqlConnection(constr);}3:建winform窗体备份代码 DialogResult result = MessageBox.Show("备份门路默认在以后程序下", "提醒", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes){string time1 = System.DateTime.Now.ToString("d").Replace("/", "-");string file = ".//mysql/" + time1 + "_test.sql";using (MySqlCommand cmd = new MySqlCommand()){using (MySqlBackup mb = new MySqlBackup(cmd)){cmd.Connection = mysql.conn;mysql.conn.Open();mb.ExportToFile(file);mysql.conn.Close();MessageBox.Show("已备份");}}}else{return;}还原代码 string file = textBox1.Text;if (file == ""){MessageBox.Show("不能为空");return;}DialogResult result = MessageBox.Show("确定还原吗?", "还原", MessageBoxButtons.YesNo, MessageBoxIcon.Question);if (result == DialogResult.Yes){try{using (MySqlCommand cmd = new MySqlCommand()){using (MySqlBackup mb = new MySqlBackup(cmd)){cmd.Connection = mysql.conn;mysql. conn.Open();mb.ImportFromFile(file);mysql. conn.Close();MessageBox.Show("已还原");}}}catch (Exception ex){MessageBox.Show(ex.Message);}}else{return;}

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:1C语言学习从源文件如何到可执行文件的

源程序就是一个.txt 的一般文本文件,是经验了哪些过程,变为可执行性文件的呢? 大体上分为四个步骤: 预处理 -> 编译 -> 汇编 -> 链接 四个过程。 对于集成开发环境(IDE,Integrated Development Environment )而言,缩小了环 境配置,合并了流程,使其便于疾速开发。就 Qt 开发环境而言,只需一步即可: unix /linux 环境下,通常没有界面,所以少有集成开发环境。所有的开发均是在命 令行模试下,开发的。以 vim 为编辑器,以 gcc 为编译器为例,演示。

May 6, 2021 · 1 min · jiezi

关于c:C51单片机学习日志

2021/05/01踩坑一开始装置驱动那里就出问题,驱动明明曾经装置,然而辨认不了单片机的接口,问客服,感觉客服也很迷,最初还是解决了。目测要么是USB线接触不良,要么是装置的WIN10驱动没起作用,因为前面还装置了一个XP驱动。 单片机相干概念单片机是单芯片微型计算机的简称,罕用英文缩写_MCU_(Microcontroller Unit)代指单片机。 我所应用的单片机为DIP封装,尽管体积较大,然而不便装配,从而损坏后更换芯片更便捷。 其余两种封装(PLCC,LQFP),尽管体积小,然而更换比拟麻烦,。厂商为_STC_的,这家厂商单片机烧录程序便捷些。 厂商尽管不同,然而内核都是应用的Intel公司的80C51系列内核,_STC_的单片机命名规定如下: 一些零散知识点(C语言)因为C语言曾经学过不少了,就选择性地记了些笔记: 罕用存储单位关系: 中文名称英文名称换算关系比特(字位)bit1B = 8bit字节byte1B = 8bit千字节kibibyte1KB = 1024B兆字节Mebibyte1MB = 1024KB吉字节Gigabyte1GB = 1024MB常说的100M宽带,并非是100MB而是100Mbit,所以换算成下载速度须要除以8,换算成字节单位,也就是12.5MB。 数据类型所占位数范畴bit10~1unsigned char80~255char8-128~127unsigned int160~65535int16-32768~32767unsigned long320~429467295float323.4e-38~3.4e38double641.7e-308~1.7e308其中,有符号位的最高位是符号位,0示意负数,1示意正数。 一些零散知识点(电子电路根底)单片机是一种数字集成芯片,数字电路中只有两种电平:高电平和低电平。 高电平为5V,低电平为0V。 TTL电平信号被利用的较多,因为数字电路中通常数据表示采纳二进制,5V等价于逻辑1,0V等价于逻辑0。TTL电平规定高电平输入电压>2.4V,低电平输入电压<0.4V,这是因为理论发送信号时,可能并不一定达到高电平和低电平的准确值,所以只有在这个稳定范畴内都是会被认定为高电平和低电平的。 而计算机串口应用的是RS232电平。 高电平为-12V,低电平为+12V,单片机与计算机串口通信时须要应用电平转换芯片,把RS232电平转换为TTL电平后,单片机能力辨认。然而电路USB接口的供电口是5V,充电宝也是,所以能够用充电宝和电脑USB接口来给单片机供电。 I/O口是根本输出Input/输入Output接口,单片机对外围设备的管制都是通过I/O口来进行的(输入高低电平)。接管内部管制也是通过I/O口来读取内部电压信号。 选电容时,个别选耐压值比利用零碎高2-3倍的电容。 有极性的电容,长脚为正,短脚为负。 电容上色彩面积小的局部所对应的为负极,反之为正极(对于直插和贴片电解电容)。而对于钽电容则相同。 单片机须要运行起来最根本的条件为: 电源单片机芯片晶振电路复位电路 单片机工作的根本时序: 振荡周期:也称时钟周期,是指为单片机提供时钟脉冲信号的振荡源的周期。 机器周期:一个机器蕴含12个时钟周期。在一个机器周期内,CPU能够实现一个独立的操作。 电路原理图中: 电阻上的471字样代表电阻阻值为47*10^1 电容上的105字样代表电容大小为10*10^5 pF 网络标号雷同的两点示意这两点理论电气相连(有导线连贯)。点亮LED灯LED,即发光二极管。其长处是,功耗低,高亮度,色彩艳丽,寿命长。 同样的,LED灯也是长正短负。它的封装形式和电容电阻相似,开发板中用的就是最小的0603封装。贴片式的LED,有小绿点的一端为负极,另一端为正极。 一般发光二极管工作压降为1.6V~2.1V。工作电流为1~20mA。一般发光二极管导通压降通常为0.7V。因为其工作电流较小,通常会再串一个限流电阻。 原理 由原理图可知,要想点亮LED灯,二极管须要处于导通状态,因为电源输出到阳极的信号恒为高电平,那么阴极为低电平能力导通,那么给阴极输出0即可。 实际 踩坑:在建我的项目编译文件时,记得在output里勾选输入hex文件。 暴力点灯 间接别离对须要亮灯的地位赋值0。 #include <reg52.h>sbit LED2 = P1^1;sbit LED3 = P1^2;sbit LED5 = P1^4;void main(){ LED2 = 0; LED3 = 0; LED5 = 0;}多口操作点灯 对P1的8个口一起操作,因为操作时是按位操作,所以赋值的数是二进制数,二进制数位上的0和1就别离代表了低电平和高电平,然而写程序时个别会赋值16进制的数。 二进制高位到低位就对应了P1的8个口从大到小的序号 ...

May 3, 2021 · 3 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:嵌入式软件工程师笔试面试指南ARM体系与架构

哈喽,大家好。我终于回来了!19号刚提交完大论文,就被抓去出差了,折腾了整整一周,26号早晨,才回到学校。鸽了良久都没更新干货了。明天更新一篇对于Arm的口试面试题目,文章内容已同步更新在github。[TOC] ARM体系与架构 硬件根底NAND FLASH 和NOR FLASH异同?不同点 类别NORNAND读快 像拜访SRAM一样,能够随机拜访任意地址的数据;如:unsighed short pwAddr = (unsighed short )0x02;unisignded short wVal;wVal = *pwAddr快,有严格的时序要求,须要通过一个函数能力读取数据,先发送读命令->发送地址->判断nandflash是否就绪->读取一页数据读命令、发送地址、判断状态、读数据都是通过操作寄存器实现的,如数据寄存器NFDATA写慢,写之前须要擦除,因为写只能是1->0,擦除能够使0->1快,写之前须要擦除,因为写只能是1->0,擦除能够使0->1擦除十分慢(5S)快(3ms)XIP代码能够间接在NOR FLASH上运行NO可靠性比拟高,位反转的比例小于NAND FLASH的10%比拟低,位反转比拟常见,必须有校验措施接口与RAM接口雷同,地址和数据总线离开I/O接口可擦除次数10000~100000100000~1000000容量小,1MB~32MB大,16MB~512MB主要用途罕用于保留代码和要害数据用于保留数据价格高低留神:nandflash和norflash的0地址是不抵触的,norflash占用BANK地址,而nandflash不占用BANK地址,它的0地址是外部的。 相同点 1写之前都要先擦除,因为写操作只能使1->0,而擦除动作是为了把所有位都变12擦除单元都以块为单位CPU,MPU,MCU,SOC,SOPC分割与差异?1.CPU(Central Processing Unit),是一台计算机的运算外围和管制外围。CPU由运算器、控制器和寄存器及实现它们之间分割的数据、管制及状态的总线形成。差不多所有的CPU的运作原理可分为四个阶段:提取(Fetch)、解码(Decode)、执行(Execute)和写回(Writeback)。 CPU从存储器或高速缓冲存储器中取出指令,放入指令寄存器,并对指令译码,并执行指令。所谓的计算机的可编程性次要是指对CPU的编程。 2.MPU (Micro Processor Unit),叫微处理器(不是微控制器),通常代表一个功能强大的CPU(暂且了解为增强版的CPU吧),但不是为任何已有的特定计算目标而设计的芯片。这种芯片往往是集体计算机和高端工作站的外围CPU。最常见的微处理器是Motorola的68K系列和Intel的X86系列。 3.MCU(Micro Control Unit),叫微控制器,是指随着大规模集成电路的呈现及其倒退,将计算机的CPU、RAM、ROM、定时计数器和多种I/O接口集成在一片芯片上,造成芯片级的芯片,比方51,avr这些芯片,外部除了CPU外还有RAM,ROM,能够间接加简略的外围器件(电阻,电容)就能够运行代码了,而MPU如x86,arm这些就不能间接放代码了,它只不过是增强版的CPU,所以得增加RAM,ROM。 MCU MPU 最次要的区别就睡是否间接运行代码。MCU有外部的RAM ROM,而MPU是增强版的CPU,须要增加内部RAM ROM才能够运行代码。 4.SOC(System on Chip),指的是片上零碎,MCU只是芯片级的芯片,而SOC是零碎级的芯片,它既MCU(51,avr)那样有内置RAM,ROM同时又像MPU(arm)那样弱小的,不单单是放简略的代码,能够放零碎级的代码,也就是说能够运行操作系统(将就认为是MCU集成化与MPU强解决力各长处二合一)。 5.SOPC(System On a Programmable Chip)可编程片上零碎(FPGA就是其中一种),下面4点的硬件配置是固化的,就是说51单片机就是51单片机,不能变为avr,而avr就是avr不是51单片机,他们的硬件是一次性掩膜成型的,能改的就是软件配置,说白点就是改代码,原本是跑流水灯的,改下代码,变成数码管,而SOPC则是硬件配置,软件配置都能够批改,软件配置跟下面一样,没什么好说的,至于硬件,是能够本人构建的也就是说这个芯片是本人结构进去的,这颗芯片咱们叫“白片”,什么芯片都不是,把硬件配置信息下载进去了,他就是相应的芯片了,能够让他变成51,也能够是avr,甚至arm,同时SOPC是在SOC根底上来的,所以他也是零碎级的芯片,所以记得当把他变成arm时还得加外围ROM,RAM之类的,不然就是MPU了。 什么是穿插编译?在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,咱们就称这种编译器反对穿插编译。这个编译过程就叫穿插编译。简略地说,就是在一个平台上生成另一个平台上的可执行代码。 这里须要留神的是所谓平台,实际上蕴含两个概念:体系结构(Architecture)、操作系统(OperatingSystem)。同一个体系结构能够运行不同的操作系统;同样,同一个操作系统也能够在不同的体系结构上运行。举例来说,咱们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。 为什么须要穿插编译?有时是因为目标平台上不容许或不可能装置咱们所须要的编译器,而咱们又须要这个编译器的某些特色;有时是因为目标平台上的资源贫乏,无奈运行咱们所须要编译器;有时又是因为目标平台还没有建设,连操作系统都没有,基本谈不上运行什么编译器。 形容一下嵌入式基于ROM的运行形式和基于RAM的运行形式有什么区别?基于RAM 须要把硬盘和其余介质的代码先加载到ram中,加载过程中个别有重定位的操作。速度比基于ROM的快,可用RAM比基于ROM的少,因为所有的代码,数据都必须寄存在RAM中。基于ROM 速度较基于RAM的慢,因为会有一个把变量,局部代码等从存储器(硬盘,flash)搬移到RAM的过程。可用RAM资源比基于RAM的多;ARM处理器什么是哈佛构造和冯诺依曼结构?定义 冯诺依曼结构釆用指令和数据对立编址,应用同条总线传输,CPU读取指令和数据的操作无奈重叠。 哈佛构造釆用指令和数据独立编址,应用两条独立的总线传输,CPU读取指令和数据的操作能够重叠。 利弊 冯诺依曼结构次要用于通用计算机领域,须要对存储器中的代码和数据频繁的进行批改,对立编址有利于节约资源。 哈佛构造次要用于嵌入式计算机,程序固化在硬件中,有较高的可靠性、运算速度和较大的吞吐。 什么是ARM流水线技术?流水线技术通 过多个性能部件并行工作来缩短程序执行工夫,进步处理器核的效率和吞吐率,从而成为微处理器设计中最为重要的技术之一。ARM7处理器核应用了典型三级流水线的冯·诺伊曼构造,ARM9系列则采纳了基于五级流水线的哈佛构造。通过减少流水线级数简化了流水线各级的逻辑,进一步提高了处理器的性能。 PC代表程序计数器,流水线应用三个阶段,因而指令分为三个阶段执行:1.取指(从存储器装载一条指令);2.译码(辨认将要被执行的指令);3.执行(解决指令并将后果写回寄存器)。而R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为以后第一条指令,因而PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=以后程序执行地位+8; ARM指令是三级流水线,取指,译指,执行,同时执行的,当初PC指向的是正在取指的地址(下一条指令),那么cpu正在译指的指令地址是PC-4(假如在ARM状态下,一个指令占4个字节),cpu正在执行的指令地址是PC-8,也就是说PC所指向的地址和当初所执行的指令地址相差8。 ...

April 28, 2021 · 3 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

关于c++:AR-正方形字符串

现请你输入指定大小的“ACM”字符串。特地地,咱们要求输入的字符串是正方形的(行数和列数相等)。输出输出的第一行是一个正整数N(N<=20),示意一共有N组数据,接着是N行数据,每行蕴含一个正整数M(M<=50),示意一行内有M个“ACM”相连。输入输入指定的正方形字符串。样例输出 Copy212样例输入 CopyACMACMACMACMACMACMACMACMACMACMACMACMACMACMACM 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// string a = "ACM";// int n = 0;// scanf("%d",&n);// while(n--){// int m = 0;// cin >> m;// for(int i = 0; i < (a.size() * m); i++){// for(int j = 0; j < m; j++){// cout << a ;// }// printf("\n");// }// }// return 0;//}

April 27, 2021 · 1 min · jiezi

关于c++:AP-奇偶位互换AQ-元音字母转换基础上机试题

给定一个长度为偶数位的0,1字符串,请编程实现串的奇偶位调换。输出输出蕴含多组测试数据。输出的第一行是一个整数C,示意有C测试数据。接下来是C组测试数据,每组数据输出均为0,1字符串,保障串长为偶数位(串长<=50)。输入请为每组测试数据输入奇偶位调换后的后果,每组输入占一行。样例输出 Copy201101100样例输入 Copy10011100 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// int n = 0;// scanf("%d",&n);// while(n--){// string a;// char q; // cin >> a;// for(int i = 0; i < (int)(a.size() - 1); i+=2){// q = a[i];// a[i] = a[i + 1];// a[i + 1] = q;// }// cout << a << endl;// }// return 0;//}给你一个字符串,现要求你对其进行解决,使得解决后的字符串满足如下要求:字符串外面的元音字母全副为大写;其余字母全副为小写。输出输出的第一行为一个正整数T(T<=20),示意测试数据的个数。每个输出的字符串只蕴含大写字母和小写字母。字符串长度不超过50。输入对于每一个测试数据,输入其对应的后果。每个后果占一行。样例输出 Copy4XYzapplicationqwcvbaeioOa样例输入 CopyxyzApplIcAtIOnqwcvbAEIOOA 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// int n = 0;// scanf("%d",&n);// while(n--){// string a;// cin >> a;// for(int i = 0; i < a.size(); i++){// if(a[i]=='A'||a[i]=='a'||a[i]=='E'||a[i]=='e'||a[i]=='I'||a[i]=='i'||a[i]=='O'||a[i]=='o'||a[i]=='U'||a[i]=='u'){// a[i] = toupper(a[i]);// }else {// a[i] = tolower(a[i]);// }// }// cout << a << endl;// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AO-墓碑上的字符基础上机试题

考古学家发现了一座千年古墓,墓碑上有神秘的字符。通过认真钻研,发现原来这是开启古墓入口的办法。墓碑上有2行字符串,其中第一个串的长度为偶数,当初要求把第2个串插入到第一个串的正地方,如此便能开启墓碑进入墓中。输出输出数据首先给出一个整数n,示意测试数据的组数。而后是n组数据,每组数据2行,每行一个字符串,长度大于0,小于50,并且第一个串的长度必为偶数。输入请为每组数据输入一个能开启古墓的字符串,每组输入占一行。样例输出 Copy2CSJIBIABCMCLU样例输入 CopyCSBIJIACMCLUB 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// int n = 0;// scanf("%d",&n);// while(n--){// string a,b;// cin >> a >> b;w// int c = (int)a.size() / 2;// for(int i = 0; i < c; i++){// cout << a[i];// }// cout << b;// for(int i = c; i < (int)a.size(); i++){// cout << a[i];// } // cout << endl;// }// return 0;//}///*办法2-insert函数 * //int main(){// int n = 0;// scanf("%d",&n);// while(n--){// string a,b;// cin >> a >> b;// a.insert(a.size() / 2,b);// cout << a << endl; // }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AN-词组缩写基础上机试题

定义:一个词组中每个单词的首字母的大写组合称为该词组的缩写。比方,C语言里罕用的EOF就是end of file的缩写。 提醒:留神思考两个单词两头有多个空格的状况输出输出的第一行是一个整数T,示意一共有T组测试数据。接下来有T行,每组测试数据占一行,每行有一个词组,每个词组由一个或多个单词组成;每组的单词个数不超过10个,每个单词有一个或多个大写或小写字母组成;单词长度不超过10,由一个或多个空格分隔这些单词。输入请为每组测试数据输入规定的缩写,每组输入占一行。样例输出 Copy1end of file样例输入 CopyEOF 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//using namespace std;////int main(){// int n = 0;// scanf("%d",&n);// getchar(); // while(n--){// string str,s;// getline(cin,str);// if(str[0] >= 'a' && str[0] <= 'z'){// str[0] -= 32; // }// s = str.substr(0,1);//先把第一个单词小写字符变成大写// for(int i = 1; i < (int)str.size(); i++){//再把残余的单词首字母变成大写 // if(str[i - 1] == ' ' && (str[i] >= 'a' && str[i] <= 'z')){// str[i] -= 32;// s.append(str,i,1);//当第i-1个字符是空格,则取第i个字符加到字符s之后 // }else if(str[i - 1] == ' ' && (str[i] >= 'A' && str[i] <= 'Z')){// s.append(str,i,1);// }// }// cout << s << endl; // }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AM-过生日基础上机试题

小明出世在一个平年,他想晓得什么时候能够过生日,你能通知他吗?给你一个正整数Y,示意起始年份,和一个正整数N,你的工作是通知小明从Y年开始第N个平年是哪一年。留神:如果Y就是平年,那么第一个平年就是Y。输出输出的第一行为一个整数T,示意测试数据的组数。每一组输出蕴含两个正整数Y和N(1<=N<=10000)。输入对于每组输出,输入从Y年开始第N个平年是哪一年。样例输出 Copy32005 251855 122004 10000样例输入 Copy2108190443236 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//using namespace std;//bool Runyear(int y);//int main(){// int t = 0;// scanf("%d",&t);// while(t--){// int y = 0,n = 0;// scanf("%d %d",&y,&n);// int count = 0;// while(1){// if(Runyear(y)){// count++;// }// if(n == count){// break;// }// y++;// }// printf("%d\n",y);// } // return 0;//}//bool Runyear(int y){// if(y % 4 == 0 && y % 100 != 0 || y % 400 == 0){// return true;// }else{// return false;// }//} ...

April 27, 2021 · 1 min · jiezi