C++新经典10--vector以及其使用
vector
vector类型是一个标准库中的类型,代表一个容器、集合或者动态数组这样一种概念。既然是容器,那就可以把若干个对象放到里面。当然,这些对象的类型必须相同。简单来说,可以把一堆int型数字放到vector容器中去,复杂点说,可以把一堆相同类型的类对象放到vector容器中去。
所以,如果换个角度考虑,vector能把其他对象装进来,所以称为容器
非常合适。容器这个概念经常被提及,读者要知道和理解这个概念。
要想使用这种类型,需要在.cpp源文件开头包含vector头文件:
另外,为了方便引用这种类型,也要书写:
定义一个vector类型对象。显然,一旦定义出来,这个对象就是容器了。例如想在里面保存int型数据(容器里面所要装的元素类型),看如下代码:
上面的代码定义了一个vector类型的对象,名字叫作vjihe,这个对象里面保存的就是int型数据。为什么是int型数据呢?读者可以看到,vector后面有一对“<>”,“<>”里面是int,表示这个vector类型的对象(容器)里面存放的是int型对象(int型数据/元素)。
这个<int>的写法读者可能第一次见到,会觉得是一种奇怪的写法,在后面章节中会讲到“类模板”的概念,其实vector就是一个类模板
,这里的“<>”实际上是类模板的一个实例化过程。但是类模板的实例化过程眼下对于读者来讲,理解起来还比较生涩,后面学习模板的时候再详细阐述,所以这里笔者换一种说法来帮助读者理解类模板。
vector理解成一个残缺的类类型,这意味着使用时光有类名vector还不够,还需要额外给vector类模板提供其要在其中保存什么类型数据的信息,这个信息就是通过<int>来提供(模板名后跟一对“<>”,“<>”内放入类型信息),所以,在使用vector时,一定要在它后面跟一对“<>”并在其中跟一个该vector容器中要保存的数据(元素)类型的信息,这才算一个完整的类型(完整的类类型)。例如,vector不是一个完整类型,而vector<int>却是一个完整的类型。看看如下范例:
一般来讲,vector容器里面可以装很多种不同类型的数据作为其元素(容器中装的内容简称“元素”)。看看如下范例:
但是vector不能用来装引用。请记住,引用只是一个别名,不是一个对象。所以,下面的写法会报语法错误:
定义和初始化vector对象
(1)空vector。
定义如下:
vector<string> mystr;
//创建一个string类型的空vector对象(容器),
//现在mystr里不包含任何元素
后续就可以用相关的一些操作函数往这个空对象里增加数据了。
例如,可以往这个容器的末尾增加一些数据。这里可以使用vector的成员函数push_back往容器末尾增加数据。看看如下范例,注意看它的下标[0],[1],[2],…不断增长,如图13.3所示。
mystr.push_back("abcd");
mystr.push_back("def");
(2)在vector对象元素类型相同的情况下,进行vector对象元素复制(新副本)。
vector<string> mystr2(mystr); //把mystr元素复制给了mystr2
vector<string>mystr3 = mystr; //把mystr元素复制给了mystr3
(3)在C++11中,还可以用初始化列表方法给初值,这个时候用“{}”括起来。
vector<string> def = {"aaa","bbb","ccc"};
当然“{}”里面为空也可以,那就相当于没有初始化,是一个空的vector了。
(4)创建指定数量的元素。请注意,有元素数量概念的初始化,用的都是“()”。
如果不给元素初值,那么元素的初值要根据元素类型而定,例如元素类型为int,系统给的初值就是0,元素类型为string,系统给的初值就是"",但也存在有些类型,必须给初值,否则就会报错。
如下范例演示不给元素初值的情况:
vector<int> ijihe2(20); //20个元素,下标[0]~[19],每一个元素值都为0
vector<string> sjihe2(5); //15个元素,下标[0]~[4],每一个元素值都为""
(5)多种初始化。“()”一般表示对象中元素数量这种概念
,“{}”一般表示元素的内容这种概念,但又不是绝对。看看如下范例:
vector对象上的操作
其实,在使用vector时,最常见的情况是并不知道vector里会有多少个元素,使用时会根据需要动态地增加和减少。所以一般来讲,使用者是先创建一个空的vector对象,然后通过代码向这个vector里增加或减少元素。这里将要介绍一些vector类型提供的常用方法。vector上很多的操作和string很相似。
(1)判断是否为空empty(),返回布尔值。
vector<int> ivec;if (ivec.empty()) //条件成立{ cout<<"ivec为空"<<endl;}
(2)push_back:一个非常常用的方法,用于向vector末尾增加一个元素。
vector<int> ivec; //先声明成空的vector对象ivec.push_back(1);ivec.push_back(2);for (int i=3;i<=100;i++){ivec.push_back(i);}
在上面的范例中,注意观察,能够发现,值2在值1的后面(最后插入的元素在vector容器的最末尾)。调试结果如下图所示。
(3)size:返回元素个数。
(4)clear:移除所有元素,将容器清空。
(5)v[n]:返回v中的第n个字符(n是一个整型值),位置从0开始计算,位置值n也必须小于.size(),如果下标引用超过这个范围,或者用下标访问一个空的vector,都会产生不可预测的结果(因为编译器可能发现不了这种错误)
(6)赋值运算符(=)。
vector<int> ivec;//先声明成空的vector对象ivec.push_back(1);ivec.push_back(2);for (int i=3;i<=100;i++){ivec.push_back(i);}vector<int> ivec2;ivec2.push_back(111);ivec2=ivec;//也得到了100个元素,用ivec中的内容取代了ivec2中原有内容,上行这个111就//被冲掉了ivec2={12,13,14,15};//用{}中的值取代了ivec2原有值cout<<ivec2.size()<<endl; //4
(7)相等和不等(==和!=)。
两个vector对象相等:元素数量相同,对应位置的元素值也都相同。否则就是不相等。
(8)范围for的应用:和讲解string时对范围for的应用类似
vector<int> vecvalue{1,2,3,4,5 };for(auto& vecitem:vecvalue) //为了修改vecvalue内部值,这里是引用,引用会绑定到元素上,达//到通过引用改变元素值的目的vecitem *= 2; //扩大一倍for (auto vecitem : vecvalue)cout << vecitem << endl;
针对范围for语句,这里希望引申一步进行讲解。如果在范围for中,增加改变vector容量的代码,则输出就会变得混乱:
vector<int> vecvalue{1,2,3,4,5 };for (auto vecitem : vecvalue){vecvalue.push_back(888);cout << vecitem << endl;}
范围for,在这里用来遍历vector容器中的元素。这里的vecitem是定义的一个变量,后面的vecvalue是一个序列(容器),for语句中使用auto
来确保序列中的每个元素都能够转换成变量vecitem对应的类型,所以一般在范围for语句中习惯使用auto(编译器来指定合适的vecitem类型)。
那为什么上述代码会产生混乱的输出呢?
因为每次执行for循环,都会重新定义vecitem,并且把它的值初始化成vecvalue序列中的下一个值。在刚刚进入这个for循环时,在系统内部会记录序列结束的位置值,但一旦在这个范围for里面改动这个序列的容量(如增加/删除元素),那么这个序列结束的位置值就肯定会发生改变,这个改变会导致for语句的混乱,其输出的值也就乱了。
所以,请记住一个结论,在for语句中,不要改变vector的容量,增加、删除元素都不可以
。请读者千万千万不要写出这种错误代码,否则隐患无穷,切记切记!
迭代器精彩演绎、失效分析及弥补、实战
迭代器简介
迭代器是一个经常听到和用到的概念。上一节学习了vector,笔者说过,这是一个容器,里面可以容纳很多对象。那迭代器是什么呢?迭代器是一种遍历容器内元素的数据类型。这种数据类型感觉有点像指针,读者就理解为迭代器是用来指向容器中的某个元素的。
string可以通过“[]”(下标)访问string字符串中的字符,vector可以通过“[]”访问vector中的元素。但实际上,在C++中,很少通过下标来访问它们,一般都是采用迭代器来访问。
除了vector容器外,C++标准库中还有几个其他种类的容器。这些容器都可以使用迭代器来遍历其中的元素内容。string其实是字符串,不属于容器,但string也支持用迭代器遍历。
通过迭代器,可以读取容器中的元素值、修改容器中某个迭代器所代表(所指向)的元素值。此外,迭代器可以像指针一样——通过++、–等运算符从容器中的一个元素移动到另一个元素。
许多容器如上述的vector,在C++标准库中,还有其他容器如list、map
等都属于比较常用的容器,C++标准库为每个这些容器都定义了对应的一种迭代器类型,有很多容器不支持“[]”操作,但容器都支持迭代器操作。写C++程序时,笔者也强烈建议读者不要用下标访问容器中的元素,而是用迭代器来访问容器中的元素。
容器的迭代器类型
刚刚讲过,C++标准库为每种容器都定义了对应的迭代器类型。这里就以容器vector为例,演示一下:
vector<int> iv = {100,200,300}; //定义一个容器vector<int >:: iterator iter; //定义迭代器,也必须是以vector<int>开头
上面的语句是什么意思呢?后面这条语句定义了一个名为iter的变量(迭代器),这个变量的类型是vector<int>::iterator类型,请注意这种写法“::iterator”。iterator是什么?它是每个容器(如vector)里面都定义了的一个成员(类型名)
,这个名字是固定的,请牢记。
在理解的时候,就把整个vector<int>::iterator理解成一种类型,这种类型就专门应用于迭代器,当用这个类型定义一个变量的时候,这个变量就是一个迭代器。
迭代器begin/end、反向迭代器rbegin/rend操作
1.迭代器
每一种容器,如vector,都定义了一个叫begin的成员函数和一个叫end的成员函数。这两个成员函数正好用来返回迭代器类型。看看如下范例。
(1)begin返回一个迭代器类型(就理解成返回一个迭代器)。
(2)end返回一个迭代器类型(就理解成返回一个迭代器)。
对上面的代码进行跟踪调试,观察begin和end结果可以看到,end()指向了一个乱数字,如图13.5所示。
vector<int> iv = {100,200,300}; //定义一个容器vector<int >::iterator iter; //定义迭代器,也必须是以vector<int>开头iter = iv.begin();iter = iv.end();
(3)如果容器为空,则begin返回的迭代器和end返回的迭代器相同。看看如下范例:
vector<int> iv2;vector<int>::iterator iterbegin = iv2.begin();vector<int>::iterator iterend = iv2.end();if (iterbegin == iterend) //条件成立{cout << "容器为空" << endl;}
所以,end返回的迭代器并不指向容器vector中的任何元素,它起到实际上是一个标志(岗哨)作用,如果迭代器从容器的begin位置开始不断往后游走,也就是不断遍历容器中的元素,那么如果有一个时刻,iter走到了end位置,那就表示已经遍历完了容器中的所有元素。
(4)写一段代码,传统的通过迭代器访问容器中元素的方法如下:
vector<int>iv={100,200,300}; //定义一个容器//经典传统用法,这里用++、!=等运算符来对迭代器进行操作for (vector<int>::iterator iter = iv.begin();iter != iv.end();iter++){cout << *iter << endl;}
运行起来看结果:100、200、300。
2.反向迭代器
如果想从后面往前遍历一个容器,那么,用反向迭代器就比较方便。反向迭代器使用的是rbegin成员函数和rend成员函数。
(1)rbegin返回一个反向迭代器类型,指向容器的最后一个元素。
(2)rend返回一个反向迭代器类型,指向容器的第一个元素的前面位置。
rbegin和rend成员函数指向的容器位置示意图如图13.7所示。
看看如下范例:
vector<int>iv={100,200,300};for (vector<int>::reverse_iterator riter = iv.rbegin(); riter != iv.rend(); riter++){cout<<*riter<<endl;}
运行起来看结果:300、200、100。
迭代器运算符
(1)iter:返回迭代器iter所指向元素的引用。必须要保证该迭代器指向的是有效的容器元素,不能指向end,因为end是末端元素后面的位置,也就是说,end已经指向了一个不存在元素。前面的cout≪iter≪endl;就是使用*iter的演示范例,这里不做进一步演示了。
(2)++iter:和iter++是同样的功能——让迭代器指向容器中的下一个元素。但是已经指向end的迭代器,不能再++,否则运行时报错。
(3)–iter:和iter–是同样的功能——让迭代器指向容器中的前一个元素。了解++自然也就能了解–。看看如下范例:
(4)iter1==iter2或iter1!=iter2:判断两个迭代器是否相等。如果两个迭代器指向的是同一个元素,就相等,否则就不相等。
(5)结构成员的引用。看看如下范例:
请注意,一定要确保迭代器指向有效的容器中的元素,否则范例中的这些行为可能会导致意想不到的结果。还有很多其他运算符,例如迭代器之间可以相减表示两个迭代器之间的距离,迭代器加一个数字表示跳过多少个元素,不过这些都不常用,不准备逐一介绍,意义也不大。读者如果以后遇到,有了现在所学的基础,再简单学习一下即可。
const_iterator迭代器
前面学习了iterator这种迭代器类型,实际上每种容器还有另外一种迭代器类型,叫作const_iterator,从名字上能感觉到其含义:有const在,一般都表示常量,也就是说值不能改变的意思。这里的值不能改变表示该迭代器指向的元素的值不能改变,并不表示该迭代器本身不能改变,该迭代器本身是能改变的,也就是说,该迭代器是可以不断地指向容器中的下一个元素的。
所以该迭代器只能从容器中读元素,不能通过该迭代器修改容器中的元素。所以说,从感觉上来讲,const_iterator更像一个常量指针,而iterator迭代器是能读能写的。看看如下范例:
什么时候用const_iterator呢?如果这个容器对象是一个常量,那么就必须使用const_iterator,否则报错:
这里再额外看一看cbegin和cend成员函数。这是C++11引入的两个新函数,与begin、end非常类似。但是,不管容器是否是常量容器,cbegin、cend返回的都是常量迭代器const_iterator。看看如下范例:
迭代器失效
上一节在讲vector容器时谈过范围for循环语句——在遍历容器的时候,如果在for循环中,通过push_back等手段往容器中增加元素,范围for循环输出的容器中元素就会混乱。其实,范围for语句等价于常规的用迭代器对容器进行操作
。看如下代码:
vector<int> vecvalue{1,2,3,4,5 };for (auto vecitem:vecvalue){cout << vecitem <<endl;}
等价于迭代器这种操作方式:
但如果一旦在for循环中增删容器中的元素,就会导致迭代器失效,整个结果就混乱了。
其实,任何一种能够改变vector对象容量的操作,如push_back,都会使当前的vector对象迭代器失效,所以请读者谨记:在操作迭代器的过程中(使用了迭代器的这种循环体),千万不要改变vector对象的容量,也就是不要增加或者删除vector容器中的元素。看如下代码:
对于向容器中添加元素和从容器中删除元素操作要小心,因为这些操作可能都会使指向容器元素的迭代器(也包括指针、引用等)失效。这种失效就表示它不能再代表任何容器中的元素,一旦使用这种失效的迭代器,就表示程序的书写犯了严重错误,很多情况下都会导致程序崩溃,就好比使用了没有被初始化的指针一样。
不同的容器实现机理不同(例如有的容器内部数据是连续存储的,插入元素时一旦原有内存不够用,则可能就会导致容器中原有数据全部迁移到一个新内存去,如vector等容器),不同的插入操作、不同的插入位置,会导致迭代器、指针、引用部分或者全部失效,甚至在循环体中的诸如vecvalue.end()代码都会因为插入数据操作导致失效。
另一种情况是删除操作。如果从容器中删除一个元素,那么,当前指向这个被删除元素的迭代器、指针、引用肯定是立即失效,绝不能再引用它们。
此外,不同的容器,针对删除操作,不同的删除位置,也会导致迭代器、指针、引用部分或者全部失效,甚至在循环体中的诸如vecvalue.end()代码都会因为删除数据操作导致失效。
解决方法就是:如果在一个使用了迭代器的循环中插入元素到容器,那只插入一个元素后就应该立刻跳出循环体,不能再继续用这些迭代器操作容器。看看如下范例:
下面将进行一些灾难程序演示。
(1)灾难程序演示1
下面代码目前一切没有问题:
接着,往循环中增加代码,注意while循环体中代码的变化:
有些人可能有更多需求,例如就是想不断地插入多条数据,并且还希望迭代器不失效,那就得查资料研究,如研究针对vector容器,如何写insert这段代码,才能让迭代器不失效,让程序安全地运行。看如下代码,是一种满足连续插入多条数据的解决方案:
相关文章:
C++新经典10--vector以及其使用
vector vector类型是一个标准库中的类型,代表一个容器、集合或者动态数组这样一种概念。既然是容器,那就可以把若干个对象放到里面。当然,这些对象的类型必须相同。简单来说,可以把一堆int型数字放到vector容器中去,复…...
std : : vector
一.简介 std::vector 的底层实现通常基于动态数组(dynamic array),它是一种连续分配的内存块,允许元素的快速随机访问。下面是 std::vector 的一些关键特点和底层实现细节: 连续内存块:std::vector 内部使…...
AJAX学习笔记8 跨域问题及解决方案
AJAX学习笔记7 AJAX实现省市联动_biubiubiu0706的博客-CSDN博客 跨域:指一个域名的网页去请求另外一个域名资源.比如百度页面去请求京东页面资源. 同源与不同源三要素:协议,域名,端口 协议一致,域名一致,端口一致.才算是同源.其他一律不同源 新建项目测试: 1.window.open();…...
webhook--详解(gitee 推送)
一、简介 webhook 是一种基于 HTTP 的回调函数,可在 2 个应用编程接口(API)之间实现轻量级的事件驱动通信。是一种新型的前后端交互方式,一种对客户端-服务器模式的逆转,在传统方法中,客户端从服务器请求数…...
高速路自动驾驶功能HWP功能定义
一、功能定义 高速路自动驾驶功能HWP是指在一般畅通高速公路或城市快速路上驾驶员可以放开双手双脚,同时注意力可在较长时间内从驾驶环境中转移,做一些诸如看手机、接电话、看风景等活动,该系统最低工作速度为60kph。 如上两种不同环境和速度…...
Leetcode113. 路径总和 II
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 官方题解:力扣(LeetCode)官网 - 全…...
分布式锁之redis实现
docker安装redis 拉取镜像 docker pull redis:6.2.6 查看镜像 启动容器并挂载目录 需要挂在的data和redis.conf自行创建即可 docker run --restart always -d -v /usr/local/docker/redis/redis.conf:/usr/local/etc/redis/redis.conf -v /usr/local/docker/redis/data:/dat…...
Idea中如何在一个项目中引入其他子模块?
首先在Settings打开Project Structure,然后找到Modules,点击加号点击import module,将需要引进的module引进来。 然后点击Artifacts 可以看到比如说day22…这个是我现在的项目,day16是我需要引入的。那么就在红色横线上面右键点第…...
UDP协议概述
传输层里比较重要的两个协议,一个是 TCP,一个是 UDP。TCP 是面向连接的,UDP 是面向无连接的。 所谓的建立连接,是为了在客户端和服务端维护连接,而建立一定的数据结构来维护双方交互的状态,用这样的数据结…...
Python-tracemalloc-跟踪内存分配
tracemalloc 模块是一个用于对 python 已申请的内存块进行debug的工具。它能提供以下信息: 定位对象分配内存的位置 按文件、按行统计python的内存块分配情况: 总大小、块的数量以及块平均大小。 对比两个内存快照的差异,以便排查内存泄漏 显示前10项 显示内存…...
02 CSS技巧
02 CSS技巧 clip-path 自定义形状,或者使用自带的属性画圆等circle HTML结构 <body><div class"container"></div> </body>CSS结构 使用*polygon*自定义形状 .container {width: 300px;height: 300px;background-color: re…...
Yarn资源调度器
文章目录 一、Yarn资源调度器1、架构2、Yarn工作机制3、HDFS、YARN、MR关系4、作业提交之HDFS&MapReduce 二、Yarn调度器和调度算法1、先进先出调度器(FIFO)2、容量调度器(Capacity Scheduler)3、公平调度器(Fair …...
android上架备案公钥和md5获取工具
最近很多公司上架遇到了一个问题,就是要提供app的备案证明,现在android上架都需要备案了,但是我们的证书都是通过工具生成的,哪里知道公钥和md5那些东西呢?无论安卓备案还是ios备案都需要提供公钥和md5。 包括ios的备案…...
SpringBoot系列(12):SpringBoot集成log4j2日志配置
最近项目上有使用到log4j2日志模板配置,本文简单总结一下之前的学习笔记,如有纰漏之处,请批评指正。 1. log4j2日志依赖 使用log4j2日志模板时,需要引入相关依赖,下边的两种依赖方式均可。 1.1 使用sl4j依赖时 <…...
HTML事件列表
鼠标事件 属性描述DOMonclick当用户点击某个对象时调用的事件句柄。2oncontextmenu在用户点击鼠标右键打开上下文菜单时触发ondblclick当用户双击某个对象时调用的事件句柄。2onmousedown鼠标按钮被按下。2onmouseenter当鼠标指针移动到元素上时触发。2onmouseleave当鼠标指针…...
并发-Executor框架笔记
Executor框架 jdk5开始,把工作单元与执行机制分离开来,工作单元包括Runable和Callable,执行机制由Executor框架来提供。 Executor框架简介 Executor框架的两级调度模型 Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本…...
【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)
前言: 本文是对于动态内存管理知识后续的补充,以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser~的博客-CSDN博客 本文涉及的知识内容主要在两方面: 简单解析C/C程序…...
深入理解 JVM 之——字节码指令与执行引擎
更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 类文件结构 Write Once,Run Anywhere 对于 C 语言从程序到运行需要经过编译的过程,只有经历了编译后,我们所编写的代码才能够翻译为机器可以直接运行的二进制代码&#x…...
C++:vector
目录 一、关于vector 二、vector的相关函数 三、相关函数的使用 ①构造函数 ②size ③[] 编辑 ④push_back ⑤迭代器iterator ⑥reserve ⑦resize ⑧find ⑨insert ⑩erase ⑪sort 一、关于vector vector比较像数组 观察可知,vector有两个模板参数…...
Android Automotive编译
系统准备 安装系统 准备一台安装Ubuntu系统的机器(windows系统的机器可以通过WSL安装ubuntu系统) 安装docker 本文使用docker进行编译,因此提前安装docker。参考网络链接安装docker并设置为不使用sudo进行docker操作。 参考链接ÿ…...
什么是50ETF期权开户条件,怎么开期权交易权限?
50ETF期权是指上证50ETF期权,标的物是上证50ETF,代码是(510500),期权是一种在上证50ETF基础上进行衍生品交易的金融工具,下文科普什么是50ETF期权开户条件,怎么开期权交易权限?本文来…...
React 从入门到精通——本文来自AI创作助手
React是一个流行的JavaScript库,用于构建用户界面。以下是React入门到精通的步骤: 入门 安装React 你可以在npm上下载React包,也可以使用其他包管理器。首先需要安装node.js,然后使用以下命令安装React: npm insta…...
【51单片机实验笔记】前篇(三) 模块功能封装汇总(持续更新)
文章目录 通用函数public.hpublic.c 延时函数delay.hdelay.c LED模块数码管模块smg.hsmg.c LED点阵模块独立按键模块矩阵按键模块外部中断模块定时器模块串口通讯模块ADC模块PWM模块 通用函数 包含常用头文件,宏定义,自定义类型,函数工具等。…...
Excel VSTO开发4 -其他事件
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 4 其他事件 针对插件的事件主要有Startup、Shutdown这两个事件,在第2节中已经讲解。在开发窗口中,选择对象…...
语音识别数据的采集方法:基本流程数据类型
“人工智能是一种模仿人类功能的产品。数据采集的方法需要针对特定的场景需求。”—–Mark Brayan (澳鹏CEO) 我们一直说,对于一个高质量的人工智能产品离不开高质量的训练数据。对于不同的人工智能我们需要不同的数据对其训练。要采集正确的数据去训练特定的模型才…...
oracle数据库给用户授权DBA权限Oracle查看哪些用户具有DBA权限
oracle数据库给用户授权DBA权限 步骤一:以sysdba身份登录到Oracle数据库 在授予DBA权限之前,我们首先要以sysdba身份登录到Oracle数据库。使用以下命令登录: sqlplus / as sysdba步骤二:创建用户(如有用户跳过&#…...
024-从零搭建微服务-系统服务(六)
写在最前 如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 源码地址(后端):https://gitee.com/csps/mingyue 源码地址(前端):https://gitee.com/csps…...
Arduino驱动TCS3200传感器(颜色传感器篇)
目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAOS TCS3200RGB感应芯片和4个白色LED灯,TCS3200能在一定的范围内检测和测量几乎所有的可见光。TCS3200有大量的光检测器,每个都有红绿蓝和清…...
基于Matlab实现多个数字水印案例(附上源码+数据集)
数字水印是一种在数字图像或视频中嵌入特定信息的技术,以保护知识产权和防止盗版。在本文中,我们将介绍如何使用Matlab实现数字水印。 文章目录 实现步骤源码数据集下载 实现步骤 首先,我们需要选择一个用于嵌入水印的图像。这可以是原始图像…...
C语言之指针进阶篇(2)
目录 函数指针 函数名和&函数名 函数指针的定义 函数指针的使用 函数指针陷阱 代码1 代码2 注意 函数指针数组定义 函数指针数组的使用 指向函数指针数组的指针 书写 终于军训圆满结束了,首先回顾一下指针进阶篇(1)主要是…...
网站建设需要精通什么知识/苏州seo服务
如何制作gif图?如何上传你项目的动态效果图到你的csdn? 这只是笔者用的方法,有其他方法的欢迎分享。 一张或几张展示了你的项目的功能及效果的动态图放在博客文章开头会为你的文章润色不少。 相信很多写博客的伙伴都会遇到这样一个问题&…...
wordpress自定义输入/搜索引擎优化的基本方法
web指纹识别的核心原理是通过正则表达式匹配特征码或匹配文件的md5值等特殊信息,进而识别web应用程序的名称和版本,收集信息,以备攻击...
做catia数据的网站/百度学术论文查重官网
一、canvas介绍 <canvas> 标签用于绘制图像(通过脚本,通常是 JavaScript),<canvas> 元素本身并没有绘制能力(它仅仅是图形的容器) - 必须使用脚本来完成实际的绘图任务。 不支持canvas的浏览器:ie8及以下 绘制环境:getcontext…...
如何注册个人网站/东莞网站优化
一.collections模块 Python拥有一些内置的数据类型,比如str, int, list, tuple, dict等, collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型: namedtuple(): 生成可以使用名字来访问元素内容的tuple子类deque:…...
甘肃省第九建设集团网站首页/志鸿优化设计答案
朋友门!等待终于结束了! 我们的社区在短短一周内已经发展到了超过10,000名Twitter粉丝,12,000名Discord成员,以及7,000名Telegram成员!为了感谢您的大力支持,我们将继续努力。为了感谢您的大力支持,我们很高…...
建站行业消失了吗/百度地图导航2022最新版
touch事件一直是Android学习者一个头疼的问题,为了更好的学习事件的传递,我们来探索一下 touch事件有如下几种: Activity中包括: dispatchTouchEvent onTouchEvent ViewGroup有: dispatchTouchEvent onTouchEvent onIn…...