关于c++:AL-18岁生日基础上机试题

小明的18岁生日就要到了,他当然很开心,可是他忽然想到一个问题,是不是每个人从出世开始,达到18岁生日时所通过的天数都是一样的呢?仿佛并不全都是这样,所以他想请你帮忙计算一下他和他的几个敌人从出世达到18岁生日所通过的总天数,让他好来比拟一下。输出输出的第一行是一个数T,前面T行每行有一个日期,格局是YYYY-MM-DD。如我的生日是1988-03-07。输入T行,每行一个数,示意此人从出世到18岁生日所通过的天数。如果这个人没有18岁生日,就输入-1。样例输出 Copy11988-03-07样例输入 Copy6574 代码示例(本人写的,只能过平台,不完满) //#include<iostream>//using namespace std;//bool Runyear(int y);//int main(){// int t = 0;// char ch1,ch2;// scanf("%d",&t);// while(t--){// int year = 0,month = 0,day = 0,sum = 0;// scanf("%d%c%d%c%d",&year,&ch1,&month,&ch2,&day);// if(Runyear(year) && month == 2 && day == 29){// printf("-1\n");// }else{// for(int i = 1; i <= 18; i++){// if(Runyear(year) && mont h <= 2 || Runyear(year + 1) && month > 2){// sum += 366;// }else if(!Runyear(year) && month <= 2 || !Runyear(year + 1) && month > 2){// sum += 365;// }// year++;// }// printf("%d\n",sum);// } // }// 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

关于c++:AK-镂空三角形基础上机试题

把一个字符三角形掏空,就能节俭资料老本,加重分量,但要害是为了谋求另一种视觉效果。在设计的过程中,须要给出各种花纹的资料和大小尺寸的三角形样板,通过电脑长期做进去,以便看看成果。输出每行蕴含一个字符和一个整数n(0<n<41),不同的字符示意不同的花纹,整数n示意等腰三角形的高。显然其底边长为2n-1。如果遇到@字符,则示意所做进去的样板三角形曾经够了。输入每个样板三角形之间应空上一行,三角形的两头为空。显然行末没有多余的空格。样例输出 CopyX 2A 7@样例输入 Copy(显示谬误,实为△型) XXXX A A AA AA A A A A AAAAAAAAAAAAAA代码示例(本人写的,只能过平台,不完满) //#include<iostream>//#include<string>//#include<string.h>//#include<cstring>//using namespace std;////int main(){// int n = 0;// char ch;ww// while((ch = getchar()) != '@'){// scanf("%d",&n); //此处能够换为 scanf("%d%*c",&n);%*c跳过一个字符// getchar();//scanf需循环输出,需应用gechar()吃掉上一次输出后暂存在buffer外面的(\n)空格 // for(int i = 0; i < n - 1; i++){//管制输入字符的行数(不含最初一行) // for(int j = i; j < n - 1; j++){ //管制左侧输入空格数 // printf(" ");// }// if(i == 0){//第一行输入一个ch并换行 // printf("%c\n",ch);// continue;// }else{//两头行输入 // printf("%c",ch);//输入一个ch; // for(int k = 2 * i - 1; k > 0; k--){//输入两头的空格数 // printf(" ");// }// printf("%c\n",ch);//输入左边的一个ch并换行 // }// }// for(int l = 2 * n - 1; l > 0; l--){//最初一行输入2*n - 1个ch // printf("%c",ch);// }// printf("\n\n");//图形之间空一行 // }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:AJ-放大的X基础上机试题

请你编程画一个放大的‘X’。如3*3的‘X’应如下所示:(图显示谬误,应为X型) X X XX X 5*5的‘X’如下所示:(图显示谬误,应为X型)X X X X X X XX X输出输出数据第一行是一个整数T,示意有T组测试数据。接下来有T行,每行有一个正奇数n(3<=n<=79),示意放大的规格。输入对于每一个n打印一个规格为 n*n 放大的‘X’,每组输入前面空一行。样例输出 Copy235样例输入 Copy(图显示谬误,应为X型)X X XX X X X X X X X XX X代码示例(本人写的,只能过平台,不完满) //#include<iostream>//using namespace std;////int main(){// int t = 0;// scanf("%d",&t);// while(t--){// int n = 0;// cin >> n; // for(int i = 1; i < (n + 1) / 2; i++){// for(int j = 1; j < i; j++){// printf(" ");// }// printf("X");// for(int k = 0; k < (n - 2 * i); k++){// printf(" ");// }// printf("X\n");// }// for(int i = (n + 1) / 2; i <= n; i++){// for(int j = n; j > i; j--){// printf(" ");// }// if(i == (n + 1) / 2){// printf("X\n");// continue;// } else{// printf("X");// }// for(int k = 0; k < 2 * i - n - 2; k++){// printf(" ");// }// printf("X\n");// }// printf("\n");// }// return 0;//} ...

April 27, 2021 · 1 min · jiezi

关于c++:C11-动态内存管理

C++内存动态内存、动态内存动态内存调配好后,程序运行过程中始终存在不会被开释,且一旦调配好,其内存大小就固定下来不能扭转,在编译和链接的阶段就会调配好。动态内存是程序运行过程中,依据程序的运行须要调配和开释,其大小可变。堆、栈堆和栈都是动态分配的,区别有两点: 栈是由编译器调配与开释;堆是程序通过调用malloc或new调配,调用free或delete开释。栈是线性构造;堆是链表构造。存储场景动态内存用来保留部分static对象、类static数据成员以及定义在任何函数之外的变量。栈内存用来保留定义在函数内的非static对象,存储在栈上,函数退出时,其占用内存被发出。调配在动态内存或栈内存中的对象由编译器主动创立和销毁。对于栈对象,仅在其定义的程序块运行时才存在;static对象在应用之前调配,在程序完结时销毁。 堆保留通过调用malloc或new失去的内存,不再须要时要显示地调用free或delete来开释堆内存容许程序员动静地申请所需空间,但也要求他们一旦不须要这些内存资源的时候就偿还他们。 内存相干谬误在程序运行的过程中,经常出现段谬误、内存继续增大等因为显式内存治理导致的问题,次要演绎为以下几点: 野指针:一些内存单元曾经开释,但之前指向它的指针还在应用。反复开释:程序试图开释曾经被开释过的内存单元。内存透露:没有开释不再应用的内存单元。缓冲区溢出:数组越界。不配对的new[]/delete[]针对上述问题中的1~3,C++规范中提供了智能指针来解决。 智能指针智能指针是基于RAII(Resource Acquisition Is Initialization)机制实现的类(模板),具备指针的行为(重载了operator*与operator->操作符)。当对象创立的时候,进行初始化;来到其作用域后,通过主动调用析构函数开释资源。 RAII (Resource Acquisition Is Initialization,资源获取就是初始化),是C++语言的一种治理资源、防止透露的习用法。C++规范保障任何状况下,已结构的对象最终会销毁,即它的析构函数最终会被调用。简略的说,RAII 的做法是应用一个对象,在其结构时获取资源,在对象生命期管制对资源的拜访使之始终保持无效,最初在对象析构的时候开释资源。 C++11新规范提供的两种智能指针区别在于治理底层指针的形式: shared_ptr 容许多个指针指向同一个对象;unique_ptr 独占所指向的对象;规范库还定义了一个名为weak_ptr的随同类,它是一种弱援用,指向shared_ptr所治理的对象。头文件:<memory>命名空间为:std unique_ptrunique_ptr”惟一“领有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有挪动语义std::move()来实现)。 unique_ptr指针自身的生命周期:从unique_ptr指针创立时开始,直到来到作用域。来到作用域时,若其指向对象,则将其所指对象销毁(默认应用delete操作符,用户可指定其余操作)。unique_ptr指针与其所指对象的关系:在智能指针生命周期内,能够扭转智能指针所指对象,如创立智能指针时通过构造函数指定、通过reset办法从新指定、通过release办法开释所有权、通过挪动语义转移所有权。#include <iostream>#include <memory>#include <vector> using namespace std; struct Foo { Foo() {} ~Foo() {} void Print() { cout << "Foo" << endl; }}; int main() { Foo* p1 = new Foo(); unique_ptr<Foo> up1; // up1==nullptr// up1 = p1; // 编译谬误,不反对这样赋值 up1.reset(p1); // 替换治理对象,并开释之前治理的对象 p1 = nullptr; // unique_ptr<Foo> up2(up1); // 编译谬误,不反对这样结构 unique_ptr<Foo> up2(std::move(up1)); // up1所有权转移到up2。up1==nullptr up1.swap(up2); // up2与up1治理对象的指针替换。 up2==nullptr if (up1) { // up1 != nullptr up1->Print(); // unique_ptr重载了-> (*up1).Print(); // unique_ptr重载了* }// up2->Print(); // 谬误 up2 == nullptr, 必须先判断再调用 p1 = up1.get(); // get() 返回所治理对象的指针, up1持续持有其管理权 p1 = up1.release(); // release() 返回治理对象的指针,并开释管理权,up1==nullptr delete p1; unique_ptr<Foo> up3(new Foo()); up3.reset(); // 显示开释开释治理对象的内存,也能够这样做:up = nullptr; vector<unique_ptr<Foo>> v; unique_ptr<Foo> up4(new Foo());// v.push_back(up4); // 编译谬误,不反对这样拷贝 v.push_back(std::move(up4); // 只能up4放弃对其所有权,通过std::move()将所有权转移到容器中 return 0;}shared_ptrshared_ptr 基于“援用计数”模型实现, 多个shared_ptr对象能够领有同一个动静对象,并保护了一个共享的援用计数。当最初一个指向该对象的shared_ptr被销毁或者reset时,会主动开释其所指的对象,回收动静资源。销毁该对象时,应用默认的delete/delete[]表达式,或者是在结构 shared_ptr 时传入的自定义删除器(deleter),以实现个性化的资源开释动作。 ...

April 26, 2021 · 2 min · jiezi

关于c++:40组合总和II排序树层去重

40.组合总和II题目:给定一个数组 candidates和一个指标数target ,找出candidates 中所有能够使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使⽤⼀次。解集不能蕴含反复的组合。与39题比拟相似,39题题目:给定⼀个⽆反复元素的数组 candidates 和⼀个⽬标数 target ,找出 candidates 中所有能够使数字和为target 的组合。candidates 中的数字能够⽆限度反复被选取。解集不能蕴含反复的组合。 与39题不同之处在于:(1)本题每个组合中每个数字只能用一次;(2)本题candidates蕴含反复元素,并且解集中不能有反复组合 思路:去重,即应用过的元素不能反复选取。应用used数组进行去重,树层去重前须要先进行排序应用援用传递 used去重,工夫复杂度O(size)留神:援用传递和全局变量在回溯中的应用办法截然不同,区别:如果须要应用题目给的nums数组的大小信息进行初始化的话,就在入口函数对used数组进行初始化,并传递援用;如果used不须要进行初始化,间接应用全局变量即可class Solution {private: vector<vector<int>> result; vector<int> path; void backtracking(vector<int> &candidates, int target, int sum, int startIndex, vector<bool> &used) { if (sum == target) { result.push_back(path); return; } //应用used辨别是树枝还是树层 for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) { // used[i - 1] == true,阐明同⼀树⽀candidates[i - 1]使⽤过 // used[i - 1] == false,阐明同⼀树层candidates[i - 1]使⽤过 // 要对同⼀树层使⽤过的元素进⾏跳过 if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) { continue; } sum += candidates[i]; path.push_back(candidates[i]); used[i] = true; backtracking(candidates, target, sum, i + 1, used); // 和39.组合总和的区别1,这⾥是i + 1,每个数字在每个组合中只能使⽤⼀次 used[i] = false; sum -= candidates[i]; path.pop_back(); } }public: vector<vector<int>> combinationSum2(vector<int> &candidates, int target) { vector<bool> used(candidates.size(), false); // ⾸先把给candidates排序,让其雷同的元素都挨在⼀起。 sort(candidates.begin(), candidates.end()); backtracking(candidates, target, 0, 0, used); return result; }};每个递归层都创立一个used数组去重,空间复杂度较高O(size*size)class Solution {private: vector<vector<int>> result; vector<int> path; void backtracking(vector<int> &candidates, int target, int sum, int startIndex) { if (sum == target) { result.push_back(path); return; } vector<bool> used(candidates.size(), false); for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) { // 要对同⼀树层使⽤过的元素进⾏跳过 if (i > 0 && candidates[i] == candidates[i - 1] && used[candidates[i - 1]]) { continue; } sum += candidates[i]; used[candidates[i]] = true; path.push_back(candidates[i]); backtracking(candidates, target, sum, i + 1); sum -= candidates[i]; // 每层都领有本人的used数组,不必置false path.pop_back(); } }public: vector<vector<int>> combinationSum2(vector<int> &candidates, int target) { path.clear(); result.clear(); // ⾸先把给candidates排序,让其雷同的元素都挨在⼀起。 sort(candidates.begin(), candidates.end()); backtracking(candidates, target, 0, 0); return result; }};

April 26, 2021 · 2 min · jiezi

关于c++:c中istringstream及ostringstream超详细说明

前文说过,istringstream是继承于istream,ostringstream是继承于ostream,而他们应用的缓冲区类是stringbuf。 对于这些类之间的关系,有趣味能够去查看我之前的文章:c++规范输入输出流关系梳理 1. stringbuf类介绍stringbuf类缓冲区应用一个std::string类作为存储介质,而后依据结构时的读写模式来对string类进行读写。 1.1 stringbuf类构造函数小贴士:explicit用来避免由构造函数定义的隐式转换。//依据传入的读写标示结构一个领有空string的缓冲区,默认可读可写explicit basic_stringbuf(ios_base::openmode __mode = ios_base::in | ios_base::out): __streambuf_type(), _M_mode(__mode), _M_string(){ }//复制一个已有的string作为缓冲区内容,且依据__mode来指定可读、可写或者读写,默认可读可写explicit basic_stringbuf(const __string_type& __str, ios_base::openmode __mode = ios_base::in | ios_base::out): __streambuf_type(), _M_mode(), _M_string(__str.data(), __str.size()){ _M_stringbuf_init(__mode); }应用例子如下: #include <sstream>using namespace std;int main(){ stringbuf *buf = new stringbuf(ios_base::in);//结构一个可写的空stringbuf string str("my name is haha"); stringbuf *bufStr = new stringbuf(str, ios_base::out); if ( buf != nullptr ) { delete buf; } if ( bufStr != nullptr ) { delete bufStr; } return 0;}1.2 str函数str函数原型如下: ...

April 26, 2021 · 2 min · jiezi

关于c#:原创基于NET的轻量级高性能-ORM-RizXFramework

前言接上一篇《【原创】打造基于Dapper的数据拜访层》,Dapper在应酬多表自在关联、分组查问、匿名查问等利用场景时未免显得吃力,常常要手写SQL语句(或者用工具生成SQL配置文件)。试想一下,我的项目中整个DAL层都塞满了SQL语句,对于前期保护来说无异于天下大乱,这个坑谁踩谁晓得。本框架在API设计上最大水平地借鉴 EntityFramework 的写法,洁净的实体,丝滑的增删改查,持重的导航属性,另外还反对链式查问(点标记)、查问表达式、聚合查问等等。在实体映射转换层面,应用 Emit 来动静构建绑定指令,性能最大限度地靠近原生程度。 XFramework 亮点原生.NET语法,零学习老本反对LINQ查问、拉姆达表达式反对批量增删改查和多表关联更新反对 SqlServer、MySql、Postgre、Oracle,.NET Core最大亮点,真正反对一对一、一对多导航属性。这一点置信现有开源的ORM没几个敢说它反对的实体字段类型不用与数据库的类型统一反对长期表、表变量操作提供原生ADO操作其它更多亮点,用了你就会晓得性能看看与EntityFramework的性能比照,机器配置不同跑进去的后果可能也不一样,仅供参考。须要特地阐明的是EntityFramework是用了AsNoTracking的,不然有缓存的话就没有比拟的意义了 性能阐明1. 实体定义如果类有 TableAttribute,则用 TableAttribute 指定的名称做为表名,否则用类名称做为表名实体的字段能够指定 ColumnAttribute 个性来阐明实体字段与表字段的对应关系,删除/更新时如果传递的参数是一个实体,必须应用 [Column(IsKey = true)] 指定实体的主键ForeignKeyAttribute 指定外键,一对多外键时类型必须是 IList 或者 ListColumnAttribute.DataType 用来指定表字段类型。以SQLSERVER为例,System.String 默认对应 nvarchar 类型。若是varchar类型,须要指定[Column(DbType= DbType.AnsiString)]`[Table(Name = "Bas_Client")]``public partial class Client``{` `/// <summary>` `/// 初始化 <see cref="Client"/> 类的新实例` `/// </summary>` `public Client()` `{` `this.CloudServerId = 0;` `this.Qty = 0;` `this.HookConstructor();` `}` `/// <summary>` `/// 初始化 <see cref="Client"/> 类的新实例` `/// </summary>` `public Client(Client model)` `{` `this.CloudServerId = 0;` `this.Qty = 0;` `this.HookConstructor();` `}` `/// <summary>` `/// clientid` `/// </summary>` `[Column(IsKey = true)]` `public virtual int ClientId { get; set; }` `/// <summary>` `/// activedate` `/// </summary>` `public virtual Nullable<DateTime> ActiveDate { get; set; }` `/// remark` `/// </summary>` `[Column(Default = "'默认值'")]` `public virtual string Remark { get; set; }` `[ForeignKey("CloudServerId")]` `public virtual CloudServer CloudServer { get; set; }` `[ForeignKey("ClientId")]` `public virtual List<ClientAccount> Accounts { get; set; }` `/// <summary>` `/// 构造函数勾子` `/// </summary>` `partial void HookConstructor();``}`2. 上下文定义`1 SQLSERVER:var context = new SqlDbContext(connString);``2 MySQL:var context = new MySqlDbContext(connString);``3 Postgre:var context = new NpgDbContext(connString);``4 Oracle:var context = new OracleDbContext(connString);`3. 匿名类型`//// 匿名类``var guid = Guid.NewGuid();``var dynamicQuery =` `from a in context.GetTable<TDemo>()` `where a.DemoId <= 10` `select new` `{` `DemoId = 12,` `DemoCode = a.DemoCode,` `DemoEnum = Model.State.Complete,// 枚举类型反对` `};``var result = dynamicQuery.ToList();``// 点标记``dynamicQuery = context` `.GetTable<TDemo>()` `.Where(a => a.DemoId <= 10)` `.Select(a => new` `{` `DemoId = 12,` `DemoCode = a.DemoCode,` `DemoEnum = Model.State.Complete,// 枚举类型反对` `});``result0 = dynamicQuery.ToList();`4. 所有字段`// Date,DateTime,DateTime2 反对``var query =` `from a in context.GetTable<TDemo>()` `where a.DemoId <= 10 && a.DemoDate > sDate && a.DemoDateTime >= sDate && a.DemoDateTime2 > sDate` `select a;``var result1 = query.ToList();``// 点标记``query = context` `.GetTable<TDemo>()` `.Where(a => a.DemoId <= 10 && a.DemoDate > sDate && a.DemoDateTime >= sDate && a.DemoDateTime2 > sDate);``result1 = query.ToList();`5. 指定字段`// 指定字段``query = from a in context.GetTable<TDemo>()` `where a.DemoId <= 10` `select new TDemo` `{` `DemoId = (int)a.DemoId,` `DemoCode = (a.DemoCode ?? "N001")` `};``result1 = query.ToList();``// 点标记``query = context` `.GetTable<TDemo>()` `.Where(a => a.DemoCode != a.DemoId.ToString() && a.DemoName != a.DemoId.ToString() && a.DemoChar == 'A' && a.DemoNChar == 'B')` `.Select(a => new TDemo` `{` `DemoId = a.DemoId,` `DemoCode = a.DemoName == "张三" ? "李四" : "王五",` `});``result1 = query.ToList();`6.构造函数用过 EntityFramework 的同学都晓得,如果要通过构造函数的形式查问指定字段,除非老老实实从新定义一个新的实体,否则一个 “The entity or complex type cannot be constructed in a LINQ to Entities query“ 的异样马上给甩你脸上。XFramework 框架的这个用法,就是为了让你远离这会呼吸的痛!~ ...

April 25, 2021 · 12 min · jiezi

关于docker:Ubuntu系统Docker环境安装远程服务开启以及Portainer访问

以下内容有可能须要迷信上网能力做到。 开始我这里应用的环境是阿里云ecs,零碎是Ubuntu 20.04 64位 docker 装置如果零碎是第一次装置docker,简略来说只须要执行两条命令 1.sudo apt-get update2.sudo apt-get install docker-ce docker-ce-cli containerd.io装置教程地址docker 官网文档 在装置实现之后输出docker info 查看docker信息 在 Windows10 零碎中,能够下载 Docker Desktop on Windows官网地址 留神,在装置docker之前,须要先装置并开启WSL(Windows中的Linux子系统)官网地址 Portainer 装置Portainer 是一款开源容器管理工具官网文档官网地址 1.docker volume create portainer_data2.docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce装置实现后能够在浏览器输出http://localhost:9000 来拜访。在第一次进入时须要设定明码。 能够通过增加 Endpoints 来治理近程的 Docker 容器 点击菜单中的 Endpoints,抉择 Environment type 中的 Docker ,轻易输出一个当前你能认出来的 Name ,而后填入 Endpoint URL ,这个 URL 就是你要治理的近程服务器的地址或者域名。失常状况下,如果你的服务器没有开启 TLS 认证的话,就能够点击 Add endpoint 按钮了。 ...

April 24, 2021 · 2 min · jiezi

关于c++:C内存管理4内存分配的重载示例

类内重载 operator new/operator delete 示例#include <iostream>#include <string>using namespace std;class Foo {public: int _id; int _data; int _num;public: // 如果没有重载的成员函数则调用全局版本 static void *operator new(size_t size); static void operator delete(void *pdead, size_t size); static void *operator new[](size_t size); static void operator delete[](void *pdead, size_t size); Foo() : _id(0) { cout << "default ctor.this=" << this << " id=" << _id << endl; } Foo(int i) : _id(i) { cout << "ctor. this=" << this << " id=" << _id << endl; } // virtual ~Foo() { cout << "dtor. this=" << this << " id=" << _id << endl; }};void *Foo::operator new(size_t size){ Foo *p = (Foo*)malloc(size); cout << "Foo::operator new(), size=" << size << "\t return: " << p << endl; return p;}void Foo::operator delete(void *pdead, size_t size){ cout << "Foo::operator delete(), pdead= " << pdead << " size= " << size << endl; free(pdead);}void *Foo::operator new[](size_t size){ Foo *p = (Foo*)malloc(size); cout << "Foo::operator new[](), size=" << size << "\t return: " << p << endl; return p;}void Foo::operator delete[](void *pdead, size_t size){ cout << "Foo::operator delete[](), pdead= " << pdead << " size= " << size << endl; free(pdead);}int main(){ cout << "sizeof(Foo)=" << sizeof(Foo) << endl; cout << "============" << endl; Foo *p = new Foo(7); delete p; cout << "============" << endl; Foo* pArray = new Foo[5]; delete [] pArray; return 0;}当 Foo 无虚析构函数时,输入: ...

April 24, 2021 · 5 min · jiezi

关于c:C-代码是如何跑起来的

上一篇「CPU 提供了什么」中,咱们理解了物理的层面的 CPU,为咱们提供了什么。 本篇,咱们介绍下高级语言「C 语言」是如何在物理 CPU 下面跑起来的。 C 语言提供了什么C 语言作为高级语言,为程序员提供了更敌对的表达方式。在我看来,次要是提供了以下形象能力: 变量,以及延长进去的简单构造体咱们能够基于变量来形容简单的状态。函数咱们能够基于函数,把简单的行为逻辑,拆分到不同的函数里,以简化简单的逻辑以。以及,咱们能够复用雷同目标的函数,事实世界里大量的根底库,简化了程序员的编码工作。示例代码构建一个良好的示例代码,能够很好帮忙咱们去了解。上面的示例里,咱们能够看到 变量 和 函数 都用上了。 #include "stdio.h"int add (int a, int b) { return a + b;}int main () { int a = 1; int b = 2; int c = add(a, b); printf("a + b = %d\n", c); return 0;}编译执行毫无意外,咱们失去了冀望的 3。 $ gcc -O0 -g3 -Wall -o simple simple.c$ ./simplea + b = 3汇编代码咱们还是用 objdump 来看看,编译器生成了什么代码: 变量局部变量,包含函数参数,全副被压入了 栈 里。函数函数自身,被独自编译为了一段机器指令函数调用,被编译为了 call 指令,参数则是函数对应那一段机器指令的第一个指令地址。$ objdump -M intel -j .text -d simple# 截取其中最重要的局部000000000040052d <add>: 40052d: 55 push rbp 40052e: 48 89 e5 mov rbp,rsp 400531: 89 7d fc mov DWORD PTR [rbp-0x4],edi 400534: 89 75 f8 mov DWORD PTR [rbp-0x8],esi 400537: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 40053a: 8b 55 fc mov edx,DWORD PTR [rbp-0x4] 40053d: 01 d0 add eax,edx 40053f: 5d pop rbp 400540: c3 ret0000000000400541 <main>: 400541: 55 push rbp 400542: 48 89 e5 mov rbp,rsp 400545: 48 83 ec 10 sub rsp,0x10 400549: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1 400550: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2 400557: 8b 55 f8 mov edx,DWORD PTR [rbp-0x8] 40055a: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 40055d: 89 d6 mov esi,edx 40055f: 89 c7 mov edi,eax 400561: e8 c7 ff ff ff call 40052d <add> 400566: 89 45 f4 mov DWORD PTR [rbp-0xc],eax 400569: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc] 40056c: 89 c6 mov esi,eax 40056e: bf 20 06 40 00 mov edi,0x400620 400573: b8 00 00 00 00 mov eax,0x0 400578: e8 93 fe ff ff call 400410 <printf@plt> 40057d: b8 00 00 00 00 mov eax,0x0 400582: c9 leave 400583: c3 ret 400584: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0] 40058b: 00 00 00 40058e: 66 90 xchg ax,ax函数内的局部变量,为什么会放入栈空间呢?这个刚好和局部变量的作用域关联起来了: ...

April 24, 2021 · 3 min · jiezi

关于c++:C11的conditionvariable实现WaitForSingleObject功能

在多线程程序开发中,咱们有时会心愿期待其余线程完结后在继续执行某些工作。比方常见的,主线程须要期待其余所有子线程完结后再完结程序。在Windows下咱们个别应用WaitForSingleObject,或者WaitForMultipleObjects来实现,它们都会期待Object被设置为有信号时才返回的。这样咱们在主线程完结的中央wait,在子线程完结的中央设置信号,就能实现上述性能。然而这个API是Windows下的,无奈跨平台应用。还好C++11为咱们带来了多线程的反对。在C++11中咱们能够通过mutex和condition_variable来达到类似成果。上面是我写的小例子。 #include <iostream>#include <thread>#include <mutex>#include <condition_variable>#include <chrono>std::mutex mx;std::mutex g_mx;std::condition_variable g_cv;uint32_t g_thread_num = 0;void function_1(){ for (int i = 0; i < 100; i++) { std::lock_guard<std::mutex> loc(mx); std::cout << "from function 1:" << i << std::endl; } std::unique_lock<std::mutex> guard(g_mx); --g_thread_num; g_cv.notify_one(); guard.unlock(); std::cout << "function 1 end" << std::endl;}void function_2(){ for (int i = 0; i < 100; i++) { std::lock_guard<std::mutex> loc(mx); std::cout << "from function 2:" << i << std::endl; } std::unique_lock<std::mutex> guard(g_mx); --g_thread_num; g_cv.notify_one(); guard.unlock(); std::cout << "function 2 end" << std::endl;}void function_3(){ for (int i = 0; i < 100; i++) { std::lock_guard<std::mutex> loc(mx); std::cout << "from function 3:" << i << std::endl; } std::this_thread::sleep_for(std::chrono::seconds(3)); std::unique_lock<std::mutex> guard(g_mx); --g_thread_num; g_cv.notify_one(); guard.unlock(); std::cout << "function 3 end" << std::endl;}int main(){ std::thread t1(function_1); { std::unique_lock<std::mutex> guard(g_mx); ++g_thread_num; } t1.detach(); std::thread t2(function_2); { std::unique_lock<std::mutex> guard(g_mx); ++g_thread_num; } t2.detach(); std::thread t3(function_3); { std::unique_lock<std::mutex> guard(g_mx); ++g_thread_num; } t3.detach(); for (int i = 0; i < 100; i++) { std::lock_guard<std::mutex> loc(mx); std::cout << "from function main:" << i << std::endl; } { std::unique_lock<std::mutex> guard(g_mx); g_cv.wait(guard, []() { return g_thread_num == 0; }); } std::cout << "main end" << std::endl; return 0;}例子写的很简略,其实能够简略封装下会更好用。大家如果有什么更好的解决方案也欢送交换。

April 24, 2021 · 1 min · jiezi

关于c++:C内存管理4内存分配的重载

C++ 应用程序,内存调配的路径默认的内存调配形式 对于 ① 处的阐明(成员函数的自定义内存调配)可通过自定义内存池的形式进步应用效率,如更快的调配速度,更省的内存空间(省去 cookie)对于 ② 处的阐明 (重载全局空间的内存管理策略)全局的内存管理策略会被多处无意或无心的应用,代码会大范畴的收到影响,可重载但少见容器的内存调配形式 容器并未采纳默认的内存治理形式,而采纳内存分配器从新实现内存调配与结构被从新封装彼此拆散内存开释与析构被从新封装彼此拆散Foo *p = (Foo)operator new(sizeog(Foo)); // 内存申请new(p) Foo(x); // 结构...p->~Foo(); // 析构operator delete(p); // 内存开释全局重载 ::operator new / ::operator deletevoid *myAlloc(size_t size){ return malloc(size);}void myFree(void *ptr){ return free(ptr);}void *operator new(size_t size){ cout << "global new" << endl; return myAlloc(size);}void *operator new[] (size_t size){ cout << "global new[]" << endl; return myAlloc(size);}void operator delete(void *ptr) noexcept{ cout << "global delete" << endl; myFree(ptr);}void operator delete[] (void *ptr) noexcept{ cout << "global delete" << endl; myFree(ptr);}operator new 的一种实现 [...\vc98\src\newop.cpp]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 (_callnewh(size) == 0) break; __CATCH(std::bad_alloc) return (0); __CATCH_END; } return (p);}operator delete 的一种实现 [...\vc98\src\delop.cpp]void __cdecl operator delete(void *p) _THROW0(){ // free an allocated object free(p);}类内重载 operator new/operator deleteclass Foo {public: void *operator new(size_t); void operator delete(void*, size_t[可选]);}------------------------------Foo *p = new Foo;==>try { void *mem = operator new(sizeof(Foo)); p = static_cast<Foo*>(sizeof(Foo)); p->Foo::Foo();}------------------------------delete p;==>p->~Foo();operator delete(p);类内重载 operator new, operator delete 的成员函数具备 static 属性非动态成员函数须要对象(暗藏的this指针)实现调用,而 operator new 被调用时示意对象正在被创立类内重载 operator new[]/operator delete[]class Foo {public: void *operator new[](size_t); void operator delete[](void*, size_t[可选]); // ...};------------------------------Foo *p = new Foo[N];==>try { void *mem = operator new(sizeof(Foo) * N + 4); p = static_cast<Foo*>(mem); p->Foo::Foo(); // N 次}------------------------------delete[] p;==>p->~Foo(); // N 次operator delete(p);类内重载 operator new[], operator delete[] 的成员函数具备 static 属性非动态成员函数须要对象(暗藏的this指针)实现调用,而 operator new[] 被调用时示意对象正在被创立

April 24, 2021 · 2 min · jiezi

关于c++:C内存管理3placement-new

placement new 容许咱们将 object 构建于 allocated memory 中;没有所谓 placement delete, 因为 placement new 基本没调配 memory;亦或称说与 placement new 对应的 operator delete 为 placement delete。 #include <new>char *buf = new char[sizeof(Complex) * 3];Complex *pc = new(buf) Complex (1, 2);// ...delete[] buf; Complex *pc = new(buf) Complex (1, 2);编译器转换为 ==>Complex *pc;try { void* mem = operator new (sizeof(Complex), buf); // allocate pc = static_cast<Complex*>(mem); // cast pc->Complex::Complex(1, 2); // construct}catch(std::bad_alloc) { // 若 allocation 失败就不执行 constructor }void* mem = operator new (sizeof(Complex), buf);源码实现 ==>void *operator new (size_t, viud *loc){ return loc;}

April 24, 2021 · 1 min · jiezi

关于c++:C内存管理2array-new-arraydelete

资源透露危险剖析示例一: // 1. 唤起 三次构造函数// 2. 无奈藉由参数进行初始化,因而 Complex 须要有默认构造函数Complex *pca = new Complex[3];......// 3. 唤起三次析构函数delete[] pca; 示例二: // 1. 唤起 三次构造函数// 2. 无奈藉由参数进行初始化,因而 string须要有默认构造函数string *psa = new string[3];......// 3. 唤起一次析构函数delete psa;问:没对数组外面的每个对象调用析构函数(示例二),会有什么影响呢? 对 class without pointer 可能没有影响(不会有资源泄露)对 class with pointer 通常有影响 (会有资源泄露)阐明: 示例一中,当 delete pca; pca 指向的全副内存空间将会被平安开释示例二中,当 delete psa; psa 指向的全副内存空间将会被平安开释,但因为 string 实现中蕴含指针指向一段堆空间中申请的内存空间以存储字符串,而数组元素数量的析构函数未被全副对应调用,导致字符串空间未被开释,因而会造成资源泄露总结 new, delete ; new [], delete [] 须要配对应用数组元素的结构与析构程序#include <iostream>using namespace std;class A{public: int id; A() : id(0) { cout << "default ctor.this=" << this << " id=" << id << endl; } A(int i) : id(i) { cout << "default ctor.this=" << this << " id=" << id << endl; } ~A() { cout << "dtor.this=" << this << " id=" << id << endl; }};constexpr size_t size = 3;int main(){ // A 必须有默认构造函数 // 默认结构函数调用三次,[0] 先于 [1] 先于 [2] A *buf = new A[size]; A* tmp = buf; cout << "buf=" << buf << " tmp=" << tmp << endl; for (size_t i=0; i < size; ++i) { // placement new: 在指定的地址结构对象 new (tmp++)A(i); } cout << "buf=" << buf << " tmp=" << tmp << endl; // 析构函数三次被调用(秩序逆反,[2] 先于 [1] 先于 [0]) delete[] buf; return 0;}总结 ...

April 24, 2021 · 2 min · jiezi

关于c:辗转相除法求整数的最大公约数和最小公倍数

求整数的最大公约数和最小公倍数 include<stdio.h>int main(){ int a,b;int t;int m,n;scanf("%d %d",&a,&b);m=a;n=b;/*a=12,b=18a b t12 18 1218 12 612 6 06 0 */while(b!=0){ t=a%b; a=b; b=t;}printf("最大公约数为%d",a);printf("最小公倍数为%d",m*n/a);return 0;}

April 23, 2021 · 1 min · jiezi

关于c:整数分解

题目:输出一个整数,正序输入它的每一个数字。如 输出:12345 输入:1 2 3 4 5 输出:700 输入:7 0 0 留神最初一个数字后无空格。代码如下: #include<stdio.h>int main(){ //输出 int input; scanf("%d",&input); int mask=1; //从新创立一个变量用来存input值 int testValue = input; //循环:当testValue大于9或大于等于10,满足循环要求 while(testValue>9){ //如果整数有5位,那么mask最终就会为10000,用来做最开始的除数 testValue /= 10; mask *= 10; } // printf("mask = %d,testValue = %d",mask,testValue); //能够用来测试以后代码mask值 do{ //用来将最高位分来到:如1434/1000=1; 434/100=4; 34/10=3;4/1=4; int receive = input/mask; //使最初一个数字后没有空格 if(mask>9){ printf(" "); } //用来去除最高位1434%1000=434;。。。 input = input%mask; //放大mask,求整数对应位数的数字 mask /= 10; } while(mask>0); return 0;}

April 23, 2021 · 1 min · jiezi

关于c:c语言结构体字节对齐详解

1.什么是字节对齐在c语言的构造体外面个别会依照某种规定去进行字节对齐。 咱们先看一段代码: struct st1{ char name; double age; char sex;};//32位下 sizeof(struct st1) = 16//64位下 sizeof(struct st1) = 24struct st2{ char a; char b; char c;};//32位和64位下, sizeof(struct st2)都是3个字节从以上后果能够看出,构造体st1在32位下是依照4个字节来对齐的,在64位下则是依照8个字节来对齐的,构造体st2则不论32位还是64位则都是依照1个字节对齐的。 那么咱们能够总结出对齐规定如下: 在所有构造体成员的字节长度都没有超出操作系统根本字节单位(32位操作系统是4,64位操作系统是8)的状况下,依照构造体中字节最大的变量长度来对齐;若构造体中某个变量字节超出操作系统根本字节单位,那么就依照零碎字节单位来对齐。留神:并不是32位就间接依照4个字节对齐,64位依照8个字节对齐。2.为什么要有字节对齐首先遍及一点小常识,cpu一次能读取多少内存要看数据总线是多少位,如果是16位,则一次只能读取2个字节,如果是32位,则能够读取4个字节,并且cpu不能跨内存区间拜访。 假如有这样一个构造体如下: struct st3{ char a; int b;};//那么依据咱们第1节所说的规定,在32位零碎下,它就应该是8个字节的。假如地址空间是相似上面这样的: 在没有字节对齐的状况下,变量a就是占用了0x00000001这一个字节,而变量b则是占用了0x00000002~0x000000005这四个字节,那么cpu如果想从内存中读取变量b,首先要从变量b的开始地址0x00000002读到0x0000004,而后再读取一次0x00000005这个字节,相当于读一个int,cpu从内存读取了两次。 而如果进行字节对齐的话,变量a还是占用了0x00000001这一个字节,而变量b则是占用了0x00000005~0x00000008这四个字节,那么cpu要读取变量b的话,就间接一次性从0x00000005读到0x00000008,就一次全副读取进去了。 所以说,字节对齐的根本原因其实在于cpu读取内存的效率问题,对齐当前,cpu读取内存的效率会更快。然而这里有个问题,就是对齐的时候0x00000002~0x00000004这三个字节是节约的,所以字节对齐实际上也有那么点以空间换工夫的意思,具体写代码的时候怎么抉择,其实是看集体的。 3.手动设置对齐什么状况下须要手动设置对齐: 设计不同CPU下的通信协议,比方两台服务器之间进行网络通信,共用一个构造体时,须要手动设置对齐规定,确保两边构造体长度始终;编写硬件驱动程序时寄存器的构造;手动设置对齐形式有两种: 代码里增加预编译标识://用法如下#pragma pack(n)//示意它前面的代码都依照n个字节对齐struct st3{ char a; int b;};#pragma pack()//勾销依照n个字节对齐,是对#pragma pack(n)的一个反向操作//这里计算sizeof(st3)=5下面这两行其实就相似于开车的时候,走到某一段路的时候,发现一个限速60公里的指示牌,过了那一段路当前,又会有解除限速60公里的指示牌。 定义构造体时://用法如下struct bbb{ char a; int b;}__attribute__((packed));//间接依照理论占用字节来对齐,其实就是相当于依照1个字节对齐了//这里计算sizeof(st3)=54.构造体比拟办法能够应用内存比拟函数memcpy进行构造体比拟,但因为构造体对齐可能会有填充位不统一的状况,此时须要留神: 设置为1个字节对齐,使它没有空位;当时对构造体进行初始化;memcpy(char *dest, const char* src, int len); //头文件#include<string.h>

April 22, 2021 · 1 min · jiezi

关于.net:2021-Top-100-CNET-Interview-Questions-And-Answers

https://jackniu81.github.io/2021/04/22/2021-Top-100-C-NET-Interview-Questions-And-Answers/1. What is the difference between “dispose” and “finalize” variables in C#?Dispose - This method uses interface – “IDisposable” interface and it will free up both managed and unmanaged codes like – database connection, files etc.Finalize - This method is called internally unlike Dispose method which is called explicitly. It is called by garbage collector and can’t be called from the code.2. What does “Jagged Arrays” mean?Answer: Jagged arrays refer to the array that has an element of type array. The dimensions and the sizes of the elements are different. An array of arrays is the other name of the jagged array. ...

April 22, 2021 · 29 min · jiezi

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

导读:在百度看似简简单单的界面前面,是遍布全国的各个数据中心里,运行着的海量C++服务。如何晋升性能,升高延时和老本就成了百度C++工程师的必修功课。随同着优化的深刻攻坚,诞生并积攒下来一系列的性能优化实践和计划,其中不乏一些冷门但精美实用的教训和技巧。本文从内存拜访角度,收集总结了一些具备通用意义的典型案例,分享进去和大家学习交换。 1  背景在百度看似简简单单的界面前面,是遍布全国的各个数据中心里,运行着的海量C++服务。对C++的重度利用是百度的一把双刃剑,学习老本平缓,指针类谬误定位难、扩散性广另很多开发者望而生畏。然而在另一方面,语言层引入的额定开销低,对底层能力可操作性强,又可能为谋求极致性能提供优异的实际环境。 因而,对百度的C++工程师来说,把握底层个性并加以利用来领导利用的性能优化,就成了一门必要而且必须的技能。长此以往,百度工程师就将这种谋求极致的性能优化,逐步积淀成了习惯,甚至造成了对技术的信奉。上面咱们就来盘点和分享一些,在性能优化的征途上,百度C++工程师积攒下来的实践和实际,以及那些为了谋求极致,所挖掘的『奇技淫巧』。 2  重新认识性能优化作为程序员,大家或多或少都会和性能打交道,尤其是以C++为主的后端服务工程师,然而每个工程师对性能优化概念的了解在细节上又是千差万别的。上面先从几个优化案例动手,建设一个性能优化相干的感性认识,之后再从原理角度,形容一下本文所讲的性能优化的切入角度和办法根据。 2.1  从字符串解决开始2.1.1  string as a buffer为了调用底层接口和集成一些第三方库能力,在调用界面层,会存在对C++字符串和C格调字符串的交互场景,典型是这样的: size\_t some\_c\_style\_api(char\* buffer, size\_t size);void some\_cxx\_style\_function(std::string& result) { // 首先扩大到短缺大小 result.resize(estimate\_size); // 从c++17开始,string类型反对通过data获得十分量指针 auto acture\_size = some\_c\_style\_api(result.data(), result.size()); // 最终调整到理论大小 result.resize(acture\_size);}这个办法存在一个问题,就是在首次resize时,string对estimate\_size内的存储区域全副进行了0初始化。然而这个场景中,理论的无效数据其实是在some\_c\_style\_api外部被写入的,所以resize时的初始化动作其实是冗余的。在交互buffer的size较大的场景,例如典型的编码转换和压缩等操作,这次冗余的初始化引入的开销还是相当可观的。 为了解决这个问题,大概从3年前开始,曾经有人在继续尝试推动规范改良。 http://www.open-std.org/jtc1/...注:在这个问题上应用clang + libc++的同学有福,较新版本的libc++中曾经非标实现了resize\_default\_init性能,能够开始尝鲜应用。 在规范落地前,为了可能在百度外部(目前宽泛应用gcc8和gcc10编译器)提前应用起来,咱们专门制作了实用于gcc的resize\_uninitialized,相似于下面的性能,在百度,能够这样编码: size\_t some\_c\_style\_api(char\* buffer, size\_t size);void some\_cxx\_style\_function(std::string& result) { auto\* buffer = babylon::resize\_uninitialized(result, estimate\_size); auto acture\_size = some\_c\_style\_api(buffer, result.size()); result.resize(acture\_size);}2.1.2  split string理论业务中,有一个典型场景是一些轻schema数据的解析,比方一些规范分隔符,典型是'\_'或者'\t',简略宰割的分列数据(这在日志等信息的粗加工解决中分外常见)。因为场景极其单纯,可能的算法层面优化空间个别认为较小,而理论实现中,这样的代码是广为存在的: std::vector<std::string> tokens;// boost::splitboost::split(token, str, \[\] (char c) {return c == '\\t';});// absl::StrSplitfor (std::string\_view sv : absl::StrSplit(str, '\\t')) { tokens.emplace\_back(sv);}// absl::StrSplit no copyfor (std::string\_view sv : absl::StrSplit(str, '\\t')) { direct\_work\_on\_segment(sv);}boost版本宽泛呈现在新工程师的代码中,接口灵便,流传度高,然而理论业务中效率其实并不优良,例如和google优化过的absl相比,其实有倍数级的差距。尤其如果工程师没有留神进行单字符优化的时候(间接应用了官网例子中的is\_any\_of),甚至达到了数量级的差距。进一步地,如果联动思考业务状态,个别典型的宰割后处理是能够做到零拷贝的,这也能够进一步升高冗余拷贝和大量长期对象的创立开销。 ...

April 22, 2021 · 3 min · jiezi

关于c++:WonderTrader架构详解之四浅谈平台对策略的支持

前言 《WonderTrader架构详解》系列文章,上一篇介绍了WonderTrader的信号执行的解决机制。平台的数据和信号执行机制曾经实现当前,接下来就是要思考如何生成信号了,也就是说策略如何编写。在解决策略编写的问题之前,首先要解决的就是平台要反对哪些策略。本文作为系列文章的第四篇,将针对WonderTrader对不同策略的反对展开讨论。 往期文章列表: WonderTrader架构详解之一——整体架构WonderTrader架构详解之二——从数据说起WonderTrader架构详解之三——信号与执行策略的分类 如何对策略进行分类,这个问题自身就很简单。很多介绍策略的书都会对策略进行一个分类,而后再开展介绍,然而每位作者都有本人的分类规范,所以每本书里介绍的策略分类也不尽相同。笔者已经拜读过几本,比拟有代表性的就是丁鹏的《量化投资——策略与技术》。这本书里大抵分为以下几个大类策略: 量化选股策略 多因子选股格调轮动选股行业轮动选股资金流选股动量反转选股……量化择时策略 趋势追踪择时市场情绪择时无效资金择时牛熊线择时Hurst指数择时...股指期货套利 期现套跨期套商品期货套利 期现套跨期套跨种类套利跨市场套利统计套利 配对交易股指套利融券套利外汇套利…… 然而对于量化平台来说,以上的分类都没有理论的意义。为什么呢?因为平台须要思考的是从技术角度如何对策略进行分类,而下面展现的策略分类都是从策略实现的逻辑和指标交易种类来进行分类的。 那么从技术实现的角度角度对策略进行分类要思考哪些问题呢? 行情数据的需要 从技术实现的角度来说,策略对数据的需要会引起很大的架构变动。比如说有些策略须要K线数据进行信号的计算,有些策略须要tick数据进行信号的计算,而有些策略同时须要K线数据和tick数据进行计算。平台在对策略凋谢接口的时候,就必须要思考到不同策略的数据需要。以趋势追踪策略为例,趋势追踪策略个别应用K线数据进行信号计算,然而在理论经营的过程中可能也须要利用实时的tick数据进行一个止盈止损逻辑的触发。平台在思考策略对数据的需要的同时,还须要思考在实盘过程中对策略所须要的数据如何进行缓存、如何进行实时的更新、以及如何传递给策略。信号执行的需要 策略对信号执行的需要,次要是执行响应速度和执行办法两个方面。对于很多日频调仓的策略来说,如多因子选股,个别状况下须要执行较大数量的调仓,对于执行的要求绝对较低,次要依据执行当天的均匀成交价作为一个参考基准,在一天内执行实现即可。而对于高频策略来说,单次执行的数量个别较少,须要立刻响应信号,在微秒级的提早下收回下单指令。而对于日内调仓的策略来说,单次执行的数量介于多因子和高频之间,对执行的要求也介于二者之间:一方面不心愿太大的提早,造成太大的滑点;另一方面须要也不可能以一天的成交均价作为基准,反而以下一个周期的开盘价作为成交价的参考基准。重算调度的需要 不论是何种策略,都须要一个机制驱动策略进行外围逻辑的计算。个别策略采纳的驱动形式次要是事件驱动和工夫驱动。工夫驱动,就是到了某个规定确定的工夫节点,驱动策略的外围逻辑进行重算。而事件驱动,咱们这里次要指的是K线闭合、K线开始、tick进入等事件。对于基于K线的日内趋势策略,个别须要在K线闭合的时候进行重算;而基于日K线的跨日趋势策略,则能够在开盘后到第二天收盘前进行重算;对于高频策略,则须要在每一笔tick到来的时候进行重算。跟踪标的的需要 跟踪标的的需要,次要思考的是跟踪的标的数量。如果你是做国内商品期货的,个别状况下,即便沉闷种类的主力合约全副跟踪,也只有40多个。而如果要跟踪沪深300的成分股、或者中证1000的成分股,那么如何设计才可能满足这样的利用场景,就是一个十分重要的问题。 综合下面几点,WonderTrader最终从技术实现的角度将策略分类成三个大类: 日内趋势类策略 日内趋势类策略,不是说策略只做日内交易,而是指策略会在日内触发信号,即在交易工夫内的某个工夫点触发信号。这类策略个别策略逻辑都是基于分钟K线数据进行外围逻辑的重算,利用tick数据进行止盈止损逻辑的计算。这类策略信号强度个别较高,不须要在执行的过程中依据订单的成交状况动静调整执行策略,可能容忍肯定水平的滑点,属于笔者在上一篇《信号与执行》中提到的“重逻辑轻执行”的策略。高频类策略 高频类策略,次要利用tick数据触发外围逻辑重算,对于信号响应的提早特地敏感,而且呈现信号当前,还须要依据订单的执行状况实时调整信号。这类策略的盈利空间很小所以对滑点的容忍度非常低,因而须要平台解决信号要尽可能地快,属于笔者在上一篇《信号与执行》中提到的“轻逻辑重执行”的策略。选股类策略 选股类策略,次要指的是日频以上周期调仓的策略,以多因子选股策略为代表,所以称为选股类策略。选股类策略,计算量大、计算工夫长,资金容量大,信号的特点是数量大,对滑点也不敏感。因而这类策略对于信号执行的成果容忍度也比拟高。不过正是因为这些特点,选股类策略如果搭配更适合的执行算法的话,对绩效能够晋升好几个点。对于大规模的资金容量来说,几个点的晋升也是一个十分可观的数字了。因而选股类策略,对执行算法的需要,就体现须要在更长的时间跨度上,找到更适合的交易点。WonderTrader的策略引擎 针对下面的策略技术分类,WonderTrader提供了三种策略引擎,以满足不同类型策略的需要。 CTA引擎 CTA引擎(类名WtCtaEngine),是WonderTrader针对日内趋势类策略设计的策略引擎,因为最早次要是针对CTA策略的,所以引擎名字就依照CTAEngine沿用下来了。 CTA策略在初始化的时候,会向CTA引擎订阅一个主K线,也能够同时订阅其余周期或者其余种类的K线。CTATicker收到行情当前,会依据工夫戳判断是否有K线闭合,如果有K线闭合,则触发策略的on_bar回调;如果闭合的是主K线,则查看是否所有的K线都曾经闭合;如果所有K线都曾经闭合,则触发策略的on_schedule回调进行策略外围逻辑的重算。如果呈现新的信号,则由CTAEngine汇总当前失去一个指标组合,再丢给执行管理器。执行管理器则将指标组合散发到各个执行通道,并由执行通道转成交易指令下达交易所。如果没有K线闭合或者K线闭合事件曾经解决实现,再触发策略的on_tick回调进行风控运算。 下图展现了CTA引擎中策略信号产生和执行的根本流程: HFT引擎 HFT引擎(类名WtHftEngine),是WonderTrader针对高频类策略设计的策略引擎。 HFT策略在初始化的时候,会向HFT引擎订阅一些合约的tick数据(如果通道反对的话,还能够订阅股票Level2数据),也能够订阅K线数据(不分主次)。HFTTicker收到行情当前,和CTA引擎不同的是,不会查看是否有K线闭合,而是间接触发策略的on_tick回调进行外围逻辑的重算。如果呈现新的信号,则间接通过交易通道收回交易指令。交易通道收到订单回报当前,会触发策略的on_order回调,如果策略有调整,则再收回新的交易指令。交易通道收到成交回报当前,会触发策略的on_trade回调,如果有相应的调整,又会收回新的交易指令。 下图展现了HFT引擎中策略信号产生和执行的根本流程: SEL引擎 SEL引擎(类名WtSelEngine),是WonderTrader针对选股类策略设计的策略引擎。因为选股类策略具备计算工夫长和计算量大的特点,并且通常是非交易工夫重算,所以SEL引擎实质上是一个工夫驱动的引擎。SEL引擎在设计的时候,要兼顾盘后计算和盘中计算两种需要,所以整个策略的重算是异步的。 SEL策略在初始化的时候,会向SEL引擎注册一个工夫驱动的策略。例如每天、每周、每月、每年指定的工夫触发重算,或者在交易工夫内每N分钟触发重算。在非交易工夫,因为没有行情接入,所以SEL引擎会依据本地工夫进行比拟,如果满足工夫条件,则触发策略的on_schedule回调进行外围逻辑的重算。如果注册的是交易工夫内的分钟线驱动,则通过SELTicker依据最新接管到的tick数据的工夫戳进行行情工夫同步,再触发策略的on_schedule回调进行外围逻辑的重算。如果有新的信号产生,则将指标组合丢给执行管理器。执行管理器则将指标组合散发到各个执行通道,执行通道会依据预设的算法交易进行拆单,并依据算法交易的逻辑在适合的实机会由执行通道转成交易指令下达交易所。 策略引擎现状的思考 后面介绍的WonderTrader不同的策略引擎的外围逻辑,曾经基本上能够笼罩市面上绝大部分策略调度的需要了。不过对于WonderTrader的策略引擎,笔者目前也存在一些疑虑。 HFT引擎对做市策略的反对 WonderTrader为了简化策略的逻辑,将策略的信号全副简化为买和卖。这样的简化,省掉了策略研发人员很多事件,比方:到底是买开还是买平?可平今仓残余多少、可平昨仓残余多少?当初买进的信号要拆成几个单子下进来?单笔下单的最大数量是多少?WonderTrader会把这些问题全副主动解决掉。比方:主动依据持仓确定是开仓还是平仓;主动依据预设的开平计划管制是平仓还是锁仓;主动依据可平数量拆分信号为多个订单。笔者置信绝大部分策略研发都会喜爱这样的简化,然而有一种策略可能会例外:做市策略。 做市策略个别的交易逻辑是在高位挂一个卖单,同时在低位挂一个买单,通过赚取两个单子之间的价差获取收益。问题在于,如果依照后面提到的一些主动解决计划,开始的时候是没有持仓的,同时挂的两个订单成交当前,持仓呈一多一空的状态,净头寸依然为0。如果这个时候呈现第二轮信号,就可能会呈现一些问题:买入订单会平掉空头的头寸,卖出订单会平掉多头的头寸。持仓的状况会如此重复,对于有些策略来说可能就不大适应了。 SEL引擎回测的难点 SEL引擎回测的难点起源于实盘中的策略的外围逻辑是异步执行的。比如说,t0时刻触发了策略的重算,重算工夫较长,始终继续到t1时刻。如果在生产环境下,间接在t1时刻执行新的信号即可。然而对于回测环境下,如果采纳同步回测的形式,回测时执行的价格为t0时刻的p0;如果采纳异步形式回测的话,回测行情回放的工夫又比生产环境快很多,到了t1时刻行情早已回放超过t1了,这时的执行价格变成了t2时刻的p2了,而不是t1时刻的p1。综合来说,SEL引擎回测后果的参考价值要比CTA引擎小很多。笔者也已经思考过,依据重算工夫t,计算t0+t时刻,找到该时刻的pt作为执行价格。这样的解决形式看起来比拟可行,然而也会引入更多的复杂度。 WonderTrader的布局 后面大抵介绍了WonderTrader各个策略引擎的一些根本状况。通过多方调研,笔者认为从底层来说WonderTrader反对的利用场景曾经足够丰盛了。然而在WonderTrader使用和推广的过程中,笔者也发现了一些预计之外的需要,这些也是前面WonderTrader欠缺的方向。 欠缺交易接口 目前来说,WonderTrader只反对一般的交易接口,能够抽象地概括为现金业务的交易接口。实际上还有其余业务类型,例如ETF申赎、期权询价报价、期权行权、两融业务等等。笔者前面会依据理论的须要逐渐的欠缺这些接口,让WonderTrader反对更多的业务类型。 适配更多种类 从WonderTrader目前的推广的反馈来看,不少用户心愿利用WonderTrader进行数字货币的交易。而后因为数字货币7×24小时交易的特点,目前WonderTrader还不能很好的反对。抛开技术细节不谈,本源还是在于WonderTrader原本设计的指标就是针对惯例的交易市场的,即便是NYMEX这样的交易所,每天也有1个小时的休市工夫。当然,这不能成为WonderTrader固步自封的理由,所以将来WonderTrader也会逐笔欠缺对不同市场和不同种类的适配。 为应用层凋谢性能扩大接口 WonderTrader在设计的时候,为了保障底层的执行效率,所有的性能组件都是用C++开发的。功夫不负有心人,WonderTrader零碎外部提早,在个别台式机上也能达到10微秒以内。然而在推广的过程中,笔者发现局部用户实际上是基于wtpy做开发的,并没有C++的开发能力。然而这样的用户想要做一些二次开发的话,都须要C++底层做同步调整,于是这些用户只能望而生畏了。鉴于这样的状况,笔者也重复斟酌了一下,打算在将来思考将行情接入模块、交易模块向应用层子框架开发。这样的益处就是,一些二次开发的门槛也同步升高了,能够丰盛WonderTrader的生态,给不同需要的人群提供更丰盛的抉择。 结束语 本文对WonderTrader的策略引擎的介绍就到此结束了,心愿本文能给一些想要应用WonderTrader进行策略开发的敌人一些指引。笔者程度无限,不免有错漏之处,还请各位朋友多多包涵斧正。下一篇,笔者将针对不同的策略引擎,来具体介绍WonderTrader不同类型策略的回测的机制,望各位读者届时多多捧场。 最初再安利一下WonderTrader WonderTrader旨在给各位量化从业人员提供更好的轮子,将技术相干的货色都封装在平台中,打造更高效的底层框架,力求给策略研发带来更好的策略开发和交易体验。 WonderTrader的github地址:https://github.com/wondertrad... WonderTrader官网地址:https://wondertrader.github.io wtpy的github地址:https://github.com/wondertrad... 市场有危险,投资需谨慎。以上陈说仅作为对于历史事件的回顾,不代表对将来的观点,同时不作为任何投资倡议。

April 19, 2021 · 1 min · jiezi

关于c:计算数组交集

两个数组计算交加题目形容给定两个数组,编写一个函数来计算它们的交加。 示例 示例 1:输出:nums1 = [1,2,2,1], nums2 = [2,2]输入:[2]示例 2:输出:nums1 = [4,9,5], nums2 = [9,4,9,8,4]输入:[9,4]阐明: 输入后果中的每个元素肯定是惟一的。 咱们能够不思考输入后果的程序。办法办法一:bitmap + 与运算1.创立两个bitmap:bitmap1、bitmap2,别离用 nums1、nums2 来初始化 bitmap1、bitmap2:将 nums1中的值作为 bitmap1 的索引,并将该索引对应的值置为 1;bitmap2 同理2.创立一个 result数组,用于保留后果3.bitmap1 和 bitmap2 一一元素进行 与运算,若 与运算后果为1,则将值赋值给 result,同时 (*resultSize)++,result中为 1 的元素就是交加,*resultSize就是交加元素个数毛病:三个大数组,空间开销大办法二:排序 + 比拟1.qsort对两个数组排序2.创立result数组,大小为 nums1Size 和 nums2Size 中较小的那个2.一一比拟 nums1[i]、nums2[j]中的元素 若想等 并且 nums1[i] 不等于 prev,则将 nums1[i] 保留至result中,i++,j++ 若不相等,将 nums1[i]、nums2[j] 中较小的值得索引向后偏移代码bitmap + 与运算#define MAX 2048/** * Note: The returned array must be malloced, assume caller calls free(). */int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ char *map1 = NULL; char *map2 = NULL; int index = 0; int *result = NULL; *returnSize = 0; map1 = (char *)malloc(MAX*sizeof(char)); if (NULL == map1) { return NULL; } memset(map1, 0x00, MAX); map2 = (char *)malloc(MAX*sizeof(char)); if (NULL == map2) { free(map1); return NULL; } memset(map2, 0x00, MAX); for(index = 0; index < nums1Size; index++) { map1[nums1[index]] = 1; } for(index = 0; index < nums2Size; index++) { map2[nums2[index]] = 1; } result = (int *)malloc(sizeof(int)*MAX); if (NULL == result) { free(map1); return NULL; } memset(result, 0x00, MAX); for (index = 0; index < MAX; index++) { if (map1[index] & map2[index]) { result[*returnSize] = index; (*returnSize)++; } } free(map1); free(map2); return result;}排序int *cmp(const void * a, const void * b){ return *(int *)a - *(int *)b;}/** * Note: The returned array must be malloced, assume caller calls free(). */int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int *result = NULL; int i = 0; int j = 0; int pre; /* 这里不能初始化为 0,否则遇到元素值为 0 的时候会出错 */ *returnSize = 0; result = (int *)malloc(sizeof(int) * (nums1Size < nums2Size ? nums1Size : nums2Size)); if (NULL == result) { return NULL; } qsort(nums1, nums1Size, sizeof(int), cmp); qsort(nums2, nums2Size, sizeof(int), cmp); while (i < nums1Size && j < nums2Size) { if (nums1[i] == nums2[j] && pre != nums1[i]) { result[(*returnSize)++] = nums1[i]; pre = nums1[i]; i++; j++; } else { nums1[i] < nums2[j] ? i++ : j++; } } return result;}int main(){ return 0;}

April 19, 2021 · 2 min · jiezi

关于c++:c中ostream类的超详细说明

依据前文,ostream类是c++规范输入流的一个基类,本篇具体介绍ostream类的次要成员函数用法。 1.ostream的构造函数从ostream头文件中截取一部分对于构造函数的申明和定义,如下: public://explicit用来避免由构造函数定义的隐式转换explicit basic_ostream(__streambuf_type* __sb) { this->init(__sb); }protected: basic_ostream() { this->init(0); }#if __cplusplus >= 201103L // Non-standard constructor that does not call init() basic_ostream(basic_iostream<_CharT, _Traits>&) { } basic_ostream(const basic_ostream&) = delete; basic_ostream(basic_ostream&& __rhs) : __ios_type() { __ios_type::move(__rhs); } // 27.7.3.3 Assign/swap basic_ostream& operator=(const basic_ostream&) = delete; basic_ostream& operator=(basic_ostream&& __rhs) { swap(__rhs); return *this; }能够看到ostream类的默认构造函数是爱护类型,而带参数的构造函数则是私有的,依据public和protected的性能,咱们要定义一个ostream对象,必须要在参数中传入streambuf类型的指针才能够,否则会报编译谬误。 一个可用的例子如下: #include <iostream>#include <fstream>using namespace std;int main(){ filebuf buf; if ( buf.open("/proc/self/fd/1", ios::out) == nullptr ) { cerr << "stdout open failed" << endl; return -1; } ostream out(&buf); return 0;}与istream一样,因为streambuf类型的构造函数是爱护类型,不能间接应用,所以须要应用它的继承者stringbuf或者filebuf,这里应用了filebuf,并且咱们输入错误信息没有应用cout,这里应用了ostream定义的另外一个实例cerr,会输入错误信息到规范谬误输入。 ...

April 19, 2021 · 3 min · jiezi

关于c++:C-变量声明与定义的各种规则

申明与定义拆散Tips:变量能且仅能被定义一次,然而能够被屡次申明。为了反对分离式编译,C++将定义和申明辨别开。其中申明规定了变量的类型和名字,定义除此性能外还会申请存储空间并可能为变量赋一个初始值。 extern如果想申明一个变量而非定义它,就应用关键字extern并且不要显式地初始化变量: extern int i; // 申明i而非定义iextern int i = 1; // 定义i, 这样做对消了extern的作用 static当咱们在C/C++用static润饰变量或函数时,次要有三种用处: 部分动态变量内部动态变量/函数类内静态数据成员/成员函数其中第三种只有C++中有,咱们后续在面向对象程序设计中再探讨,这里只探讨动态部分/全局变量。 1. 动态局部变量在局部变量后面加上static说明符就形成动态局部变量,例如: // 申明部分动态变量static int a;static int array[5] = {1, 2, 3, 4, 5};动态局部变量在函数内定义,但不像主动变量那样当函数被调用时就存在,调用完结就隐没,动态变量的生存期为整个源程序动态变量的生存期尽管为整个源程序,然而作用域与主动变量雷同,即只能在定义该变量的函数内应用该变量,退出函数后尽管变量还存在,但不可能应用它对根本类型的动态局部变量如果在申明时未赋初始值,则零碎主动赋0值;而对一般局部变量不赋初始值,那么它的值是不确定的依据动态局部变量的特点,它的生存期为整个源程序,在来到定义它的函数(作用域)但再次调用定义它的函数时,它又可持续应用,而且保留了前次被调用后留下的值。因而,当屡次调用一个函数且要求在调用之间保留某些变量的值时,可思考采纳动态局部变量,尽管用全局变量也能够达到上述目标,但全局变量有时会造成意外的副作用,因而最好采纳部分动态变量。例如: #include <iostream>void foo() { int j = 0; // 一般局部变量 static int k = 0; // 动态局部变量 ++j; ++k; printf("j:%d, k:%d\n", j, k);}int main(void){ for (int i = 1; i <= 5; i++) { foo(); }}// 输入:j:1, k:1j:1, k:2j:1, k:3j:1, k:4j:1, k:52. 动态全局变量(C++废除,用匿名命名空间代替)Tips:对于全局变量,不论是否被static润饰,它的存储区域都是在动态存储区,生存期为整个源程序。只不过加上static后限度这个全局变量的作用域只能在定义该变量的源文件内。全局变量(内部变量)的申明之前加上static就形成了动态的全局变量,全局变量自身就是动态存储变量,动态全局变量当然也是动态存储形式。这两者在存储形式上并无不同,这两者的区别在于非动态全局变量的作用域是整个源程序。当一个源程序由多个源程序组成时,非动态的全局变量在各个源文件中都是无效的,而动态全局变量则限度了其作用域,即只在定义该变量的源文件内无效,在同一源程序的其余源文件中不能应用它。 ...

April 18, 2021 · 3 min · jiezi

关于c#:C-计算字符串-SHA1

private string SHA1(string str){ byte[] strRes = Encoding.Default.GetBytes(str); HashAlgorithm iSha = new SHA1CryptoServiceProvider(); strRes = iSha.ComputeHash(strRes); StringBuilder enText = new StringBuilder(); foreach (byte iByte in strRes) { enText.AppendFormat("{0:x2}", iByte); } return enText.ToString();}

April 18, 2021 · 1 min · jiezi

关于c#:C-Stream-保存为文件

首先把 Stream 读到 byte 数组中,而后再用 BinaryWriter 写入到二进制文件: using System.IO;// streamFile 是 Stream 类型byte[] bytes = new byte[streamFile.Length];streamFile.Read(bytes, 0, bytes.Length);streamFile.Seek(0, SeekOrigin.Begin);FileStream fs = new FileStream("D:/a.jpg", FileMode.Create);BinaryWriter bw = new BinaryWriter(fs);bw.Write(bytes);bw.Close();fs.Close();

April 18, 2021 · 1 min · jiezi

关于c#:C-字符串转换为指定编码集的-base64-字符串

using System;using System.Text;string EncodeBase64(string code_type, string code){ string encode = ""; byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code); try { encode = Convert.ToBase64String(bytes); } catch { encode = code; } return encode;}EncodeBase64("utf-8", "abc123");

April 18, 2021 · 1 min · jiezi

关于c#:WinForm-DataGridView-控件中复选框的用法

System.Windows.Forms.DataGridView 是 .NET 窗体中提供的数据列表容器控件,就像是 MSSQL 中查问进去的行列,除了展现数据外还提供了编辑的性能。单元格内甚至可能退出特有的控件元素,如文本框,复选框,甚至是图片等,此文介绍了对于其中的复选框。 能够在窗体设计器中为 DataGridView 增加一个 ColumnType 值为 DataGridViewCheckBoxColumn 的列,这就是复选框列,复选框的 TrueValue 与 FalseValue 属性别离指选中与不选中状态的值,这两个值用于在前面判断选中状态。留神复选框与表格容器都不能为只读,否则鼠标点不动复选框。 判断表格中某一行是否被复选框选中,只需判断复选框的值,拿到其所在行号就可能晓得,代码如: for (int i = 0; i < dataGridView1.Rows.Count; i++){ if ((bool)dataGridView1.Rows[i].Cells[0].EditedFormattedValue == true) { Console.WriteLine(i + " selected"); }}代码中假如有个名为 dataGridView1 的表格,假如复选框是第一列,也就是每一行的第一个单元格,连贯起来就是遍历每一行的第一个单元格的值。 相干环境: .NET Framework 4.5

April 18, 2021 · 1 min · jiezi

关于c#:C-Dictionary-类型排序

在 C#.NET 中 System.Collections.Generic.Dictionary<TKey, TValue> 示意键和值的汇合,这个类型蕴含 OrderBy 办法用于排序,参数跟一个 lamda 表达式: // 这里假如 datas 为 Dictionary<string, string> 类型datas.OrderBy(x => x.Key).ToDictionary(x => x.Key, y => y.Value);// OrderByDescending 办法用于倒序应用时留神 ToDictionary 办法进行了一次类型转换;键类型如果是 string,那么将会依照字母程序进行排列,就像英文字典一样。 相干环境:.NET Framework 4.0

April 18, 2021 · 1 min · jiezi

关于c#:C-获取-WebBrowser-的内容源码

System.Windows.Forms.WebBrowser 是 WinForm 框架中提供的一个简略的 Web 浏览器组件,浏览器内核就是零碎自带的 IE 内核,版本依赖于 IE 的版本。假如有一个 Name 属性值为 webBrowser1 的 WebBrowser 控件,获取 Web 内容源码的办法如下: using System;using System.IO;using System.Windows.Forms;using System.Text;StreamReader getReader = new StreamReader(webBrowser1.DocumentStream, Encoding.GetEncoding(webBrowser1.Document.Encoding));string gethtml = getReader.ReadToEnd();getReader.Close();

April 18, 2021 · 1 min · jiezi

关于c++:C五花八门的C初始化规则

总结初始化的概念:创立变量时赋予它一个值(不同于赋值的概念)类的构造函数管制其对象的初始化过程,无论何时只有类的对象被创立就会执行构造函数如果对象未被用户指定初始值,那么这些变量会被执行默认初始化,默认值取决于变量类型和定义变量的地位无论何时只有类的对象被创立就会执行构造函数,通过显式调用构造函数进行初始化被称为显式初始化,否则叫做隐式初始化应用等号(=)初始化一个类变量执行的是拷贝初始化,编译器会把等号右侧的初始值拷贝到新创建的对象中去,不应用等号则执行的是间接初始化传统C++中列表初始化仅能用于一般数组和POD类型,C++11新规范将列表初始化利用于所有对象的初始化(然而内置类型习惯于用等号初始化,类类型习惯用构造函数圆括号显式初始化,vector、map和set等容器类习惯用列表初始化)初始化不等于赋值初始化的含意是创立变量时赋予其一个初始值,而赋值的含意是把对象的以后值擦去,并用一个新值代替它。 C++定义了初始化的好几种不同模式,例如咱们定义一个int变量并初始化为0,有如下4种形式: int i = 0;int i = {0};int i{0};int i(0);默认初始化与值初始化Tips:C不容许用户自定义默认值从而进步性能(减少函数调用的代价),C++默认也不做初始化从而进步性能,然而C++提供了构造函数让用户显式设置默认初始值。有个例外是把全局变量初始化为0仅仅在程序启动时会有老本,因而定义在任何函数之外的变量会被初始化为0。如果定义变量时没有指定初始值,则变量会被默认初始化或值初始化,此时变量被赋予了默认值,这个默认值取决于变量类型和定义地位。 #include <iostream>class Cat { public: std::string name; Cat() = default;};int main() { Cat cat1; // 默认初始化 Cat cat2 = Cat(); // 显式申请值初始化}1. 内置类型的默认初始化Tips:倡议初始化每一个内置类型的变量,起因在于定义在函数外部的内置类型变量的值是未定义的,如果试图拷贝或者以其余模式拜访此类值是一种谬误的编程行为且很难调试。如果内置类型的变量未被显式初始化,它的值由定义的地位决定。定义于任何函数体之外的变量会被初始化为0,定义在函数体外部的内置类型变量将不被初始化(uninitialized),一个未被初始化的内置类型变量的值时未定义的,如果试图拷贝或以其余模式拜访此类值将引发谬误。 #include <iostream>int global_value; // 默认初始化为0int main() { int local_value; // 应用了未初始化的局部变量 int* new_value = new int; std::cout << "new_value:" << *new_value << std::endl; // 未定义 std::cout << "global_value:" << global_value << std::endl; // 0 std::cout << "local_value:" << local_value << std::endl; // 未定义, 且会报warning return 0;}2. 类类型的默认初始化定义一个类变量然而没有指定初始值时,会应用默认构造函数来初始化,所以没有默认构造函数的类不能执行默认初始化。定义于任何函数体之外的类变量会先进行零初始化再执行默认初始化,定义在函数体外部的类变量会间接执行默认初始化。 ...

April 18, 2021 · 6 min · jiezi

关于c#:C-获取某目录下的所有文件

using System;using System.Collections.Generic;using System.IO;private List<string> finded_files = new List<string>();private void RecursiveGetFiles(string parent_path){ string[] files = Directory.GetFiles(parent_path); foreach (string file in files) { // 这里能够进行文件的过滤,比方筛选指定的后缀 finded_files.Add(file); } string[] paths = Directory.GetDirectories(parent_path); foreach (string path in paths) { RecursiveGetFiles(path); }}

April 17, 2021 · 1 min · jiezi

关于c#:C-获取随机字符串

代码如下: using System;string GetRandomString(int length){ string result = ""; for (int i = 0; i < length; i++) { char c = (char)new Random(Guid.NewGuid().GetHashCode()).Next(97, 123); result += c; } return result;}length 参数就是指的字符串的长度;默认是返回随机小写英文字母,因为原理是根据的 ASCII 码表,所以只需稍加批改就能获取大写字母或者是数字。

April 17, 2021 · 1 min · jiezi

关于asp.net:ASPNET-应用程序缓存

ASP.NET 应用程序缓存的钻研;首先新建一个 Web 窗体,默认状况下就可能间接应用 Cache 对象来进行缓存的治理,但十分奇怪的是在 Visual Studio 中,当鼠标放到这个 Cache 上时会呈现来自 System.Web.Caching.Cache 的提醒,但实际上你不能间接应用这个命名空间加上类型来治理缓存,否则会呈现谬误;当本人键入这个命名空间加上 Cache 时只会呈现两个名字带 Expiration 的成员。来自两个不同命名空间的 Cache 对象治理缓存实际上成果是一样的,它们可能都间接作用于以后 Web 应用程序的缓存,如下代码: System.Web.HttpRuntime.Cache.Insert("cache_test", "System.Web.HttpRuntime.Cache success.<br/>", null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);System.Web.Caching.Cache cache = new System.Web.Caching.Cache();Response.Write(System.Web.HttpRuntime.Cache.Get("cache_test").ToString());Response.Write(Page.Cache.Get("cache_test").ToString());Response.Write(this.Cache.Get("cache_test").ToString());Response.Write(cache.Get("cache_test").ToString());cache.Insert("cache_test", "System.Web.Caching.Cache success.<br/>", null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);Response.Write(System.Web.HttpRuntime.Cache.Get("cache_test").ToString());Response.Write(Page.Cache.Get("cache_test").ToString());Response.Write(this.Cache.Get("cache_test").ToString());Response.Write(cache.Get("cache_test").ToString());//对象援用对于非动态的字段、办法或属性“Cache.Insert(...)”是必须的//System.Web.Caching.Cache.Insert("cache_test", "System.Web.Caching.Cache success.", null, DateTime.Now.AddSeconds(5), System.Web.Caching.Cache.NoSlidingExpiration);//对象援用对于非动态的、办法或属性“Cache.Get(...)”是必须的//Response.Write(System.Web.Caching.Cache.Get("cache_test").ToString());因为创立的 Web 窗领会默认继承自 System.Web.UI.Page,所以可能间接应用 Page 类提供的公开成员 Cache;System.Web.HttpRuntime.Cache 是动态类,也可能间接应用;就只有 System.Web.Caching.Cache 须要实例化后应用。 最终的输入后果如下: System.Web.HttpRuntime.Cache success.System.Web.HttpRuntime.Cache success.System.Web.HttpRuntime.Cache success.System.Web.HttpRuntime.Cache success.System.Web.Caching.Cache success.System.Web.Caching.Cache success.System.Web.Caching.Cache success.System.Web.Caching.Cache success. 相干环境:.NET Framework 4.0

April 17, 2021 · 1 min · jiezi

关于c#:CNET-PPT-导出为图片

在应用 Microsoft Office 组件之前我有理解过许多不须要依赖的形式,比方 Spire.Presentation,Aspose 这些组件,Spire.Presentation 应用起来很便捷,然而免费版有图片张数限度,Aspose 如同没有单纯的 PPT 解决,应该是把 PPT 先转为 PDF,再从 PDF 进行输入的。但毕竟是商业我的项目,免费问题是防止不了的,对于这些组件的开发商并不算大厂,所以什么破解、盗版的形式我都会间接回绝(集体认为应该尊重劳动成果),对于本人从底层解析 PPT 的难度过大,因为波及到解释类语言,即便费良久功夫解析进去也要思考平台兼容性,所以最终我还是抉择了 Microsoft Office。应用 Office 套件的毛病实际上也非常明显,像是体积太宏大,原本只须要这么一个小点的性能却要装置几个 GB 的多余部件,部署环境从此须要依赖 Windows + Office。不过倒是相比拟其它商业我的项目,Microsoft Office 能够不用激活就可能应用可编程的组件(过期后可能会存在一点小问题),这的确是一个比拟具备说服力的理由。性能的实现从代码上来看并不多: using Microsoft.Office.Core;using Microsoft.Office.Interop.PowerPoint;Application app = new Application();Presentation ppt = app.Presentations.Open(fileName, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);int slideCounts = ppt.Slides.Count + 1;for (int i = 1; i < slideCounts; i++){ string picSavePath = "D:/filename_" + i + ".jpg"; ppt.Slides[i].Export(picSavePath, ".jpg");}ppt.Close();app.Quit();代码到这里实际上就曾经完了,增加的援用是 COM 程序集里的 Microsoft PowerPoint 15.0 Object Library 与 Microsoft Office 15.0 Object Library,具体的版本号视状况而定。尽管代码没有什么问题,或者本地调试也没有什么问题,然而部署到大多数的生产环境中多半是不能执行的,因为 COM 程序集的调用须要肯定的权限,如果某些中央的配置不当就可能会遇到各种各样的谬误,而且大多数的异样音讯可能也很难看出问题所在。我是把程序作为 ASP.NET 网站给部署到 IIS 上的,比方上面就是我遇到的各种异样: ...

April 17, 2021 · 1 min · jiezi

关于c#:C-发送邮件

这里以 QQ 邮箱的 SMTP 服务为例,写代码之前须要先进入 QQ 邮箱进行配置,开启 SMTP 服务,而后查看受权,拿到受权码,记录下 SMTP 服务器地址和端口,配置实现后才是写代码。.NET Framework 曾经对发送邮件相干的性能进行了整合,因而调用起来并不算麻烦: MailAddress sender = new MailAddress("发件人邮箱");MailAddress to = new MailAddress("收件人邮箱");// 邮件服务设置SmtpClient smtpClient = new SmtpClient();// SSL 和鉴权的配置是依据 QQ 邮箱配置的,不同 SMTP 服务器所要求的可能会不一样smtpClient.EnableSsl = true;smtpClient.UseDefaultCredentials = false;// 鉴权的格局是 QQ 邮箱规定的smtpClient.Credentials = new NetworkCredential("发件人邮箱", "受权码");smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;smtpClient.Host = smtpServer;smtpClient.Timeout = 5000;// 端口是 QQ 邮箱规定的,能够到 QQ 邮箱帮忙核心查找smtpClient.Port = 587;MailMessage mailMessage = new MailMessage(sender, to);mailMessage.Subject = "邮件题目";mailMessage.Body = "邮件内容";mailMessage.BodyEncoding = Encoding.UTF8;mailMessage.IsBodyHtml = true;// 最初发送smtpClient.Send(mailMessage);不同 SMTP 服务器所要求的参数可能会不一样,所以肯定要先看官网提供的文档,但基本上发邮件的代码都大同小异了。 ...

April 17, 2021 · 1 min · jiezi

关于c#:C-通过反射的方式调用方法

using System;using System.Reflection;using System.IO;// 读取 .dll 文件byte[] fileData = File.ReadAllBytes("D:\\file.dll");Assembly assembly1 = Assembly.Load(fileData);// 获取 TypeType type1 = assembly1.GetType("namespace.type");// 获取办法MethodInfo method = type1.GetMethod("method");// 创立一个实例object activator = Activator.CreateInstance(type1);// 执行办法并获取返回后果object result = method.Invoke(activator, null);载入程序集是通过读取为字节数组的形式,这样能够防止 Assembly.LoadFile 办法造成的 .dll 文件被占用问题,这里须要应用绝对路径;获取 Type 时须要在后面加上命名空间,获取办法只需提供办法名称即可;对于静态方法的调用能够不用应用 Activator 类创立实例,所以 Invoke 办法的第一个参数能够为 null,Invoke 办法的第二个参数是 object[] 类型,示意传递给该办法的参数汇合,办法被调用后返回的后果是以 object 类型保留的,在理论状况下当然还须要一个转换操作。

April 17, 2021 · 1 min · jiezi

关于windows:C-编写-Windows-服务应用程序

在 .NET Framework 平台中编写 Windows 服务 算是一件比拟容易的事件。首先关上 Visual Studio 创立一个名为 Windows 服务 的我的项目,创立后看到的是一个 .cs 文件的设计界面,用鼠标右键单击能够看到几个菜单,点击增加安装程序后又会转到另一个 .cs 文件的设计界面,这个界面上默认有两个组件,一个叫 serviceProcessInstaller1,另一个叫 serviceInstaller1,其中 serviceInstaller1 组件的属性窗口如下: Description 属性和 DisplayName 属性别离指服务的形容和名字,ServiceName 属性指服务的过程名字,StartType 属性指服务的启动类型,这里抉择 Automatic 的意思为主动启动;这里还会把 serviceProcessInstaller1 组件的 Account 属性批改为 LocalSystem,要不然等到装置服务的时候可能会呈现要求输出用户名和明码的对话框。 服务装置组件的配置曾经完了,当初转到服务的代码地位,还是在方才那个右键菜单地位,点击“查看代码”就能够看到服务要执行的代码,我编写如下代码: using System;using System.ServiceProcess;namespace WindowsService1{ public partial class Service1 : ServiceBase { public Service1() { InitializeComponent(); } System.Timers.Timer timer = new System.Timers.Timer(); protected override void OnStart(string[] args) { timer.Interval = 1000; timer.AutoReset = true; timer.Enabled = true; timer.Start(); timer.Elapsed += new System.Timers.ElapsedEventHandler(timertick); } private void timertick(object source, System.Timers.ElapsedEventArgs e) { System.IO.FileStream fs = new System.IO.FileStream("D:\\log.txt", System.IO.FileMode.Append); System.IO.StreamWriter sw = new System.IO.StreamWriter(fs); sw.WriteLine(DateTime.Now.ToString()); sw.Close(); fs.Close(); } protected override void OnStop() { } }}OnStart 办法中的代码会在服务启动时执行一次,所以这里我用了一个定时器有限执行;OnStop 办法中的代码会在服务进行时执行。服务程序编译后仍然会是 .exe 文件,只不过不可能间接运行,这里须要应用 .NET Framework 提供的程序来装置咱们编写的服务,装置服务的命令如下: ...

April 17, 2021 · 1 min · jiezi

关于c#:C-中-DateTime-的加减

在 .NET Framework 4.0 中,DateTime 类型与 DateTime 类型之间 不能进行加运算,然而能够进行减运算。两者相减后的后果可用 TimeSpan 类型存储,TimeSpan 类中具备间接获取减运算后果的成员,代码如下: using System;TimeSpan ts = Convert.ToDateTime("2019-11-15 14:00:00") - Convert.ToDateTime("2019-11-14 14:00:00");double days = ts.TotalDays;//天double hours = ts.TotalHours;//时double minutes = ts.TotalMinutes;//分须要留神的是值能够为正数。

April 17, 2021 · 1 min · jiezi

关于c:const-和指针

const 和指针const 也能够和指针变量一起应用,这样能够限度指针变量自身,也能够限度指针指向的数据。const 和指针一起应用会有几种不同的程序,如下所示: const int *p1;int const *p2;int * const p3;在最初一种状况下,指针是只读的,也就是 p3 自身的值不能被批改;在后面两种状况下,指针所指向的数据是只读的,也就是 p1、p2 自身的值能够批改(指向不同的数据),但它们指向的数据不能被批改。 当然,指针自身和它指向的数据都有可能是只读的,上面的两种写法可能做到这一点: 纯文本复制 const int * const p4;int const * const p5;const 和指针联合的写法多少有点让初学者摸不着头脑,大家能够这样来记忆:const 离变量名近就是用来润饰指针变量的,离变量名远就是用来润饰指针指向的数据,如果近的和远的都有,那么就同时润饰指针变量以及它指向的数据。

April 16, 2021 · 1 min · jiezi

关于c#:C-for-与-foreach-循环的性能测试

测试的办法是用这两种循环形式遍历已知的汇合数据,应用的计时器是 Stopwatch 类,最初会在两个相应的文本框中输入工夫耗费,先间接贴出后果画面: 测试各执行了十次,其中右边的文本框是 for 语句的后果,左边的是 foreach 语句的后果,能够看出 foreach 语句在这个程序当中效率更高,上面是测试的局部代码: using System;using System.Diagnostics;using System.Collections.Generic;using System.Windows.Forms;private List<int> datas = new List<int>(100000000);for (int i = 0; i < 100000000; i++){ datas.Add(i);}// forprivate void normalFor(){ Stopwatch watch = new Stopwatch(); watch.Start(); int result = 0; for (int i = 0; i < datas.Count; i++) { result += datas[i]; } watch.Stop(); textBox1.Text += watch.ElapsedMilliseconds.ToString() + "ms\r\n";}// foreachprivate void forEach(){ Stopwatch watch = new Stopwatch(); watch.Start(); int result = 0; foreach (int i in datas) { result += i; } watch.Stop(); textBox2.Text += watch.ElapsedMilliseconds.ToString() + "ms\r\n";}这个程序中拿了较为极其的数据来作测试,最终也只是达到了不到 200 ms 的差距,实际上在应用环境中两者之间的性能差异基本上能够忽略不计,还是就思考开发者的应用习惯和上下文环境来进行抉择。 ...

April 16, 2021 · 1 min · jiezi

关于c#:C-对象与-JSON-字符串的相互转换

程序应用 .NET Framework 提供的 JavaScriptSerializer 类进行序列化和反序列化操作,须要援用 .NET Framework 中的 System.Web.Extensions 程序集。对于间接进行 DataTable 类型对象的转换会呈现 “序列化类型为“System.Reflection.RuntimeModule”的对象时检测到循环援用” 这一异样,所以程序中对 DataTable 类型的转换作了独自解决,当然只是从 DataTable 转换为 JSON 时作了解决,如果将 JSON 字符串转换为 DataTable 仍然会失败,我想通常状况下的前后端交互只须要用到 DataTable 到 JSON 的转换就差不多了吧,上面是实现: using System;using System.Web.Script.Serialization;using System.Data;using System.Collections.Generic;// 对象转换为 JSON 字符串string ObjectToJSON(object _obj){ try { JavaScriptSerializer serializer = new JavaScriptSerializer(); if (_obj is DataTable) { DataTable dt = (DataTable)_obj; List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>(); Dictionary<string, object> row; foreach (DataRow dr in dt.Rows) { row = new Dictionary<string, object>(); foreach (DataColumn dc in dt.Columns) { row.Add(dc.ColumnName, dr[dc]); } rows.Add(row); } return serializer.Serialize(rows); } return serializer.Serialize(_obj); } catch { return "{}"; }}// JSON 字符串转换为相应类型的对象T JSONToObject<T>(string _json){ try { JavaScriptSerializer serializer = new JavaScriptSerializer(); return serializer.Deserialize<T>(_json); } catch { return default(T); }}相干环境:.NET Framework 4.0 ...

April 16, 2021 · 1 min · jiezi

关于c#:C-图片转换为-base64-字符串

程序的根本转换方法是应用 .NET Framework 提供的 base64 转换器,其中用到了 ImageFormatGuidToString 办法,这个办法是为了确保图像保留到内存流的时候用的是失常的图像格式。如果是应用 Image 类创立的新图像,那么它的 RawFormat 参数值并不是惯例的格局,这个时候如果应用这种图像格式保留到内存流中会导致失败,具体的异样音讯大略是 “值不能为 null。参数名:encoder”,所以这个中央在图像保留到内存流之前首先查看了现有图像的格局。转换后的 base64 字符串是没有标识头的,要在 HTML 标签中显示须要本人加上头部,如 “data:image/png;base64,...”: using System;using System.Drawing;using System.Drawing.Imaging;using System.IO;// Image 对象转换为 base64 字符串string ImageToBase64(Image _image){ MemoryStream ms = new MemoryStream(); try { if (ImageFormatGuidToString(_image.RawFormat) == null) { _image.Save(ms, ImageFormat.Png); } else { _image.Save(ms, _image.RawFormat); } byte[] arr = new byte[ms.Length]; ms.Position = 0; ms.Read(arr, 0, (int)ms.Length); return Convert.ToBase64String(arr); } catch { return null; } finally { ms.Close(); }}// base64 字符串转换为 Image 对象Image Base64ToImage(string _base64){ byte[] arr = Convert.FromBase64String(_base64); MemoryStream ms = new MemoryStream(arr); Bitmap bmp = new Bitmap(ms); try { Image result = new Bitmap(bmp.Width, bmp.Height); Graphics g = Graphics.FromImage(result); g.DrawImage(bmp, 0, 0); g.Dispose(); return result; } catch { return null; } finally { bmp.Dispose(); ms.Close(); }}// 用于查看图像格式string ImageFormatGuidToString(ImageFormat _format){ if (_format.Guid == ImageFormat.Bmp.Guid) { return "bmp"; } else if (_format.Guid == ImageFormat.Gif.Guid) { return "gif"; } else if (_format.Guid == ImageFormat.Jpeg.Guid) { return "jpg"; } else if (_format.Guid == ImageFormat.Png.Guid) { return "png"; } else if (_format.Guid == ImageFormat.Icon.Guid) { return "ico"; } else if (_format.Guid == ImageFormat.Emf.Guid) { return "emf"; } else if (_format.Guid == ImageFormat.Exif.Guid) { return "exif"; } else if (_format.Guid == ImageFormat.Tiff.Guid) { return "tiff"; } else if (_format.Guid == ImageFormat.Wmf.Guid) { return "wmf"; } else { return null; }}相干环境:.NET Framework 4.0 ...

April 16, 2021 · 1 min · jiezi

关于c#:C-执行基本的-Web-POST-请求

这个办法用的是浏览器最传统的表单提交形式 application/x-www-form-urlencoded,这个办法可用到两种组合数据的办法,一是间接传递数据到 data 对象,二是组合键/值对类型的数据到 parameters 对象,办法内会优先选择 data 对象所带的参数,如果想要以键/值对的形式传递,将 data 对象的值填为空字符串即可,这两个二选一;获取返回值的办法中退出了异样解决,这使得即便在遇到申请服务器产生服务器谬误(如 404 等 HTTP 状态)时也可失常取得返回的异样信息,应用时须要留神超时值与字符编码集: using System;using System.Net;using System.Text;using System.IO;using System.Collections.Generic;public string HttpPost(string url, string data = "", IDictionary<string, string> parameters = null, int timeout = 5000, CookieCollection cookies = null){ HttpWebRequest request = null; request = WebRequest.Create(url) as HttpWebRequest; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.Timeout = timeout; if (cookies != null) { request.CookieContainer = new CookieContainer(); request.CookieContainer.Add(cookies); } if (!string.IsNullOrWhiteSpace(data)) { byte[] databytes = Encoding.UTF8.GetBytes(data); using (Stream stream = request.GetRequestStream()) { stream.Write(databytes, 0, databytes.Length); } } else if (parameters != null && parameters.Count != 0) { StringBuilder buffer = new StringBuilder(); int i = 0; foreach (string key in parameters.Keys) { if (i > 0) { buffer.AppendFormat("&{0}={1}", key, parameters[key]); } else { buffer.AppendFormat("{0}={1}", key, parameters[key]); i++; } } byte[] kvdata = Encoding.UTF8.GetBytes(buffer.ToString()); using (Stream stream = request.GetRequestStream()) { stream.Write(kvdata, 0, kvdata.Length); } } try { using (Stream stream = request.GetResponse().GetResponseStream()) { using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { return reader.ReadToEnd(); } } } catch (WebException ex) { using (Stream stream = ex.Response.GetResponseStream()) { using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { return reader.ReadToEnd(); } } }}相干环境:.NET Framework 4.0 ...

April 16, 2021 · 1 min · jiezi

关于c#:C-执行-Web-GET-请求

这里留神超时值不要设置得太小,不然会引发 System.Net.WebException 异样,值以毫秒为单位,个别设置为 5000 以上: using System;using System.Net;using System.IO;using System.Text;string GetHttpResponse(string url, int timeout){ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.Timeout = timeout; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string resString = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); return resString;}相干环境:.NET Framework 4.0

April 16, 2021 · 1 min · jiezi

关于算法-数据结构:PAT甲级2020年冬季考试-73-File-Path

7-3 File Path (25 分)The figure shows the tree view of directories in Windows File Explorer. When a file is selected, there is a file path shown in the above navigation bar. Now given a tree view of directories, your job is to print the file path for any selected file. Input Specification:Each input file contains one test case. For each case, the first line gives a positive integer N (≤10^3), which is the total number of directories and files. Then N lines follow, each gives the unique 4-digit ID of a file or a directory, starting from the unique root ID 0000. The format is that the files of depth d will have their IDs indented by d spaces. It is guaranteed that there is no conflict in this tree structure. ...

April 13, 2021 · 2 min · jiezi

关于算法-数据结构:PAT甲级2020年冬季考试-72-Subsequence-in-Substring

7-2 Subsequence in Substring (25 分)A substring is a continuous part of a string. A subsequence is the part of a string that might be continuous or not but the order of the elements is maintained. For example, given the string atpaaabpabtt, pabt is a substring, while pat is a subsequence. Now given a string S and a subsequence P, you are supposed to find the shortest substring of S that contains P. If such a solution is not unique, output the left most one. ...

April 13, 2021 · 2 min · jiezi

关于c++:PAT甲级2020年冬季考试-71-The-Closest-Fibonacci-Number

7-1 The Closest Fibonacci Number (20 分)The Fibonacci sequence Fn is defined by $$F_{n+2} =F_{n+1} +F_n \;\;for \;\;n≥0, with \;\;F_0 =0 \;\;and\;\; F_1 =1.$$ The closest Fibonacci number is defined as the Fibonacci number with the smallest absolute difference with the given integer N. Your job is to find the closest Fibonacci number for any given N. Input Specification:Each input file contains one test case, which gives a positive integer N (≤10^8). ...

April 13, 2021 · 2 min · jiezi

关于c++:PAT甲级2020年冬季考试-74-Chemical-Equation

7-4 Chemical Equation (30 分)A chemical equation is the symbolic representation of a chemical reaction in the form of symbols and formulae, wherein the reactant entities are given on the left-hand side and the product entities on the right-hand side. For example, $$CH_4+2O_2=CO_2+2H_2O$$ means that the reactants in this chemical reaction are methane and oxygen: CH4 and O2, and the products of this reaction are carbon dioxide and water: CO2 and H2O. ...

April 13, 2021 · 4 min · jiezi

关于c++:c标准输入输出流关系梳理

输入输出是每一种编程语言必不可少的局部,c++也不例外,上面咱们就来阐明c++的规范输入输出的前世今生。 1.首先说一下iostream和iostream.h的区别#include<iostream> // 这个就是1998年标准化当前的规范头文件,应用时须要应用申明命名空间std#include<iostream.h> // 这个就是标准化以前的头文件,外面的函数以及类都是全局的iostream是当初C++中规定的规范,目标在于使C++代码用于移植和混合嵌入时不受扩展名.h的限度,防止因为.h而造成的额定的解决和批改。 iostream蕴含的基本功能和对应的iostream.h雷同,iostream中定义的内容都在命名空间std中,而iostream.h是为了对c语言进行兼容,所以将规范输入输出性能都定义在全局空间中,他们的应用办法也是不一样的,另外举荐间接应用iostream,毕竟iostream.h是很多年前的老物件了,规范c++中曾经明确不实用了,当前有可能被淘汰。 留神:在标准化的过程中,库中有些局部的细节被批改了,所以旧头文件和新头文件中的实体不肯定齐全对应这里看一下他们应用上的不同: #include<iostream.h>或者是 #include<iostream>using namespace std;可见但凡要应用规范c++输入输出,都须要加上using namespace std。 2.输入输出流关系梳理要弄清楚c++的输入输出流,必须要从源头找起,从安装文件外面找出输入输出流相干的头文件,大略列一下,相干头文件有以下这些: istream,能够看到istream头文件是申明了basic_istream模板类ostream,ostream头文件是申明了basic_ostream模板类iostream,iostream只是申明了一个istream对象和三个ostream对象,这一点前面会阐明iosfwd,iosfwd头文件外面申明了所有输入输出类的模板类的一个实例fstream,fstream外面申明了basic_filebuf模板类、basic_ifstream模板类、basic_ofstream模板类iomainip,iomainip外面申明了一些带参数的操纵算子sstream,sstream外面申明了basic_stringbuf模板类、basic_istringstream模板类、basic_ostringstream模板类streambuf,streambuf外面申明了basic_streambuf模板类下面说到iosfwd对输入输出的类模板做了实例化,咱们截取一段代码,如下: /// Base class for @c char streams. typedef basic_ios<char> ios; //根底类 /// Base class for @c char buffers. typedef basic_streambuf<char> streambuf; /// Base class for @c char input streams. typedef basic_istream<char> istream; /// Base class for @c char output streams. typedef basic_ostream<char> ostream; /// Base class for @c char mixed input and output streams. typedef basic_iostream<char> iostream; /// Class for @c char memory buffers. typedef basic_stringbuf<char> stringbuf; /// Class for @c char input memory streams. typedef basic_istringstream<char> istringstream; /// Class for @c char output memory streams. typedef basic_ostringstream<char> ostringstream; /// Class for @c char mixed input and output memory streams. typedef basic_stringstream<char> stringstream; /// Class for @c char file buffers. typedef basic_filebuf<char> filebuf; /// Class for @c char input file streams. typedef basic_ifstream<char> ifstream; /// Class for @c char output file streams. typedef basic_ofstream<char> ofstream; /// Class for @c char mixed input and output file streams. typedef basic_fstream<char> fstream;为了叙述不便,后续咱们间接应用以上实例类来代指模板类,上面用一张图阐明这些类之间的关系: ...

April 13, 2021 · 1 min · jiezi

关于c:简单的逆序的三位数

思路:拆散出每个数字如将整数217分来到即为:712/100=>7712/10%10=>1 或者 712%100/10=>1712%10=>2 将原数的百位变成个位,个位变成百位,即2100+110+7 = 217 代码如下: int a;scanf("%d", &a);int b = a/100 + (a%100/10)*10 + (a%10)*100;printf("%d",b);return 0;或者 int n,a,b,c,m;scanf("%d",&n);a = n/100;b = n/10%10;c = n%10;m = c*100 + b *10 + a;printf("%d\n",m);return 0;留神:题目要求输出700时,输入为7,而非007,所以printf("%d%d%d\n",c,b,a);是不行的

April 10, 2021 · 1 min · jiezi

关于electron:开发Electron不小心接触到C经过一周多的时间终于摸索出

为啥要写二进制编译 exe程序,CMake minGW练习教程?前阵子,钻研了一下electron,想开发一款离线图片压缩桌面程序。写的过程中发现程序在,windows环境下运行没问题,然而在linux 和 macOS会有问题。常常排查发现是node依赖的第三方插件问题(只给了 exe程序)。所以开始着手钻研,如何通过 c++之类的源码,编译出别离对应 Wndows Linux MacOS的二进制应用程序。通过一周的工夫查阅大量的材料(google),最终得出上面的流程。 当初只是学会了,编译Linux 和windows的应用程序,然而我想要是 在一个零碎环境下别离编译出Windows Linux MacOS。目前只接触到了 穿插编译这个货色。正在着手学习,摸索出残缺无坑的流程再持续发相干文章。 本文存储于github 工具筹备OS: windows 10 CMake: https://cmake.org/ Visual Studio 2019: https://visualstudio.microsof... 下载 libpng-1.6.35 源码 Download the libpng-1.6.35 source codelibpng: https://github.com/glennrp/li... 解压 libpng-1.6.35.tar.gz directory|-libpng-1.6.35关上 zlib.props 文件,查看依赖zlib的版本libpng > projects -> vstudio -> zlib.props line 34 <ZLibSrcDir>..\..\..\..\zlib-1.2.8</ZLibSrcDir>下载 zlib-1.2.8 源码 Download the zlib-1.2.8 source codezlib : https://github.com/madler/zli... 解压 zlib-1.2.8.tar.gz directory|-libpng-1.6.35|-zlib-1.2.8编译 zlib-1.2.8关上 CMake gui点击 Browse Source 抉择 zlib-1.2.8 点击 Browse Build 抉择 zlib-1.2.8/build 目录点击 Configure(生成CMake Cahce) 抉择 Visual Studio和 x64点击 Finish 期待输入音讯 Configuring done ...

April 8, 2021 · 2 min · jiezi

关于node.js:node-本地二进制包装器无缝的用作本地依赖

本地二进制文件包装器次要是为了解决,不同环境下须要应用不同的本地二进制文件。 为什么不依据以后环境在线下载呢? 因为网络下载会有墙和编译的等不可抗力问题。所以自行下载好放起来,再通过包装器应用. const path = require('path');const fs = require('fs-extra');class Local_Bin_Wrapper { constructor(){ this.map = new Map(); } /** * 配置包门路 * @param url 本地二进制包的绝对路径 * @param platfrom 包的平台 darwin -> macOs win32-> windows * @returns this */ src(url: string, platfrom: "darwin" | "win32"): this { this.map.set(platfrom, path.resolve(url)); return this; } //返回合乎以后平台的二进制地址 path(): string { return this.map.get(process.platform); } //仅仅提供一个调用办法 async run(cmd = ["--version"]): Promise<execa.ExecaChildProcess<string>> { const path = this.path(); try { //验证是否存在 //如果不存在就会报错 try catch捕捉 fs.statSync(path); const result_1 = await execa(path, cmd); console.log("command:", result_1.command); if (result_1.stderr.length > 0) { console.log(result_1.stderr); } if (result_1.stdout.length > 0) { console.log(result_1.stdout); } return result_1; } catch (e) { console.log(`Failed to access file ${path}`, e); return Promise.reject(e); } }}调用例子import * as execa from "execa";const url = path.resolve(__dirname,'../bin');const bin = new Local_Bin_Wrapper() .src(`${url}/mac/pngquant/pngquant`, 'darwin') .src(`${url}/win/pngquant/pngquant.exe`, 'win32');//这样便于本人封装const pngquantBin = bin.path();execa(pngquantBin, ['--version']);

April 8, 2021 · 1 min · jiezi

关于c++:c类访问权限及友元

1.类的拜访权限class是c++的类申明关键字,它的成员类型有三种,是应用三个关键字来申明的,别离是public、private、protected,public申明的叫做私有成员,private申明的是公有成员,protected申明的则是爱护成员。 1)public-私有成员首先看一下public申明的私有成员: class A{public: int a; int b;public: int add();private: int sub();protected: int mul();};int A::add(){ return a+b;}int A::sub(){ return a-b;}int A::mul(){ return a*b;}int main(){ A a; a.a = 2; a.b = 3; return 0;}对于以上代码,编译通过,阐明对于私有成员a和b,私有成员函数、公有成员函数、爱护成员函数以及类对象都是能够间接进行拜访的。 2)private-公有成员接下来将成员变量a申明为公有,如下: class A{private: int a;public: int b;public: int add();private: int sub();protected: int mul();};int A::add(){ return a+b;}int A::sub(){ return a-b;}int A::mul(){ return a*b;}int main(){ A a; a.a = 2; a.b = 3; return 0;}编译时报错如下: test.cpp: In function ‘int main()’:test.cpp:33:4: error: ‘int A::a’ is private within this context编译报错的意思是第33行,a是一个公有成员,不能间接拜访,那么将33行正文掉,而后再编译,能够通过。综上,阐明对于公有成员a,私有成员函数、公有成员函数、爱护成员函数都能够间接进行拜访,但类对象不能间接拜访。 ...

April 8, 2021 · 2 min · jiezi

关于c++:HackingC-Learning笔记-Chapter10Generic-Programming泛型编程

@@@@@@ @@@

April 6, 2021 · 1 min · jiezi

关于c++:HackingC-Learning笔记-Chapter11Memory-Management

xxx xxxxxxx

April 6, 2021 · 1 min · jiezi

关于asm:实操体验-CPU-的流水线多发射

前言前文 <一行机器指令感触下内存操作到底有多慢> 中,咱们体验到了 CPU 流水线阻塞带来的数量级性能差别。过后只是依据机器码,剖析推断进去的,这次咱们做一些更小的试验来剖析验证。 入手之前,咱们先理解一些背景。在 \<CPU 提供了什么> 一文中介绍过,CPU 对外提供了运行机器指令的能力。那 CPU 又是如何执行机器指令的呢? CPU 是如何执行机器指令的一条机器指令,在 CPU 外部也分为好多个细分步骤,逻辑上来说能够划分为这么五个阶段: 获取指令解析指令执行执行拜访内存后果写回流水线作业例如间断的 ABCD 四条指令,CPU 并不是先残缺的执行完 A,才会开始执行 B;而是 A 取指令实现,则开始解析指令 A,同时持续取指令 B,顺次类推,造成了流水线作业。 现实状况下,充分利用 CPU 硬件资源,也就是让流水线上的每个器件,始终放弃工作。然而实际上,因为各种起因,CPU 没法残缺的跑满流水线。 比方: 跳转指令,可能跳转执行另外的指令,并不是固定的程序执行。例如这样的跳转指令,可能接下来就须要跳转到 400553 的指令。je 400553对于这种分支指令,CPU 有分支预测技术,基于之前的后果预测本次分支的走向,尽量减少流水线阻塞。 数据依赖,前面的指令,依赖后面的指令。例如上面的两条指令,第二条指令的操作数 r8 依赖于第一条指令的后果。mov r8,QWORD PTR [rdi]add r8,0x1这种时候,CPU 会利用操作数前推技术,尽量减少阻塞期待。 多发射古代简单的 CPU 硬件,其实也不只有一条 CPU 流水线。简略从逻辑上来了解,能够假如是有多条流水线,能够同时执行指令,然而也并不是简略的反复整个流水线上的所有硬件。 多发射能够了解为 CPU 硬件层面的并发,如果两条指令没有前后的程序依赖,那么是齐全能够并发执行的。CPU 只须要保障执行的最终后果是合乎冀望的就能够,其实很多的性能优化,都是这一个准则,通过优化执行过程,然而放弃最终后果统一。 实际体验实践须要联合实际,有理论的体验,能力更清晰的了解原理。 这次咱们用 C 内联汇编来构建了几个用例来领会这其中的差别。 基准用例#include <stdio.h>void test(long *a, long *b, long *c, long *d) { __asm__ ( "mov r8, 0x0;" "mov r9, 0x0;" "mov r10, 0x0;" "mov r11, 0x0;" ); for (long i = 0; i <= 0xffffffff; i++) { } __asm__ ( "mov [rdi], r8;" "mov [rsi], r9;" "mov [rdx], r10;" "mov [rcx], r11;" );}int main(void) { long a = 0; long b = 0; long c = 0; long d = 0; test(&a, &b, &c, &d); printf("a = %ldn", a); printf("b = %ldn", b); printf("c = %ldn", c); printf("d = %ldn", d); return 0;}咱们用如下命令才执行,只须要 1.38 秒。留神,须要应用 -O1 编译,因为 -O0 下,基准代码自身的开销也会很大。 ...

April 5, 2021 · 3 min · jiezi

关于c#:比尔盖茨都不知道的cwinfrom的陷阱坑

1.datagridview外面的坑:1.1、界面UI图 如图,标段和分包名称都是个下拉框,原本我写的办法是初始化加载数据只查问了标段,通过点击表白这个单元格的事件触发了查问分包名称,从而造成分包的下拉框,但这样的弊病就是经常报这个(分包名称字段)dataGridViewColum的数据报错,出错就是绑定数据异样,这个并不是数据格式的问题。这让人很苦恼。这个相似的代码在这里能找到:https://juejin.cn/post/687517... ,如果您有幸看到这篇文章,肯定不要被原文蒙蔽啊。 1.2 办法改良 这里的查问我就是一开始加载时,把所有信息全副查问进去,这样一一对应关系也有了,也不至于一开始加载联动关系对应不上。 这不是是点击标会联动分包名称的下拉,也不必多说了。 2.label文字换行的坑: 2.1 原本这个需要是我想做个文章列表页,用label用习惯了,一开始如图区域的控件 我用的是label,而后文字不换行被遮蔽了,百度了一下,好多反复文章都是说怎么调属性的诸如此类,如图: 反正最终款式很丑,无论如何,行的文字对不齐。 前面应用的是RichText这个控件,暗藏横向滚动条和背景,这样就行了。就如同html的p标签款式个别,我这么平平淡淡的说,也只是跟大家讲 思维很重要,不要陷入思维误区,有些货色的应用不是你想想的那样,应该多多尝试,还有就是想吐槽一下,为什么百度能搜出这么多不靠谱的文章,反复不说 还排名这门靠前。 本文来源于:程序员ken,专属平台有csdn、思否(SegmentFault)、 简书、 开源中国(oschina)、掘金,转载请注明出处。

April 4, 2021 · 1 min · jiezi

关于c++:c中运算符重载

加号运算符重载对于内置数据类型,编译器晓得如何运算 然而对于本人封装的类,编译器无奈进行运算 这时能够通过本人定义运算符重载进行运算 operator 通过成员函数重载+号#include<iostream>using namespace std;class Person{public: int m_a; int m_b; //通过成员函数实现重载 Person operator+ (Person &p) { //创立一个长期变量 Person temp; temp.m_a = this->m_a + p.m_a; temp.m_b = this->m_b + p.m_b; return temp; }};void test01(){ Person p1; p1.m_a = 66; p1.m_b = 44; Person p2; p2.m_a = 6; p2.m_b = 4; Person p3; //通过函数原型调用 p3 = p1.operator+(p2); //简便调用 //p3 = p1 + p2; cout << "p3.m_a:" << p3.m_a << endl; cout << "p3.m_b:" << p3.m_b << endl;}int main(){ test01(); system("pause"); return 0;}留神两种调用形式 ...

April 4, 2021 · 3 min · jiezi

关于c++:HackingC-Learning笔记-Chapter7Standard-Library-–-Part-2

规范库Range Copy算法留神: 必须要保障指标地位有足够的空间(resize 或者 reserve),规范算法在大多数状况下不能查看指标范畴是否足够大 copy(@beg, @end, @target_begin) -> @target_out copy_n(@beg, n, @target_begin) -> @target_out copy_backward(@beg, @end, @target_end) -> @target_begin (拷贝到end处)copy_if(@beg, @end, @target,f(O)->bool)->target_endsample(@beg, @end, @out, n, random_generator) ->out_end (实现采样-c++17)Special 迭代器感觉用途不大哦,除了插入这个interator规范库Sequence Reordering算法#shitf Elements 转换元素1.reserve/reserve_copy 反转2.rotate/rotate_copy 旋转 shift_left/shift_right(X感觉用途不大c++20)3.shuffle(@beg, @end, randim_engine) 随机打乱#sort 排序1.sort(@begin, @end, compare(o,o)->bool)2.stable_sort(@begin, @end, compare(o,o)->bool)//a.sort是疾速排序实现,因而是不稳固的;stable_sort是归并排序实现,因而是稳固的;//b.对于相等的元素sort可能扭转程序,stable_sort保障排序后相等的元素秩序不变//c.如果提供了比拟函数,sort不要求比拟函数的参数被限定为const,而stable_sort则要求参数被限定为const,否则编译不能通过3.partial_sort(@begin, n, @end, compare(o,o)->bool) /partial_sort_copy() nth_elements(没想到用处)4.is_sorted(@begin, @end, compare(o,o)->bool) -> true (是否有序)5.is_sorted_until(@begin, @end, compare(o,o)->bool) -> @sorted_end (返回到哪里之前是有序的)# partition 分区1.partition(@beg, @end, f(o,o)->bool) ->@ftrue_end 2.partition_copy(@beg, @end, @ft, @ff, f(O)->bool) -> {@ft_end, @ff_end}3.stable_partition(@beg, @end, f(o,o)->bool) ->@ftrue_end // stable_partition保障分区后原来的先后顺序不变,而partition无奈保障4.is_partition() -> true5.partition_point() -> @ftrue_end (分区后返回分界点)## Permutations 排列组合(不晓得利用场景??)1.next_permutation(@beg, @end) -> true 只有下一种排列能够是逻辑上大的,就返回true2.prev_permutataion(@beg, @end) -> true 只有上一种排列能够是逻辑上小的,就返回true3.is_permutation(@beg, @end, @beg2) -> true if range2 is a permutation of range1规范库Element-Wise Range Modifications(批改)# Filling / Overwriting Ranges 填充改写1.fill(@beg, @end, value) ->@filled_end (fill_n)2.generate(@begin ,@end generator()-> ●) (generator_n)//generator能够通过functors 写入不同的value,比fill性能强,不必循环这么捞的写了# Changing / Replacing Values 扭转代替1.transform(@beg, @end, @out, f(O)->■) -> @out_end2.transform(@beg, @end, @beg2, @out, f(O,△) -> ■) -> @out_end//该算法在其余编程语言中也称为"map"//target 必须可能承受和input range元素一样多的元素//f必须没有 side_effect / be stateful , 因为不能保障将functors利用于输出元素的程序3.replace(@beg, @end, old_value, new_value) / replace_if(@beg, @end, condition(O)->bool)4.replace_copy/replace_copy_if ...

April 2, 2021 · 1 min · jiezi

关于c:使程序语言支持变量

上面咱们来让计算器程序反对变量的应用,使得程序能够设置和获取变量的值。从当初开始我将不掩藏咱们要实现的是一个程序语言,因为出自计算器所以命名为 bkcalclang 这次的代码以上一篇《使计算器反对语句块》的代码为根底编写,如果发现不相熟当下的内容能够回顾一下之前的篇章。 代码清单【go语言为例】package mainimport ( "fmt" "strconv" "io/ioutil" "./bklexer")var ValueDict map[string]float64type Node interface { Eval() float64}type Block struct { statements []Node}func NewBlock() *Block { return &Block{}}func (block *Block) AddStatement(statement Node) { block.statements = append(block.statements, statement)}func (block *Block) Eval() { for _, statement := range block.statements { statement.Eval() }}type Number struct { value float64}func NewNumber(token *BKLexer.Token) *Number { value, _ := strconv.ParseFloat(token.Source, 64) return &Number{value: value}}func (number *Number) Eval() float64 { return number.value}type Name struct { name string}func NewName(token *BKLexer.Token) *Name { return &Name{name: token.Source}}func (name *Name) Eval() float64 { if value, found := ValueDict[name.name]; found { return value; } return 0.}type BinaryOpt struct { opt string lhs Node rhs Node}func NewBinaryOpt(token *BKLexer.Token, lhs Node, rhs Node) *BinaryOpt { return &BinaryOpt{opt: token.Source, lhs: lhs, rhs: rhs}}func (binaryOpt *BinaryOpt) Eval() float64 { lhs, rhs := binaryOpt.lhs, binaryOpt.rhs switch binaryOpt.opt { case "+": return lhs.Eval() + rhs.Eval() case "-": return lhs.Eval() - rhs.Eval() case "*": return lhs.Eval() * rhs.Eval() case "/": return lhs.Eval() / rhs.Eval() } return 0}type Assign struct { name string value Node}func NewAssign(token *BKLexer.Token, value Node) *Assign { return &Assign{name: token.Source, value: value}}func (assign *Assign) Eval() float64 { value := assign.value.Eval() ValueDict[assign.name] = value return value}type Echo struct { value Node}func NewEcho(value Node) *Echo { return &Echo{value: value}}func (echo *Echo) Eval() float64 { value := echo.value.Eval() fmt.Println(":=", value) return value}func parse(lexer *BKLexer.Lexer) *Block { block := NewBlock() token := lexer.NextToken() for token.TType == BKLexer.TOKEN_TYPE_NEWLINE { token = lexer.NextToken() } for token.TType != BKLexer.TOKEN_TYPE_EOF { statement := parse_statement(lexer) if statement == nil { return nil; } token = lexer.GetToken() if token.TType != BKLexer.TOKEN_TYPE_NEWLINE && token.TType != BKLexer.TOKEN_TYPE_EOF { return nil; } block.AddStatement(statement) for token.TType == BKLexer.TOKEN_TYPE_NEWLINE { token = lexer.NextToken() } } return block}func parse_statement(lexer *BKLexer.Lexer) Node { token := lexer.GetToken() if token.Name == "SET" { name := lexer.NextToken() if name.Name != "NAME" { return nil } token = lexer.NextToken() if token.Name != "ASSIGN" { return nil } lexer.NextToken() value := parse_binary_add(lexer) if value == nil { return nil } return NewAssign(name, value) } else if token.Name == "ECHO" { lexer.NextToken() value := parse_binary_add(lexer) if (value == nil) { return nil } return NewEcho(value) } return parse_binary_add(lexer)}func parse_binary_add(lexer *BKLexer.Lexer) Node { lhs := parse_binary_mul(lexer) if lhs == nil { return nil } token := lexer.GetToken() for token.Source == "+" || token.Source == "-" { lexer.NextToken() rhs := parse_binary_mul(lexer) if rhs == nil { return nil } lhs = NewBinaryOpt(token, lhs, rhs) token = lexer.GetToken() } return lhs}func parse_binary_mul(lexer *BKLexer.Lexer) Node { lhs := factor(lexer) if lhs == nil { return nil } token := lexer.GetToken() for token.Source == "*" || token.Source == "/" { lexer.NextToken() rhs := factor(lexer) if rhs == nil { return nil } lhs = NewBinaryOpt(token, lhs, rhs) token = lexer.GetToken() } return lhs}func factor(lexer *BKLexer.Lexer) Node { token := lexer.GetToken() if token.Name == "LPAR" { lexer.NextToken() expr := parse_binary_add(lexer) if expr == nil { return nil } token := lexer.GetToken() if token.Name != "RPAR" { return nil } lexer.NextToken() return expr } if token.Name == "NUMBER" { number := NewNumber(token) lexer.NextToken() return number } if token.Name == "NAME" { name := NewName(token) lexer.NextToken() return name } return nil}func main() { lexer := BKLexer.NewLexer() lexer.AddRule("\\d+\\.?\\d*", "NUMBER") lexer.AddRule("[\\p{L}\\d_]+", "NAME") lexer.AddRule("\\+", "PLUS") lexer.AddRule("-", "MINUS") lexer.AddRule("\\*", "MUL") lexer.AddRule("/", "DIV") lexer.AddRule("\\(", "LPAR") lexer.AddRule("\\)", "RPAR") lexer.AddRule("=", "ASSIGN") lexer.AddIgnores("[ \\f\\t]+") lexer.AddIgnores("#[^\\r\\n]*") lexer.AddReserve("set") lexer.AddReserve("echo") bytes, err := ioutil.ReadFile("../test.txt") if err != nil { fmt.Println("read faild") return } code := string(bytes) lexer.Build(code) result := parse(lexer) if result == nil { fmt.Println("null result") return } ValueDict = make(map[string]float64) result.Eval()}引入须要应用的包import ( "fmt" "strconv" "io/ioutil" "./bklexer")fmt 打印输出strconv 字符串转换io/ioutil 读取文件./bklexer 用于词法解析申明用于存储变量值的字典var ValueDict map[string]float64咱们会应用一个map类型的对象来存取值,并以此实现变量赋值和取值的操作。 ...

April 2, 2021 · 5 min · jiezi

关于c++:leetcodeJZ22

题面输出一个链表,输入该链表中倒数第k个节点。为了合乎大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。 例如,一个链表有 6 个节点,从头节点开始,它们的值顺次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。 示例: 给定一个链表: 1->2->3->4->5, 和 k = 2.返回链表 4->5.原题链接 剖析区间滑动思维,看代码正文即可 源代码(正文局部即为思路)/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public: ListNode* getKthFromEnd(ListNode* head, int k) { int n=1; ListNode* tmp = head; ListNode* backup = head; //思考到k可能等于1 if(n==k){ tmp = backup; backup = head; } //当头节点head后退k位后,记录head之前第k位的节点head_before_k,而后head每前进一步,head_before_k也前进一步 while(head->next!=NULL){ head = head->next; n++; if(n==k){ tmp = backup; backup = head; } if(n>k){ tmp = tmp->next; } } return tmp; }};

April 1, 2021 · 1 min · jiezi

关于c++:leetcodeJZ21

题面输出一个整数数组,实现一个函数来调整该数组中数字的程序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半局部。 示例: 输出:nums = [1,2,3,4]输入:[1,3,2,4]注:[3,1,2,4] 也是正确的答案之一。 提醒: 0 <= nums.length <= 500001 <= nums[i] <= 10000原题链接 剖析刚开始想到思路1: 从前向后遍历数组,遇到奇数时,什么也不做;遇到偶数时,把该偶数删除,而后把该偶数放到数组前面然而这种思路会超时 上面剖析超时起因: 数组最大长度为50000,思路1绝不仅仅是简略的遍历数组,工夫复杂度为O(N),思路1还波及到数组的插入、删除,删除操作(erase)的复杂度就是O(N),最坏状况下,工夫复杂度为O(N2),太大。 接下来想到思路2: 采纳双指针,left指向数组首部,right指向数组尾部,left总体趋势向右挪动,right总体趋势向左挪动上面剖析这种思路不超时的起因: 只遍历数组一遍,工夫复杂度为O(N)。 源代码(正文局部即为思路)class Solution {public: vector<int> exchange(vector<int>& nums) { int len = nums.size(); int left = 0; int right = len-1; while(left<right){ //左偶、右奇 if(nums[left]%2==0 && nums[right]%2==1){ //替换数组元素的操作其实很简略,工夫复杂度O(1),空间复杂度O(1) int tmpL = nums[left]; int tmpR = nums[right]; nums[left] = tmpR; nums[right] = tmpL; left++; right--; } //左偶、右偶 if(nums[left]%2==0 && nums[right]%2==0){ right--; } //左奇、右偶 if(nums[left]%2==1 && nums[right]%2==0){ left++; right--; } //左奇、右奇 if(nums[left]%2==1 && nums[right]%2==1){ left++; } } return nums; }};提交后果: ...

April 1, 2021 · 1 min · jiezi

关于c++:leetcodeJZ21

题面请实现一个函数用来判断字符串是否示意数值(包含整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"-1E-16"、"0123"都示意数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。原题链接 剖析除非承受过专业训练,否则一开始很难想到用自动机(Automata)来做,我是一开始凭直觉列举出不同的规定,而后一直的用测试用例试错,最终通过所有测试用例。 上面的代码没有任何参考意义,正文局部能够看一看。 做完本题最大的意义在于: 了解官网自动机解法的优越性坚固了一些C++根底语法常识源代码(正文局部即为思路)class Solution {public: bool isNumber(string s) { char candidate[15] = {'0','1','2','3','4','5','6','7','8','9','.','+','-','E','e'}; set<char> cand; for(int i=0; i<15; i++){ cand.insert(candidate[i]); } set<char> cand2; for(int i=0; i<10; i++){ cand2.insert(candidate[i]); } //cand3没有存在的必要性 set<char> cand3; for(int i=0; i<13; i++){ cand3.insert(candidate[i]); } int rawLen = s.length(); for(int i=0; i<rawLen; i++){ if(s[i]==' '){ int tmpL = i; int tmpR = i; //避免空格有多个 while(s[tmpL]==' ' && tmpL>0){ tmpL--; } while(s[tmpR]==' ' && tmpR<rawLen-1){ tmpR++; } if(cand.find(s[tmpL])!=cand.end() && cand.find(s[tmpR])!=cand.end()){ return false; } } } //之前是判断和空格无关的状况 //删除掉所有的空格 s.erase(std::remove(s.begin(), s.end(), ' '), s.end()); //之后是去掉所有空格之后进行判断 int len = s.length(); //特判 if(len==0){ return false; } //特判 if(len==1){ if(s[0]=='+' || s[0]=='-' || s[0]=='.' || s[0]=='E' || s[0]=='e'){ return false; } else{ if(cand.find(s[0])!=cand.end()){ return true; } else{ return false; } } } //特判 if(s[1]=='+' || s[1]=='-' || s[len-1]=='e' || s[len-1] == 'E'){ return false; } /*后两个特判意义不大*/ int dotNumber = 0; int eNumber = 0; int dotPosition = -1; int ePosition = -1; for(int i=0; i<len; i++){ if(cand.find(s[i])==cand.end()){ return false; } else{ if(s[i]=='.'){ //.最多只能呈现一次 dotNumber++; dotPosition = i; if(dotNumber>=2){ return false; } if(dotPosition==len-1){ if(cand2.find(s[dotPosition-1])==cand2.end()){ return false; } } // cout<<dotPosition; } if(s[i] == 'e' || s[i]=='E'){ eNumber++; ePosition = i; if(eNumber>=2){ return false; } } if(s[i]=='+' || s[i]=='-'){ if(ePosition==-1){ if(i!=0){ return false; } } else{ if(i!=0){ if(i!=ePosition+1){ return false; } } } } } } //e之后不能再有小数点 if(ePosition !=-1 && dotPosition !=-1 && ePosition<dotPosition){ return false; } if(ePosition!=-1){ //e后面的那一个字符,必须是数字或者‘.' if((ePosition-1)<0 || s[ePosition-1]=='+' || s[ePosition-1]=='-'){ return false; } else{ //如果e后面那一个字符是. if(s[ePosition-1]=='.'){ if((ePosition-2)<0 || cand2.find(s[ePosition-2])==cand2.end()){ return false; } } } if(s[ePosition+1]=='+' || s[ePosition+1]=='-'){ if(ePosition+2>=len){ return false; } for(int k=ePosition+2; k<len; k++){ if(cand2.find(s[k])==cand2.end()){ return false; } } } //e前面第一位呈现的不是加号和减号 else{ if(ePosition+1>=len){ return false; } for(int k=ePosition+1; k<len; k++){ if(cand2.find(s[k])==cand2.end()){ return false; } } } } return true; }};提交后果: ...

April 1, 2021 · 2 min · jiezi

关于c:使用malloccallocfree和realloc在C中进行动态内存分配

因为C是一种结构化语言, 因而它具备一些固定的编程规定。其中之一包含更改数组的大小。数组是存储在间断内存地位的我的项目的汇合。 能够看出, 上述数组的长度(大小)为9。然而, 如果须要更改此长度(大小), 该怎么办。例如, 如果存在只须要在此数组中输出5个元素的状况。在这种状况下, 残余的4个索引只会节约该数组中的内存。因而须要将数组的长度(大小)从9缩小到5。 采取另一种状况。在这里, 有9个元素组成的数组, 所有9个索引均已填充。然而须要在此数组中再输出3个元素。在这种状况下, 还须要3个索引。因而, 阵列的长度(大小)须要从9更改为12。 此过程称为C中的动态内存调配. 因而, C动态内存调配能够定义为在运行时更改数据结构(如Array)的大小的过程。 C提供了一些性能来实现这些工作。 C下定义了4个提供的库函数<stdlib.h>头文件, 以不便C编程中的动态内存调配。他们是: malloc()calloc()自在()realloc()让咱们更具体地钻研它们。 C malloc()办法" malloc"or"内存调配"C语言中的办法用于动态分配具备指定大小的单个大内存块。它返回void类型的指针, 该指针能够转换为任何模式的指针。它应用默认垃圾值初始化每个块。 语法如下: ptr = (cast-type*) malloc(byte-size)例如: ptr =(int )malloc(100 sizeof(int));因为int的大小为4个字节, 因而此语句将调配400个字节的内存。并且, 指针ptr保留调配的存储器中的第一个字节的地址。 如果空间有余, 调配将失败并返回NULL指针。 例子: #include <stdio.h>#include <stdlib.h> int main(){ // This pointer will hold the // base address of the block created int * ptr; int n, i; // Get the number of elements for the array n = 5; printf ( "Enter number of elements: %dn" , n); // Dynamically allocate memory using malloc() ptr = ( int *) malloc (n * sizeof ( int )); // Check if the memory has been successfully // allocated by malloc or not if (ptr == NULL) { printf ( "Memory not allocated.n" ); exit (0); } else { // Memory has been successfully allocated printf ( "Memory successfully allocated using malloc.n" ); // Get the elements of the array for (i = 0; i < n; ++i) { ptr[i] = i + 1; } // Print the elements of the array printf ( "The elements of the array are: " ); for (i = 0; i < n; ++i) { printf ( "%d, " , ptr[i]); } } return 0;}输入如下: ...

March 31, 2021 · 5 min · jiezi

关于c++:HackingC-机翻阅读记录-Chapter6Function-Objects

集体笔记向+google机翻(机翻的确很多细节形容不清,看不懂记得参考原文)原文参见:https://hackingcpp.com/cpp/be... Function Objects至多提供一个operator() 重载像一个函数一样能够是有状态的(对象的data数据有记忆,相似函数里有一个static data) Example: Interval Query Lambdas (Basics)

March 31, 2021 · 1 min · jiezi

关于linq:在C中编写LINQ查询

本文介绍能够用于在 C# 中编写 LINQ 查问的三种办法: 应用查问语法。应用办法语法。联合应用查问语法和办法语法。上面的示例演示应用后面列出的每种办法的一些简略 LINQ 查问。 备注这些查问对简略的内存中汇合进行操作;然而,根本语法等同于在 LINQ to Entities 和 LINQ to XML 中应用的语法。示例 - 查问语法编写大多数查问的举荐形式是应用查问语法创立查问表达式 。上面的示例演示三个查问表达式。第一个查问表达式演示如何通过利用蕴含 where 子句的条件来筛选或限度后果。它返回源序列中值大于 7 或小于 3 的所有元素。第二个表达式演示如何对返回的后果进行排序。第三个表达式演示如何依据某个键对后果进行分组。此查问基于单词的第一个字母返回两个组。 // Query #1.List<int> numbers = new List<int>() { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };// The query variable can also be implicitly typed by using varIEnumerable<int> filteringQuery = from num in numbers where num < 3 || num > 7 select num;// Query #2.IEnumerable<int> orderingQuery = from num in numbers where num < 3 || num > 7 orderby num ascending select num;// Query #3.string[] groupingQuery = { "carrots", "cabbage", "broccoli", "beans", "barley" };IEnumerable<IGrouping<char, string>> queryFoodGroups = from item in groupingQuery group item by item[0];留神,查问类型为 IEnumerable。能够应用 var 编写所有这些查问,如上面的示例所示: ...

March 31, 2021 · 2 min · jiezi

关于c++:C内存管理1内存分配的每个层面

C++ 应用程序,应用 memory 的路径 C++ memory primitives调配开释类属可否重载malloc()free()C 函数不可newdeleteC++ 表达式不可::operator new()::operator delete()C++ 函数可allocator<T>::allocate()allocator<T>::deallocateC++ 规范库可自在设计并予以搭配任何容器void *p1 = malloc(512); // 512 bytesfree(p1)complex<int>* p2 = new complex<int>; // one objectdelete p2;void *p3 = ::operator new(512); // 512 bytes::operator delete(p3);// 以下应用 C++ 规范库提供的 allocators// 其接口虽有规范规格,但实现厂商并未齐全恪守;上面三种模式略异#ifdef _MSV_VER // 以下两个函数都是 no-static, 要通过 object 调用。 // 调配 3 个 ints int *p4 = allocator<int>().allocate(3, (int*)0); // 对应规范库分配器的第二个参数 allocator<int>().deallocate(p4, 3);#endif#ifdef __BORLANDC__ // 以下两个函数都是 no-static, 要通过 object 调用。 // 调配 5 个 ints int *p4 = allocator<int>().allocate(5); // 同样蕴含第二个参数,但申明处有默认值,因而调用处可不写 allocator<int>().deallocate(p4, 5);#endif#ifdef __GNUC__ // 晚期版本的实现, 2.9 // 以下两个啊含混都是 static, 可通过全名调用。 // 调配 512 bytes void *p4 = alloc::allocate(512); alloc::deallocate(p4, 512);#endif#ifdef __GNUC__ // 古代版本的实现, 4.9 // 以下两个函数都是 no-static,要通过 object 调用。 // 调配 7 个 ints void *p4 = allocator<int>().allocate(7); allocator<int>().deallocate((int*)p4, 7); // 以下两个函数都是 no-static,要通过 object 调用。 // 调配 9 个 ints void *p4 = __gnu_cxx::pool_alloc<int>().allocate(9); __gnu_cxx::pool_alloc<int>.deallocate((int*)p4, 9);#endifnew expression (new 背地的行为)Complex *pc = new Complex(1, 2);编译器转换为 ==>>Complex *pc;try { /* 1 */ void mem = operator new (sizeof(Complex)); // allocate 申请内存空间 /* 2 */ pc = static_cast<Complex*>(mem); // cast 类型转换 /* 3 */ pc->Complex::Complex(1, 2); // construct 调用构造函数 // 留神:只有编译器才能够像下面那样间接呼叫 ctor}catch (std::bad_alloc) { // 若 allocation 失败,就不执行 constructor }注:申请内存可能会失败,因而引入 try...catch...new 做两个动作 ...

March 30, 2021 · 3 min · jiezi

关于c++:HackingC-机翻阅读记录-Chapter5Standard-Library-–-Part-1

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

March 30, 2021 · 1 min · jiezi

关于c:HackingC-机翻阅读记录-Chapter3Custom-Types-–-Part-1

集体笔记向+google机翻(机翻的确很多细节形容不清,看不懂记得参考原文)原文参见:https://hackingcpp.com/cpp/be... Custom Types – Part 1Simple Classes / Custom TypesPointersDestructorsExceptionsNoexcept

March 30, 2021 · 1 min · jiezi

关于c++:HackingC-机翻阅读记录-Chapter2InputOutput

集体笔记向+google机翻(机翻的确很多细节形容不清,看不懂记得参考原文)原文参见:https://hackingcpp.com/cpp/be... Input&Output1.Command Line Arguments 命令行参数What &WhyHow to Access in C++int main (int const argc, char const* argv/*a pointer to a constant char*/) {Argument ConversionConversion to std::string, int, …String → Number Conversion Functions2.File Input&Output 文件输入输出3.Stream Input&Output 流输入输出4.Recover From Input Error 从输出谬误中复原

March 30, 2021 · 1 min · jiezi

关于c++:leetcodeJZ15剪绳子IIC实现

题面给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,咱们把它剪成长度别离为2、3、3的三段,此时失去的最大乘积是18。 答案须要取模 1e9+7(1000000007),如计算初始后果为:1000000008,请返回 1。 示例 1: 输出: 2输入: 1解释: 2 = 1 + 1, 1 × 1 = 1示例 2: 输出: 10输入: 36解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36提醒: 2 <= n <= 1000原题链接 剖析该题在第14题“剪绳子”的根底上,减少了大数取余局部,上面探讨C++的4种解题思路: 动静布局、数学推导、数学推导优化、贪婪。 最初会再次印证一句古老的话:艺术与迷信终将在某一点相遇 1 动静布局(行不通)在第14题代码根底上,每次从第i-1个状态计算第i个状态时,退出取余运算,会得出谬误的后果。理由如下: 动静布局的特点是,第i个状态依赖于第i-1个状态,最初一个状态(指标状态)依赖于倒数第二个状态,如果在状态转移间进行取余,会呈现有的转移须要取余,有的转移不须要取余: 假如a和b是两个数,a>b,a须要取余,b不须要取余,a取余之后的值为a1,可能呈现a1<b的状况,这就会误导前面的状态转移,最终导致谬误的后果。 这是无奈得出正确后果的动静布局的代码,留神,为了不产生溢出,须要将dp数组和若干两头值改成long类型(详见代码正文): class Solution {public:int cuttingRope(int n){ int base = 1000000007; if(n==2) { return 1; } if(n==3) { return 2; } // 将dp数组改成long类型 long dp[n+1][n+1]; for(int i=0; i<n+1; i++) { for(int j=0; j<n+1; j++) { dp[i][j] = -1; } } for(int i=0; i<n+1; i++) { dp[i][i] = 1; dp[i][1] = i; } //dp[i][j],长度为i的绳子,切成j段,乘积的最大值 for(int tmp=3; tmp<=n; tmp++) { int now_len = tmp; for(int sp=2; sp<now_len; sp++) { int split = sp; // 将x1改成long类型 long x1 = 1; // 将dp数组候选值tmp_max改成long类型 long tmp_max = -1; bool overflow = false; while((x1<now_len) && (now_len-x1)>=(split-1)) { // 将乘积multi改成long类型 long multi = (x1*dp[now_len-x1][split-1]); if(!overflow){ if(multi>base){ multi = multi%base; tmp_max = multi; overflow = true; } else{ if(multi>tmp_max){ tmp_max = multi; } } } else{ if(multi>base){ multi = multi%base; if(multi>tmp_max){ tmp_max = multi; } } } x1++; } dp[now_len][split] = tmp_max; } } int final_max = -1; for(int p=1; p<=n; p++) { if(dp[n][p]>final_max) { final_max = dp[n][p]; } } return final_max;}};2 数学推导务必先看此处的数学推导过程。 ...

March 29, 2021 · 3 min · jiezi

关于c:如何在C语言中动态分配2D数组代码示例

以下是在堆上创立2D数组(或动态分配2D数组)的不同办法。 在以下示例中, 咱们思考了"[R‘作为行数, ‘C‘作为列数, 咱们创立了一个2D数组, 其中r = 3, c = 4和以下值 1 2 3 4 5 6 7 8 9 10 11 121)应用单个指针:一种简略的办法是应用简略的指针算法调配大小为r * c的存储块和拜访元素。 #include <stdio.h>#include <stdlib.h> int main(){ int r = 3, c = 4; int *arr = ( int *) malloc (r * c * sizeof ( int )); int i, j, count = 0; for (i = 0; i < r; i++) for (j = 0; j < c; j++) *(arr + i*c + j) = ++count; for (i = 0; i < r; i++) for (j = 0; j < c; j++) printf ( "%d " , *(arr + i*c + j)); /* Code for further processing and free the dynamically allocated memory */ return 0;}输入如下: ...

March 29, 2021 · 3 min · jiezi

关于c++:C如何通俗理解this指针解析和用法示例

要了解"this"指针, 重要的是要理解对象如何对待类的函数和数据成员。 每个对象都有本人的数据成员正本。全副拜访与代码段中雷同的性能定义。意味着每个对象都有本人的数据成员正本, 并且所有对象共享成员函数的单个正本。 当初的问题是, 如果每个成员函数只有一个正本并且被多个对象应用, 那么如何拜访和更新适当的数据成员? 编译器提供隐式指针以及函数名称" this"。" this"指针作为暗藏参数传递给所有非动态成员函数调用, 并且可用作所有非动态函数体内的局部变量。" this"指针在动态成员函数中不可用, 因为能够在没有任何对象(带有类名)的状况下调用动态成员函数。对于X类, this指针的类型为" X "。另外, 如果X的成员函数申明为const, 则this指针的类型为" const X "在晚期的C ++版本中, " this"指针将被更改;通过这样做, 程序员能够更改办法正在解决的对象。该性能最终被删除, 当初在C ++中为r值。C ++通过调用以下代码让对象销毁本身: delete this ;正如Stroustrup所说, "this"可能是指针的参考, 但在C ++的晚期版本中没有该参考。如果将" this"用作参考, 则能够防止上述问题, 并且比指针更平安。 以下是应用" this"指针的状况:1)当本地变量的名称与成员的名称雷同时 #include<iostream>using namespace std; /* local variable is same as a member's name */class Test{private : int x;public : void setX ( int x) { // The 'this' pointer is used to retrieve the object's x // hidden by the local variable 'x' this ->x = x; } void print() { cout << "x = " << x << endl; }}; int main(){ Test obj; int x = 20; obj.setX(x); obj.print(); return 0;}输入如下: ...

March 29, 2021 · 3 min · jiezi

关于c#:C-笔记

C# 类型零碎

March 29, 2021 · 1 min · jiezi

关于c:C-系统标准库

c零碎的规范库里的syscall零碎调用号都在iOS零碎库/usr/include里的sys/syscall.h里

March 29, 2021 · 1 min · jiezi

关于c#:C队列Queue介绍和用法详细指南

队列用于示意对象的先进先出(FIFO)汇合。当你须要我的项目的先进先出拜访时应用。这是非通用类型的汇合, 在System.Collections命名空间。依据程序的须要, 它用于创立一直增长的动静汇合。在队列中, 你能够存储雷同类型和不同类型的元素。通常, 当你以与存储在汇合中雷同的形式拜访该信息时, 队列是有用的, 它是存储数据的长期存储。 下图阐明了Queue类的层次结构: 重要事项: Queue类实现了IEnumerable, ICollection和可克隆接口。当你在列表中增加我的项目时, 该我的项目称为入队.当你删除我的项目时, 该我的项目称为出队.队列承受null作为援用类型的有效值。将元素增加到队列后, 将通过重新分配外部数组来依据须要主动减少容量。在队列中, 容许你存储反复的元素。队列的容量是队列能够包容的元素数。如何创立队列?队列类有四个构造函数用于创立队列的办法如下: Queue():此构造函数用于创立Queue类的实例, 该实例为空并具备默认的初始容量, 并应用默认的增长因子。Queue(ICollection):此构造函数用于创立Queue类的实例, 该实例蕴含从指定汇合中复制的元素, 具备与复制的元素数量雷同的初始容量, 并应用默认的增长因子。Queue(Int32):此构造函数用于创立Queue类的实例, 该实例为空并具备指定的初始容量, 并应用默认的增长因子。Queue(Int32, Single):此构造函数用于创立Queue类的实例, 该实例为空并具备指定的初始容量, 并应用指定的增长因子。让咱们看看如何应用Queue()构造函数创立一个队列: 第1步:包含零碎汇合借助using关键字在程序中命名空间。 语法如下: using System.Collections;第2步:应用Queue类创立一个队列, 如下所示: Queue queue_name = new Queue();第3步:如果要在队列中增加元素, 请应用入队在队列中增加元素的办法。如下例所示。 例子: // C# program to illustrate queueusing System;using System.Collections; public class GFG { static public void Main() { // Create a queue // Using Queue class Queue my_queue = new Queue(); // Adding elements in Queue // Using Enqueue() method my_queue.Enqueue( "GFG" ); my_queue.Enqueue(1); my_queue.Enqueue(100); my_queue.Enqueue( null ); my_queue.Enqueue(2.4); my_queue.Enqueue( "Geeks123" ); // Accessing the elements // of my_queue Queue // Using foreach loop foreach ( var ele in my_queue) { Console.WriteLine(ele); } }}输入如下: ...

March 28, 2021 · 3 min · jiezi

关于c#:分支语句C如何使用Switch语句用法示例

在C#中, Switch语句是多路分支语句。它提供了一种无效的形式, 能够依据表达式的值将执行转移到代码的不同局部。开关表达式是整数类型, 例如int, char, byte或short, 或者是枚举类型, 或者是字符串类型。查看表达式的不同状况, 而后执行一次匹配。 语法如下: switch (expression) {case value1: // statement sequence break;case value2: // statement sequence break;...case valueN: // statement sequence break;default: // default statement sequence}switch执行流程图: 要记住的要点: 在C#中, 不容许反复的大小写值。开关中变量的数据类型和案例的值必须是同一类型。案例的值必须是常量或文字。不容许应用变量。break in switch语句用于终止以后序列。默认语句是可选的, 它能够在switch语句中的任何地位应用。不容许应用多个默认语句。例子: // C# program to illustrate// switch case statementusing System; public class GFG { // Main Method public static void Main(String[] args) { int nitem = 5; switch (nitem) { case 1: Console.WriteLine( "case 1" ); break ; case 5: Console.WriteLine( "case 5" ); break ; case 9: Console.WriteLine( "case 9" ); break ; default : Console.WriteLine( "No match found" ); break ; } }}输入如下: ...

March 28, 2021 · 3 min · jiezi

关于c++:C中对文件的操作

文件操作写在后面 <u>ofstream写文件,也就是对文件的输入,所以out,以O结尾</u> <u>ofstream的成员函数中蕴含write写文件</u> <u>ifstream读文件,也就是文件对外输出,所以in,以I结尾</u> <u>ifstream的成员函数中蕴含read读文件</u> 操作文件蕴含头文件fstream 类型:文本文件:ASCLL存储 二进制文件:二进制存储 操作文件三大类1、ofstream:写操作 2、ifstream:读操作 3、fstream:读写操作 文本文件操作写文件1、蕴含头文件 fstream 2、创立流对象 ofstream ofs 3、关上文件 ofs.open(”文件门路“,"打开方式"); 4、写数据 ofs<<"写入的数据"; 5、敞开文件 ofs.close 打开方式解释ios::in为读文件而关上文件ios::out为写文件关上文件ios::ate初始地位:文件尾ios::app追加形式写文件ios::trunc如果文件存在先删除,再创立ios::binary二进制文件留神:文件打开方式能够配合应用,利用|操作符 例如:用二进制形式写文件 ios::binary|ios::out #include<iostream>#include<fstream>using namespace std;void test(){ //1、蕴含头文件 //2、创立流对象 ofstream ofs; //3、关上文件 ofs.open("材料.txt",ios::out); //4、写数据 ofs << "此情可待成追忆,只是过后已惘然"; //5、敞开文件 ofs.close();}int main(){ test(); system("pause");}总结: 文件操作必须蕴含头文件fstream 读文件能够利用ofstream,或者fstream类 关上文件时候须要操作文件的门路,以及打开方式 利用<<能够向文件中写数据 操作结束要敞开文件 读文件1、蕴含头文件 2、创立流对象 ifstream ifs 3、关上文件判断是否关上 ifs.open(“材料”,iOS::in); ifs.is_open返回布尔类型用if语句判断文件是否关上胜利 4、读数据(四种办法) 1/char buf[1024]={0};while(ifs>>buf){cout<<buf<<endl;}2/char buf[1024]={0};while(ifs.getline(buf,sizeof(buf))){cout<<buf<<endl;}3/string bufwhile(getline(ifs,buf)){cout<<buf<<endl;}4/不举荐char c;while((c=ifs.get())!=EOF)//end of file{cout<<c;}5、敞开文件 ifs.close() #include<iostream>#include<fstream>#include<string>using namespace std;void test(){ //1、蕴含头文件 //2、创立流对象 ifstream ifs; //3、关上文件 ifs.open("材料.txt", ios::in); if (ifs.is_open() == false) { cout << "文件关上失败!" << endl; } //4、读数据 string buf; while (getline(ifs, buf)) { cout << buf << endl; } //5、敞开文件 ifs.close();}int main(){ test(); system("pause");}二进制文件操作写文件ios::binary ...

March 27, 2021 · 1 min · jiezi

关于c++:C-STL标准库概述容器

一、定义STL,英文全称 sdard template library,中文可译为规范模板库或者泛型库,其蕴含有大量的模板类和模板函数,是 C++ 提供的一个根底模板的汇合,用于实现诸如输出/输入、数学计算等性能。简略来讲,STL是一些容器、算法和其余一些组件的汇合。二、组成构造STL是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 局部形成,其中前面 4 局部是为前 2 局部服务的,它们各自的含意如下图所示。 C++ 规范中,STL被组织为 13 个头文件。 三、容器容器(container)是用于存放数据的类模板。可变长数组、链表、均衡二叉树等数据结构在 STL 中都被实现为容器。容器中能够寄存根本类型的变量,也能够寄存对象。对象或根本类型的变量被插入容器中时,理论插入的是对象或变量的一个复制品。容器分为两大类,即程序容器和关联容器;也能够分为三大类:序列容器、排序容器和哈希容器。1、程序容器(序列容器) 程序容器或序列容器,其特点就是元素在容器中的地位同元素的值无关,即容器不会对存储的元素进行排序。将元素插入容器时,指定在什么地位(尾部、头部或两头某处)插入,元素就会位于什么地位。STL规范库中所有的序列式容器,包含 array、vector、deque、list 和 forward_list。2、关联容器(排序容器、有序关联容器) 关联容器分为 set(汇合)和 map(映射表)两大类,及其衍生体 multiset 和 multimap。这些容器的底层机制均以 RB-tree(红黑树)实现,均衡二叉树中的一种(还包含AVL-tree、AA-tree)。RB-tree 也是一个独立容器,但并不凋谢应用。SGI STL 还提供一个不在规范规格的关联式容器 hash_table(散列表),以及以 hash_table 为底层机制而实现的 hash_set散列汇合、hash_map散列映射表、hash_multiset散列多键汇合、hash_multimap散列多键映射表。关联容器中每个元素都有一个键值key和一个实值value。关联容器内的元素是排序的。插入元素时,容器会按肯定的排序规定将元素放到适当的地位上,因而插入元素时不能指定地位。默认状况下,关联容器中的元素是从小到大排序(或按关键字从小到大排序)的,而且用`<`运算符比拟元素或关键字大小。因为是排好序的,所以关联容器在查找时具备十分好的性能。3、无序关联容器(哈希容器) 无序关联式容器,它们常被称为“无序容器”、“哈希容器”或者“无序关联容器”。无序容器是 C++ 11 规范才正式引入到 STL 规范库中的,如果要应用该类容器,则必须抉择反对 C++ 11 规范的编译器。和关联式容器一样,无序容器也应用键值对(pair 类型)的形式存储数据。然而它们有着实质上的不同:关联式容器的底层实现采纳的树存储构造,更确切的说是红黑树结构;无序容器的底层实现采纳的是哈希表的存储构造。C++ STL 底层采纳哈希表实现无序容器时,会将所有数据存储到一整块间断的内存空间中,并且当数据存储地位发生冲突时,解决办法选用的是“链地址法”(又称“开链法”)。基于底层实现采纳了不同的数据结构,因而和关联式容器相比,无序容器具备以下 2 个特点:①无序容器外部存储的键值对是无序的,各键值对的存储地位取决于该键值对中的键;②和关联式容器相比,无序容器善于通过指定键查找对应的值(均匀工夫复杂度为 O(1));但对于应用迭代器遍历容器中存储的元素,无序容器的执行效率则不如关联式容器。和关联式容器一样,无序容器只是一类容器的统称,其蕴含有 4 个具体容器,别离为 unordered_map、unordered_multimap、unordered_set 以及 unordered_multiset。这4种无序容器的名称,仅是在关联式容器名称的根底上,增加了 "unordered_"。以 map 和 unordered_map 为例,其实它们仅有一个区别,即 map 容器内存会对存储的键值对进行排序,而 unordered_map 不会。也就是说,C++ 11 规范的 STL 中,在已提供有 4 种关联式容器的根底上,又新增了各自的“unordered”版本(无序版本、哈希版本),进步了查找指定元素的效率。理论场景中如果波及大量遍历容器的操作,倡议首选关联式容器;反之,如果更多的操作是通过键获取对应的值,则应首选无序容器。留神,因为哈希容器直到 C++ 11 才被正式纳入 C++ 规范程序库,而在此之前,“民间”流传着 hash_set、hash_multiset、hash_map、hash_multimap 版本,不过该版本只能在某些反对 C++ 11 的编译器下应用(如 VS),有些编译器(如 gcc/g++)是不反对的。4、容器适配器 ...

March 26, 2021 · 1 min · jiezi

关于c++:动态规划数组等子集和问题总结

1.是否划分成2个相等和的子数组,转化为0-1背包问题,何为sum/2,二重循环从大到小遍历 #include <stdio.h>#include <iostream>#include<vector>using namespace std;bool canPartion(vector<int>nums) { int sum = 0; for (int i = 0; i < nums.size(); i++) { sum += nums[i]; } if (sum % 2 == 1) { return false; } int target = sum / 2; vector<int> dp(target + 1, 0); for (int i = 0; i < nums.size(); i++) { for (int j = target; j >= nums[i]; j--) { dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]); } } std::cout << dp[target] << " " << target << endl; return dp[target] == target;}int main(){ vector<int> nums = {1, 5, 11, 5}; cout << canPartion(nums) << endl; return 0;}2。是否划分成k个和雷同数组,间接递归 ...

March 25, 2021 · 2 min · jiezi

关于c++:细数继承与派生纯干货推荐10

目录一、类与对象的根底1、简略概念2、类的类型①、私有②、公有③、爱护4、扩大:(类和构造体的区别)二、应用类和对象办法一:办法二:办法三:三、继承与派生1、名称解释2、繁多继承①、私有继承②、公有继承③、爱护继承④、总结3、多重继承4、注意事项①、互相赋值②、防止二义性最近在学习C++面向对象设计,看似很根底的内容实际上有多知识点值得斟酌。 学完类与对象,就很想写点货色来输入我的思考和学习的想法,也心愿各位朋友一起多多交换,如果文章里有谬误的中央请多多斧正。 一、类与对象的根底前言: 学习C,要有面向过程的设计思维。 学习C++,要有面向对象的设计思维。 1、简略概念对象: 任何一个事物都能够看成一个对象,比方一个班级,一个学校,一篇文章等等。 对象蕴含两个因素:属性 和 行为。 举个栗子:咱们把一个班级看做一个对象,那么班级里的人数,业余,均匀问题叫做属性(动态的)。班级上课,加入运动会等叫做行为(动静的)。一个对象个别是由一组属性和一组行为形成。 封装 :个别对象里的内容会波及到机密,在面对外人时。咱们能够把对象里的局部内容盖起来不让外人看到。 举个栗子:班级期末考试,家长想晓得班级里所有人的问题(家长对班级这个对象进行拜访/调用),但咱们只通知家长班级均匀问题,所有的同学的问题都不对外颁布(集体问题进行封装)。相同,平均分就是属于大家都能看到/接触/调用的内容。 2、类的类型①、私有听名字就晓得,这是个大家都能看失去或者接触失去的内容。 比方上个栗子中的班级平均分就属于私有局部,班级中的每位家长都能够看到。 `class Student{ public:}` ②、公有听名字就晓得属于定义对象所领有的局部,不能让外界看到或者解除(当然也会有例外,这里挖个坑)。把局部成员进行封装,避免外人看到。 上个栗子中对应的是班级里每位同学的问题。 `class Student{ private:}` ③、爱护首先一个问题,爱护类型和公有类型有什么区别? 这里咱们先做个简略的介绍: 公有和爱护的成员函数和数据只能被本类中的其余成员函数所调用,而不能被类外调用。 而爱护的性能在继承与派生中更能体现进去, 当然也有例外的状况产生。同公有类型一样,挖个坑。 写完例外情况(友元),我会在此处做个文章链接。 `class Student{ protected:}` 4、扩大:(类和构造体的区别)先上两种定义:(Student为例) `///classclass Student{ private: int num; char sex: string name; public: void display();};` `///struct(C)struct Student{ int num; char sex: string name; }stu;void display(int num,char sex,string name);` 补充一个小常识:C++在设计的时候就以兼容C,但又不是齐全简略的继承C,同时还要有本人的特点为准则进行开发。 最显著的就是struct中没有private和public,想给student增加什么属性间接写进去就完事了。 class不同,除了想把属性加进去外,还要思考这个属性要不要让他人看到。想让他人能看到,退出public中。不想让他人看到就退出private中。 举个栗子: 如果把struct比作一家新百伦鞋店,那么这家店就属于通透型的,穿鞋换鞋坐在沙发板凳上就能够实现,无需试衣间。所有的中央和盘托出。 class更像是含有试衣间的优衣库。筛选衣服的时候大家都能看到,然而试衣服的时候就必须要去试衣间里。我想没有多少人在换衣服的时候被他人看到吧? 以上内容援用于比拟C中的struct和C++中的class。 而在C++中对于struct的用法进行了降级: `///struct(C++)struct Student{ private: int num; char sex: string name; public: void display();};` 可见C++中应用struct也能够像class一样对成员进行public或private分类。 ...

March 25, 2021 · 3 min · jiezi

关于opencv:Learning-OpenCV3习题答案

不定时更新。。Codes

March 24, 2021 · 1 min · jiezi

关于c#:快速了解C-80中可空引用类型Nullable-reference-type语言特性

Visual C# 8.0中引入了可空援用类型(Nullable reference type),通过编译器提供的弱小性能,帮忙开发人员尽可能地躲避由空援用带来的代码问题。这里我大抵介绍一下可空援用类型的根本内容。刚开始接触这个语言个性的时候,可能会不太容易了解。援用类型原本不就是能够为空(null)的么,为啥还要特地地引入“可空援用类型”的概念呢?其实这是从编译器的角度要求开发人员在编程的时候就思考某个变量是否有可能为空,从而尽可能地缩小由空援用所带来的代码谬误。假如有如下类: class Student{ public Student(string name, DateTime dayOfBirth) => (Name, DayOfBirth) = (name, dayOfBirth); public string Name { get; set; } public DateTime DayOfBirth { get; set; } public string Notes { get; set; }}此类定义了一个“学生”实体的根本信息,为了简化起见,这里只列出了须要探讨的几个属性: Name:学生姓名DayOfBirth:学生生日Notes:对学生信息的一些备注假如咱们有两个操作:在所有学生中,找出所有具备备注信息的学生,以及对所有学生按姓名排序,在C#中很容易应用Linq来实现: var studentsHasNotes = students.Where(s => s.Notes.Length > 0);以及: var orderedStudents = students.OrderBy(s => s.Name);到目前为止没啥问题,程序可能失常运行。然而认真进行代码审查不难发现,在获取所有具备备注信息的学生的代码中(也就是下面第一段代码中),有可能呈现空援用的异样,因为对于一个“学生”实体来说,它的Notes属性是有可能为null的。当初咱们关上“可空援用类型”这一语言个性,打开方式次要有两种:能够在我的项目级别,编辑csproj我的项目文件进行设置,也能够通过#nullable预编译指令来实现: 编辑csproj我的项目文件,退出<Nullable>enable</Nullable>即可: 通过#nullable预编译指令来实现,只须要在代码中须要的中央退出#nullable指令即可: 启用“可空援用类型”这一语言个性之后你会发现,在下面的Student类的构造函数处呈现了一个正告,提醒在构造函数执行实现时,不可为空的“Notes”属性须要有一个不为空的值,倡议将其设置为可空的string类型。为什么编译器仅提醒Notes有可能为空,而不是Name属性呢?因为构造函数中曾经为Name赋值了,因而,对于任何一个Student的对象,Name不可能为空,而Notes则不然。 Name不可能为空?它不是string类型么?万一在代码中它为空了怎么办?别急,编译器是不会容许呈现这种状况的: 在此,咱们将Notes属性设置为string类型,于是你会发现,位于构造函数上的正告信息曾经没有了,因为咱们容许Student对象能够没有Notes数据,但在“找出所有具备备注信息的学生”这一操作时,又会呈现正告,提醒说Notes有可能为空: 于是,你会发现,在启用了可空援用类型的语言个性后,咱们就须要认真考查Student类型中的每一个援用类型的属性,看它在理论利用中是否有可能为空,如果可能为空,则用可空援用类型来定义属性,之后编译器就会帮忙你来剖析哪些地方有可能存在空援用。 在下面的“找出所有具备备注信息的学生”例子中,如果你感觉Notes必定不会为空,那么也能够应用“!”操作符来笼罩编译器的正告信息,比方: 当初风行的.NET开源框架基本上都曾经反对了可空援用类型了,而且如果你是一名开源框架的开发人员,也强烈建议在你的框架中启用这一语言个性来尽可能地防止空援用问题。比方,如果你在代码中启用了可空援用类型个性,那么当你从Newtonsoft.Json的JsonConverter类继承时,你会发现,你必须应用可空援用类型的函数重载: ...

March 24, 2021 · 1 min · jiezi

关于c:C程序打印带有星形图案的锐角三角形

解题思路绿色部份打印的是左直角三角形 红色部份打印的是左倒置直角三角形 /*打印如下:************************* */#include <stdio.h>int main(void){ int i; int j; for (i = 1; i <= 5; i++) { for (j = 1; j <= i; j++) { printf("*"); } printf("\n"); } for (i = 1; i <= 5; i++) { for (j = 1; j <= 5 - i; j++) { printf("*"); } printf("\n"); } return 0;}

March 24, 2021 · 1 min · jiezi

关于loadrunner:Error-27723-Step-download-timeout-120-seconds-has-expired

软件LoadRunner Controller(我的LoadRunner是12.55版本的) 报错Action.c(116): Error -27723: Step download timeout (120 seconds) has expired when downloading resource "https://ieonline.microsoft.com/iedomainsuggestions/ie11/suggestions.zh-CN". Set the "Step Timeout caused by resources is a warning" Run-Time Setting to Yes/No to have this message as a warning/error, respectively [MsgId: MERR-27723]解决关上Runtime Setting   单击Internet Protocol下的Preferences。单击图中的Options按钮   顺次批改HTTP下的HTTP-request connect timeout(sec)、HTTP-request receive timeout(sec)以及General下的Step download timeout(sec)的值120为600或更大的数字 补充如果你方才曾经设置过了并运行了脚本A,当初你运行脚本B时可能还会报这个错,Controller仿佛不会保留你的Runtime Setting设置,也就是说即使你这次设置过了,将120改为600了,下次它可能还会变回120 参考Step download timeout (120 seconds)是什么问题?

March 23, 2021 · 1 min · jiezi

关于qt:Qt4K高分屏自适应解决字体没有跟随组件增大的问题

解决背景在一次做我的项目的过程中,公司让我做高分屏适配,就是让咱们所开发的软件反对4K屏的显示,我在百度上开始搜寻材料,有很多博客给出的答案就是: #if(QT_VERSION >= QT_VERSION_CHECK(5,6,0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);#endif QApplication a(argc, argv);   解决过程我也这样做了,后果,没错,Qt的确是把窗口以及组件的大小进行了屏幕自适应,然而组件内的字体大小却没有扭转,所以显示进去的后果就是这个样子,如图:  解决办法看上去是不是很不协调,很丑有没有,然而没方法,你如果非得让我给你解释原理的话,就是:起因是qt的dpi计算错误,这样的状况会导致qt在不同的平台上大小不一,解决的办法就是设置好qt的dpi,qt是依据显示器的物理长度或者宽度于分辨率的关系来计算dpi的, 所以,咱们把Qt字体的PointSize从新设置,一次,就能解决这个问题。废话不说间接上代码: #if(QT_VERSION >= QT_VERSION_CHECK(5,6,0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);#endif QApplication a(argc, argv); QFont font = a.font(); font.setPointSize(10);//这个值依据本身状况自行调节,如果字体没变动,把setPointSize()内的值持续增大 a.setFont(font); 当你把setPointSize()内的值设置大了之后,你会发现,显示居然失常了,如图:   最终代码当初的话,字体大小就曾经失常了,然而如果在1080P下面字体可能会更大,因为你当初是在4K屏,所以看上去是失常的,那咱们接下来应该怎么做,很简略,让setPointSize()的值依据零碎自行调节,问题就解决了,废话不说,持续上代码: #if(QT_VERSION >= QT_VERSION_CHECK(5,6,0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);#endif QApplication a(argc, argv); const float DEFAULT_DPI = 96.0; HDC screen = GetDC(NULL); FLOAT dpiX = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSX)); ReleaseDC(0, screen); float fontSize = dpiX / DEFAULT_DPI; QFont font = a.font(); font.setPointSize(font.pointSize()*fontSize); a.setFont(font);好了,这样的话,问题解决,这样自适应问题就解决掉了注:这些操作都需在main主函数外面操作

March 23, 2021 · 1 min · jiezi

关于c:用C程序打印空心星形金字塔

解题思路用10*10网格 第1行打印9个空格 第2行打印8个空格 第3行打印7个空格 以此类推 从第1行开始列如果(j==1||j==i)则打印星与空格,否则打印两个空格,最初一行打印10个星和空格 /*打印如下: * * * * * * * * * * * * * * * * ** * * * * * * * * * */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 0; j < 10 - i; j++) { printf(" "); } for (j = 1; j <= i; j++) { if (j == 1 || j == i) { printf("* "); } else if (i == 10) { printf("* "); } else { printf(" "); } } printf("\n"); } return 0;}

March 23, 2021 · 1 min · jiezi

关于c++:网络编程IO复用函数

I/O复用使得程序可能同时监听和解决多个文件描述符,进步程序的效率。支流的零碎调用次要有select,poll和epoll。 select零碎调用原型int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* expectfds, struct timeval* timeout);其中,nfds为select监听的最大文件描述符个数+1,fd_set是一个数据结构,其本质上是一个整形数组,数组中的每一个位都标记一个文件描述符,而fd_set的容量是由内核决定的,即select能同时解决的文件数量是无限的。 fd_set操作的一些宏定义: FD_ZERO(fd_set *fdset) —— 革除fdset所有的位FD_SET(int fd, fd_set *fdset) —— 设置fd位FD_CLR(int fd, fd_set *fdset) —— 革除fd位int FD_ISET(int fd, fd_set *fdset) —— 测试fd位是否被设置

March 22, 2021 · 1 min · jiezi

关于c++:C-常见编译运行错误总结

最近开始写C++的代码了,小结一下谬误和起因。 Symbols[Symbols not found in architecture + linker command failed with exit code 1]起因: symbol没有找到,实际上就是应用某个变量或者某个函数名的时候,它的申明没有找到。很可能是函数头的变量类型没写对。应用MacOS的clang++作为调试器,提醒的谬误可能和最终用g++编译的不同,最好还是应用gdb调试Segmentfault个别是指针或者数组越界之类的谬误

March 22, 2021 · 1 min · jiezi

关于c#:技术分享PPT整理二C常用类型与数据结构

这篇博客起源于我对Dictionary、List、ArrayList这几个类区别的好奇,过后在革新公司的旧零碎,发现很多中央应用了ArrayList,但咱们平时用的多是泛型汇合List<T>,革新的时候要全副替换成泛型汇合,本来我对于这几个汇合类就有些疑难,所以略微做了些功课。 装箱与拆箱在开始剖析汇合类之前先简略说下装箱拆箱的概念,在理论的开发中,兴许咱们很少提到这个概念,但它实际上遍布咱们的开发过程,并且对性能有很大的影响,首先来理解一下什么是装箱和拆箱: 装箱和拆箱是值类型和援用类型之间互相转换是要执行的操作。装箱在值类型向援用类型转换时产生拆箱在援用类型向值类型转换时产生int i = 123;object o = (object)i; // 将int转object,产生装箱int j = (int)o; // 从object转回原来的类型,解除装箱通过下面的阐明和例子能够看到,这是一个很简略的概念,实际上就是在咱们进行类型转换时产生的一种状况,但如果咱们再深刻一些能够从数据结构的角度来更清晰地解释这个问题,先看上面两个例子: 值类型int i = 123;object o = i; // 装箱会把i的值拷贝到oi = 456; // 扭转i的值// i的变动不会影响到o的值Console.WriteLine("{0},{1}", i,o); 原始值类型和装箱的对象应用不同的内存地位,因而可能存储不同的值。 援用类型public class ValueClass{ public int value = 123; public void Test() { ValueClass b = new ValueClass(); ValueClass a = b; b.value = 456; Console.WriteLine("{0},{1}", a.value, b.value); }} 两个变量指向同一块内存数据,当一个变量对内存区数据扭转之后,另一个变量指向的数据当然也会扭转。 简略地说,值类型的赋值相当于间接将物品交给另一个人,而援用类型的赋值相当于将一个寄存了物品的地址复制给另一个人,每当有人来找的时候,再依据地址去找到物品,地址没有产生扭转的状况下,将外面的物品替换,那么前面所有顺着线索找过去的人拿到的都是被替换的物品。如果以数据结构的常识来看,援用类型和值类型就是别离寄存在堆和栈外面的数据。 堆与栈咱们把内存分为堆空间和栈空间: 线程堆栈:简称栈Stack,栈空间比拟小,然而读取速度快托管堆:简称堆Heap,堆空间比拟大,然而读取速度慢栈存储的是根本值类型,堆存储的是new进去的对象。援用类型在栈中存储一个援用,其理论的存储地位位于托管堆。 值类型:在C#中,继承自System.ValueType的类型被称为值类型,次要有以下几种:bool、byte、char、decimal、double、enum、float、Int、long、sbyte、short、struct、uint、ulong、ushort 援用类型:以下是援用类型,继承自System.Object:class、interface、delegate、object、string 装箱(Boxing)咱们再回头看方才例子的装箱操作,能够用很清晰的图片来表白: int i = 123;object o = (object)i; ...

March 22, 2021 · 2 min · jiezi

关于c:用C程序打印星形金字塔

解题思路用10*10网格 9个空格(10-1行号)和一个星号(1行号) 第二行8个空格(10-2行号)和两个星号(2行号) 第三行7个空格(10-3行号)和三个星号(3行号) 第四行6个空格(10-4行号)和四个星号(4行号) 以此类推… 从法则来看,每行打印的都与行号有 /* 打印如下: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * */#include <stdio.h>int main(){ int i; int j; for(i=1;i<=10;i++){ for(j=0;j<10-i;j++){ printf(" "); } for(j=1;j<=i;j++){ printf("* "); } printf("\n"); } return 0;}

March 18, 2021 · 1 min · jiezi

关于c:Socket编程基础知识

罕用的数据结构及函数地址转换类主机字节序与网络字节序的转换主机序通常为小端,网络字节序为大端。下列函数在<netinet/in.h>包中: usinged long int htonl(unsigned long int hostlong) —— 主机序转网络序(host to network long)usinged short int htons(unsigned short int hostlong) —— 主机序转网络序(host to network short)usinged long int ntohl(unsigned long int hostlong) —— 网络序转主机序(network to host long)usinged short int ntohl(unsigned short int hostlong) —— 网络序转主机序(network to host short)IP地址转换函数计算机可能辨认二进制的IP地址,但生存中咱们罕用点分十进制来示意IPv4地址,用十六进制示意IPv6地址,于是须要一些函数对他们进行一些转换,这些函数位于<arpa/inet.h>包中。 in_addr_t inet_addr(const char* strprt) —— 将点分十进制IPv4地址转化成网络字节序的地址int inet_aton(const char cp, struct in_addr inp) —— 同上,将后果存在指针里char* inet_ntoa(struct in_addr in) —— 将二进制后果转为点分十进制int inet_pton(int af, const char src, void dst) —— 将十六进制地址转为二进制地址,并存在指针。其中af示意地址族,能够是AF_NET或AF_NET6。const char inet_ntop(int af, const void src, char* dst, socklen_t cnt) —— 将二进制地址转换为十六进制地址,其中cnt指定指标存储单元大小socket地址构造通用socket地址——sockaddr#include <bits/socket.h>struct sockaddr { sa_family_t sa_family; char sa_data[14];}其中,sa_family是地址族,包含:PF_UNIX(UNIX本地区协定族)、PF_INET(TCP/IPv4地址协定族)、PF_INET6(IPv6地址协定族)。留神:AF_xxx和PF_xxx在socket.h中值雷同,因而常混用。sa_data用于寄存socket地址值,不同协定的地址具备不同含意和长度。PF_UNIX寄存的是文件的路径名(疑难:在PF_UNIX中,socket是以一个什么样的模式存在的?),长度可达到108字节;在PF_INET中,寄存16bit的端口号和32bit的IPv4地址;在AF_INET6中,寄存的是128bit的IPv6地址、16bit端口号以及32bit的ID。因为14字节显然无奈容下所有地址,因而linux中sockaddr定义为: ...

March 17, 2021 · 1 min · jiezi

关于c++:CC-性能优化背后的方法论TMAM

开发过程中咱们多少都会关注服务的性能,然而性能优化是绝对比拟艰难,往往须要多轮优化、测试,属于费时费力,有时候还未必有好的成果。然而如果有较好的性能优化办法领导、工具辅助剖析能够帮忙咱们疾速发现性能瓶颈所在,针对性地进行优化,能够事倍功半。 性能优化的难点在于找出要害的性能瓶颈点,如果不借助一些工具辅助定位这些瓶颈是十分艰难的,例如:c++程序通常大家可能都会借助perf /bcc这些工具来寻找存在性能瓶颈的中央。性能呈现瓶颈的起因很多比方 CPU、内存、磁盘、架构等。本文就仅仅是针对CPU调优进行调优,即如何榨干CPU的性能,将CPU吞吐最大化。(实际上CPU出厂的时候就曾经决定了它的性能,咱们须要做的就是让CPU尽可能做有用功),所以针对CPU利用率优化,实际上就是找出咱们写的不够好的代码进行优化。 一、示例先敬上代码: #include <stdlib.h> #define CACHE_LINE __attribute__((aligned(64))) struct S1 { int r1; int r2; int r3; S1 ():r1 (1), r2 (2), r3 (3){} } CACHE_LINE; void add(const S1 smember[],int members,long &total) { int idx = members; do { total += smember[idx].r1; total += smember[idx].r2; total += smember[idx].r3; }while(--idx); } int main (int argc, char *argv[]) { const int SIZE = 204800; S1 *smember = (S1 *) malloc (sizeof (S1) * SIZE); long total = 0L; int loop = 10000; while (--loop) { // 不便比照测试 add(smember,SIZE,total); } return 0; }注:代码逻辑比较简单就是做一个累加操作,仅仅是为了演示。编译+运行: ...

March 17, 2021 · 3 min · jiezi

关于c:用C程序打印星形棱形

解题思路用5*10网格 第0行打印5个空格和5个星 第1行打印4个空格和5个星 第2行打印3个空格和5个星 /*打印如下: ***** ***** ***** ***** ***** */#include <stdio.h>int main(){ int i; int j; for (i = 0; i < 5; i++) { for (j = 0; j < 10 - 5 - i; j++) { printf(" "); } for (j = 0; j < 5; j++) { printf("*"); } printf("\n"); } return 0;}

March 17, 2021 · 1 min · jiezi

关于qt5:项目实战QtC轨道交通行业高性能高流畅度模拟火车移动图像控件

若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114866533长期继续带来更多我的项目与技术分享,征询请加QQ:21497936、微信:yangsir198808 红瘦子(红模拟)的博文大全:开发技术汇合(蕴含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门) 开发专栏:商业我的项目实战 需要 高清线阵相机扫描火车并主动切割单节车厢实现图像合成。通过视频图像处理组件晦涩模仿火车行驶整个过程的视频图像: 1.模仿火车通过时的滚动图像,图像次要以两侧和顶部图像的预览为主; 2.模仿的图像数据可反对手动调节速度变量使火车滚动速度变动; 3.模仿的图像反对倒退滚动,并在点击暂定后图像可通过鼠标拖拽能实现后退或后退成果。 4.反对上部、中部、下部图片独自增加等(间接设置图片列表) 5.反对上部、中部、下部一次性增加一列操作(每次增加) 6.反对清空已增加图片清空操作 7.反对模仿挪动速度的设置、获取、减速、加速、速度反向等操作 8.反对模仿火车播放器操作:播放、暂停、复原、进行等操作 9.反对左部区域百分比回调,区域宽度可设置百分比,回调优先级:底部 > 左部 > 右部 10.已高度性能显示优化,逻辑优化,较Qt+GPU更加晦涩播放(轨道交通行业内相干技术人员技术支持), 技术要求 1.视频图像播放晦涩、无卡顿、无丢帧景象。 2.视频图像播放速度调节适度安稳无丢帧卡顿。 3.视频图像导入图片数量横向不低于100张,导入过程无卡顿。 4.视频图像窗口缩放(小窗口、全屏切换)不影响图像播放晦涩度、无卡顿、丢帧。 Demo: Qt (录屏只有30fps,截取为gif后显示卡顿,可下载打包的四个版本进行终端测试). 下载体验地址 CSDN(粉丝免积分下载):https://download.csdn.net/download/qq21497936/15837003 QQ群:1047134658(点击“文件”搜寻“train”,群内与博文同步更新) Demo C ; C#接口源代码 若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/114866533

March 16, 2021 · 1 min · jiezi

关于c++:C防止头文件被重复引入的3种方法

在之前咱们具体介绍了 C 语言中如何应用宏定义(#ifndef / #define / #endif)来无效防止头文件被反复 #include,此形式在 C++ 多文件编程中也很罕用。 举个例子,如下是一个 C++ 我的项目,其外部含有 school.h 和 student.h 这 2 个头文件以及 main.cpp 源文件,其各自蕴含的代码为: //student.hclass Student { //......};//school.h#include "student.h"class School { //......private: Student stu[50];};//main.cpp#include "student.h"#include "school.h"int main() { //...... return 0;}运行此我的项目会发现,编译器报“Student 类型重定义”谬误。这是因为在 school.h 文件中曾经 #include 了一次 "student.h",而在 main.cpp 主程序又同时 #include 了 "school.h" 和 "student.h",即 Student 类的定义被引入了 2 次,C++不容许同一个类被反复定义。 有小伙伴可能想到,既然 School.h 文件中曾经引入了 Student 类,那去掉 main.cpp 主程序引入的 student.h 文件不就能够了吗?这样的确能够防止反复引入 Student 类,但此形式并不适用于所有“反复引入”的场景。 C++ 多文件编程中,解决“屡次 #include 导致反复引入”问题的形式有以下 3 种。 ...

March 16, 2021 · 2 min · jiezi

关于c:用C程序打印空心星形右直角三角形

解题思路用10*10网格 第1行打印9个空格1个星 第2行打印8个空格 第3行打印7个空格 以此类推 从第1行开始列如果(j==1||j==i)则打印星,否则打印空格,最初一行打印10个星 /*打印如下: * ** * * * * * * * * * * * * * *********** */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 1; j <= 10 - i; j++) { printf(" "); } for (j = 1; j <= i; j++) { if (j == 1 || j == i) { printf("*"); } else if (i == 10) { printf("*"); } else { printf(" "); } } printf("\n"); } return 0;}

March 16, 2021 · 1 min · jiezi

关于c:用C程序打印空心星形左直角三角形

## 解题思路用10*10网格 行号从1开始计算 每行列号等于1或者列号等于行号打印1个星,最初一行打印10个星,否则打印空格 /*打印如下:**** ** ** ** ** ** ** *********** */#include <stdio.h>int main(){ int i; int j; for (i = 1; i <= 10; i++) { for (j = 1; j <= i; j++) { if (j == 1 || j == i) { printf("*"); } else if (i == 10) { printf("*"); } else { printf(" "); } } printf("\n"); } return 0;}

March 15, 2021 · 1 min · jiezi

关于c++:WonderTrader架构详解之一整体架构

前言 时至今日,WonderTrader曾经受到不少敌人的关注,笔者也感到十分荣幸。这样的关注从某种角度来说,也是对笔者的认可,哪怕是批评的声音,也是对笔者的鞭策。之前有一些敌人在研读WonderTrader代码的时候,遇到了一些问题,最次要的就是不分明整个平台的架构设计,很多细节上了解不透。所以这些敌人曾经三番五次跟笔者说,心愿笔者写个文章整体介绍一下平台的架构设计。 其实笔者一开始不是很想写这样的文章。毕竟笔者自问还是下了很多功夫在代码里的,还是心愿识货的人多读读源码,而不是看一下架构文章就对WonderTrader缄口结舌地指点江山。起初天人交战了一段时间,笔者恍然大悟:既然开源了,何必悭吝多写几篇文章,授人以鱼不如授人以渔。于是乎,就有了这个《WonderTrader架构详解》的系列文章。 本文是该系列文章的第一篇,次要介绍WonderTrader的整体架构和策略实盘环境下的个别流程。 外围设计准则 笔者之前有一篇文章,大抵介绍了一下WonderTrader的演变过程。而WonderTrader通过这么屡次的迭代和重构,有一套外围的设计准则贯通始终,这也是WonderTrader经验屡次迭代和重构,最终走向成熟而不是土崩瓦解的外围起因。 1、组件化准则 在软件工程中,解耦是零碎设计的必修课程。耦合太重,各个模块之间的相互依赖太多,会导致代码逻辑简单难解,从而升高代码的可维护性。所以咱们在设计简单零碎的时候,肯定要思考如何正当的解耦。合了解耦当前,失去的就是一个组件化的零碎。 零碎组件化,有很多益处: 便于团队合作,不同组件的开发能够同步进行,晋升开发效率组件开发更灵便,只有合乎组件接口的范式,开发环境能够灵便应用组件扩大更便捷,对接新的第三方时只须要增量更新,不影响其余组件 然而零碎组件化,也有一些前提: 各组件之间通过接口进行拜访,没有额定的依赖。所以接口设计的好坏,间接关系到组件化的成功率和成果。组件化,须要在接口层面进行形象。而形象,则难以避免带来性能损失,如果在对性能有极致谋求的场景下,组件化肯定要审慎。对于同一个接口,接口层的形象,会将合乎该接口的不同组件的差异化的点暗藏起来。如果零碎肯定要用到这些差异化的局部,可能会导致接口设计的复杂化。 WonderTrader采纳的组件化设计,将独立的功能模块全副封装到独立的组件中,用接口连接起来。比拟典型的是不同的行情接入模块(Parsers)和不同的交易通道模块(Traders),因为每个模块都要对接各自对应的第三方API,所以采纳组件化设计,能无效的将各自不同的逻辑隔离开,让零碎只须要关注接口传递的数据即可。此外,执行单元(ExecuteUnit)、风控模块(RiskMonitor)、数据落地模块(DataWriter)和数据读入模块(DataReader)等,都遵循组件化设计的准则。 2、策略最简化准则 策略最简化准则,从某种角度来说,是一个哲学问题。之所以这么说,是源自于笔者和一位用户的探讨,探讨次要围绕策略的信号接口是怎么实现的来开展的。大抵的观点就是这位敌人感觉策略须要确定以后信号到底是要开多、开空、平多或者平空,而笔者却认为策略只须要设置指标部位即可,不须要关注到底是要怎么下达交易指令。 在上一次重构WonderTrader的时候,笔者花了很长时间来思考一些问题,诸如: 策略关注的最外围的点是什么?策略是不是肯定要晓得开平多空?策略是不是肯定要晓得不同的接口回调过去的数据结构?策略是不是肯定要自行治理订单?…… 在经验了重复的思考当前,笔者没有得出任何答案。然而笔者也不是一个拖沓的人,既然没有答案,那么笔者就决定从减法做起。 策略只须要关注信号逻辑,不须要关注如何执行,所有都丢给底层策略不须要晓得开平多空,只须要通知交易引擎本人的指标部位是什么,所有都丢给底层策略不须要和任何接口打交道,只和数据打交道,其余的所有都丢给底层策略不须要治理订单,所有都丢给底层…… 减法做完当前,笔者也不再纠结这个问题,正如后面提到的,这是一个哲学问题,而大多数哲学问题,都没有答案。然而笔者置信这样的减法,对于每个策略研发人员来说,都是十分敌对的。底层会帮忙策略把策略逻辑以外的任何事件都搞定,从数据管理到订单执行,包含多空开平,甚至平今对锁等等,底层都会全副搞定。 3、策略一致性准则 策略的一致性准则,蕴含多个方面: 策略代码的一致性,即回测和实盘用同样的代码策略回测和实盘信号的一致性,即实盘中触发的信号,在应用历史数据回测时该当是统一的同一套策略,不同的交易通道中收回的交易指令,该当是统一的 策略代码的一致性比拟好了解,也比拟好实现,只有保障回测框架和实盘框架向策略提供的API是统一的,就能够保障策略能够无缝在回测环境和实盘环境之间切换。 策略信号的一致性,其实是对平台数据处理的一致性的要求。只有实盘中实时处理的数据和历史数据完全一致,能力保障历史回测和实盘信号的一致性。因为实盘环境中,数据的达到有先后,如果解决数据保障策略响应的一致性,的确是比拟考验功夫的。笔者在WonderTrader中花了很多精力,来设计一种机制,能够尽可能的保障实盘数据的解决和历史回测数据的一致性,从而保障策略在实盘和回测中信号的一致性。 对于不同的交易通道中,信号和指令的一致性,这个就是WonderTrader的外围机制之一,即1+N的执行架构。1+N的执行架构,能够保障一个策略组合的信号在不同的交易通道中都可能统一,从而使得不同的交易通道的策略绩效相差无几。对于1+N执行架构的具体介绍,笔者会在后续的文章中做具体的论述,这里临时就不开展了。 外围架构介绍 后面提到的设计准则,绝对比拟形象。上面笔者将联合示意图,别离介绍WonderTrader的回测框架、实盘框架以及策略在实盘中的根本流程。读者能够从上面的架构设计中和后面提到的设计准则相互参考,应该能够失去一些印证。 1、回测框架 上图是WonderTrader回测框架的架构图。从上图咱们能够看进去,回测框架还是比拟简洁的。整个回测框架的外围在于4个仿真器和一个历史数据回放器。而4个仿真器,别离对应3种不同类型的策略,以及执行单元。 而策略局部,除了C++策略能够间接和回测引擎交互以外,多语言策略(当初只实现了python)则须要通过C接口的粘合层跟回测引擎进行交互,同时还须要提供一个多语言子框架提供多语言环境下的API和底层交互接口(python下为wtpy)。 执行单元,是实盘中执行器的外围逻辑模块,用于执行交易指令和治理订单的。因为执行单元只能C++开发,所以不再提供C接口粘合层。Exec仿真器,则通过定时设置指标仓位,触发执行单元的外围逻辑,并对执行单元收回的交易指令进行模仿撮合,从而达到回测执行单元,剖析执行逻辑的体现的目标。 历史数据回放器,通过从数据引擎加载历史数据,并依据历史数据按数据周期进行回放,触发策略的重算,从而驱动策略逻辑,并在仿真器Mocker中进行仿真撮合,进而达到回测的目标。从上图能够看出,历史数据回放器,能够从WT数据文件系统、CSV文件以及数据库(目前只对接了Mysql)加载历史数据。 2、实盘框架 WonderTrader实盘框架相比回测框架就要简单很多。除了策略实现和回测框架是统一的(前文提到的策略一致性准则),底层外围为了对接实盘中不同的功能模块,所以就有了很大的不同。 策略引擎,也是一个策略组合,接管到数据组件播送的实时数据当前,触发策略重算,从而生成信号,并经由策略引擎轧平汇总当前,丢给执行器执行,而执行器调用不同的执行单元的执行逻辑当前,最终通过Trades交易通道模块,向交易柜台下达交易指令,从而实现一轮信号的生产执行的循环。目前策略引擎针对不同类型的策略实现上有一些区别,所以分成了3种策略引擎。 须要留神的是,数据组件其实是作为一个独立的伺服在运行的。目标也比拟明确,就是要实现读写拆散,并且能够同时向多个组合盘实例提供数据服务。数据组件通过调用DataWriter模块接口进行数据的落地,数据存储反对WT文件系统以及数据库两种模式。而策略则通过策略引擎调用数据管理器,通过DataReader从数据存储中读取文件到内存中,失去数据管理器中返回的数据切片。 还有一个绝对独立的模块,就是风控模块RiskMonitor。风控模块次要针对组合盘(策略引擎)的虚构资金进行风控,目前内置的风控模块反对的指标次要包含最大日内回撤、最大多日回撤等危险指标进行管制。 3、策略根本流程 上图是WonderTrader中CTA策略在实盘环境中的根本流程。 首先Parser从行情源接入行情数据,并解析成WonderTrader本人的tick数据tick数据先传递给CTATicker(数据同步器)进行工夫戳的同步控制每一笔tick,都会触发策略的on_tick回调当tick数据的工夫戳确定了上一个分钟的完结,就会判断是否有K线刚好闭合如果K线曾经闭合,则触发策略的on_bar回调如果策略订阅的全副K线都闭合了,则触发策略的on_schedule回调进行重算策略重算过程中,调整了指标仓位,最终汇总到策略引擎中进行汇总解决头寸汇总当前,分发给各个执行器进行执行执行器调用底层执行单元的逻辑收回下单指令最初下单指令通过交易通道Traders最终下达交易柜台 WonderTrader一共有三种不同的策略引擎,以用于不同利用场景的策略。除了HFT策略,策略间接对接交易通道Trader以外,另外两种策略的根本流程都和下面介绍的CTA根本流程是统一的。 结束语 因为篇幅无限,本文的介绍就到此结束了。置信通过本文的介绍,各位读者对于WonderTrader的整体架构曾经有了一个初步的认知了。如果有读者违心更进一步的理解WonderTrader,心愿这篇文章能够帮忙到各位。下一周,笔者将围绕数据处理,来介绍WonderTrader的数据处理机制,望各位读者届时多多捧场。 WonderTrader旨在给各位量化从业人员提供更好的轮子,将技术相干的货色都封装在平台中,力求给策略研发带来更好的策略开发体验。 最初再安利一下WonderTrader WonderTrader的github地址:https://github.com/wondertrad... WonderTrader官网地址:https://wondertrader.github.io wtpy的github地址:https://github.com/wondertrad... 市场有危险,投资需谨慎。以上陈说仅作为对于历史事件的回顾,不代表对将来的观点,同时不作为任何投资倡议。

March 15, 2021 · 1 min · jiezi

关于.net:进击吧Blazor系列入门教程-第一章-7图表

《进击吧!Blazor!》是自己与张善友老师单干的Blazor零根底入门教程视频,此教程能让一个从未接触过Blazor的程序员把握开发Blazor利用的能力。视频地址:https://space.bilibili.com/48...Blazor WebAssembly 是单页利用 (SPA) 框架,用于应用 .NET 生成交互式客户端 Web 利用,采纳 C# 代替 JavaScript 来编写前端代码 本系列文章因篇幅无限,省略了局部代码,残缺示例代码:https://github.com/TimChen44/...作者:陈超超Ant Design Blazor 我的项目贡献者,领有十多年从业教训,长期基于.Net技术栈进行架构与开发产品的工作,现就职于正泰团体。邮箱:timchen@live.com欢送各位读者有任何问题分割我,咱们共同进步。图表的作用我就不扯了,想要让零碎高大上就少不了它,作为一个加分项,咱们天然也要给咱们ToDo援用来一波。 Chart控件抉择目前还没有比拟优良的Blazor原生Chart控件,这也是咱们未来须要晋升Blazor生态的重要工作之一。 然而无需悲观,Blazor反对C#调用JS,反之亦可,所以社区中有不少通过此技术对现有JS版本的Chart控件二次分装的Blazor组件可用。 这里我就举荐自己封装G2Plot后的Blazor组件ant-design-charts-blazor。 文档地址:https://ant-design-blazor.git...源码地址:https://github.com/ant-design...技术实现形式介绍:https://zhuanlan.zhihu.com/p/...https://www.bilibili.com/vide... 革新ToDo援用组件通过命令或可视化界面为ToDo.Client增加AntDesign.Charts组件$ dotnet add package AntDesign.Charts 在 wwwroot/index.html(WebAssembly) 或 Pages/_Host.razor(Server) 中引入动态文件:<script src="https://unpkg.com/@antv/g2plot@latest/dist/g2plot.js"></script><script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>在 _Imports.razor 中退出命名空间@using AntDesign.Charts将Charts命名空间退出全局援用,领有应用时省略残缺命名门路的益处,然而请留神当Chart中的组件与其余组件重名时,不管Chart组件还是其余组件都须要补上残缺命名门路,思考到Chart应用的页面并不多,所以自己的习惯不会将他退出 _Imports.razor中。统计页咱们用柱状图做一个每日代办事项数量统计图 ChartAmountDto.cs在ToDo.Shared我的项目中创立用于显示数据的实体。 public class ChartAmountDto{ public string Day { get; set; } public string Type { get; set; } public int Value { get; set; }}Day字段存储日期文本。Type存储重要度信息,蕴含“一般”,“重要”两个值,图表中也是用这个进行分组显示。Value存储具体的数值。 ChartController.cs在ToDo.Server我的项目新建ChartController控制器,用于提供图表所需的数据。 [ApiController][Route("api/[controller]/[action]")]public class ChartController{ TodoContext Context; public ChartController(TodoContext context) { Context = context; } //每日待办数量 public List<ChartAmountDto> GetAmountDto() { return Context.Task.GroupBy(x => new { x.PlanTime, x.IsImportant }).Select(x => new ChartAmountDto() { Day = x.Key.PlanTime.ToString("yy-MM-dd"), Type = x.Key.IsImportant ? "一般" : "重要", Value = x.Count(), }).ToList(); }}通过对打算日期和重要度进行分组,而后对分组后果进行计数,接口返回的局部数据结构如下 ...

March 14, 2021 · 2 min · jiezi