C++学习-入门到精通-【5】类模板array和vector、异常捕获

C++学习-入门到精通-【5】类模板array和vector、异常捕获


类模板array和vector、异常捕获

  • C++学习-入门到精通-【5】类模板array和vector、异常捕获
  • 一、array对象
    • array对象的声明
    • 使用array对象的例子
    • 使用常量变量指定array对象的大小
  • 二、基于范围的for语句
  • 三、利用array对象存放成绩的GradeBook类
  • 四、array对象的排序与查找
    • 使用排序和查找的例子
  • 五、多维array对象
  • 六、利用二维array对象的GradeBook类
  • 七、C++标准库类模板vector的介绍
    • vector对象和array对象的主要区别


一、array对象

Array是C++标准库中的类模板。array对象是一组具有相同类型的、连续的内存空间。每个array对象都知道自己的大小,可以调用类的成员函数size来确定。例如一个array对象c,使用c.size()可以获得c的大小。

array对象的声明

使用如下的语法声明一个array对象:
array <类型, 大小> array对象名

// 声明一个元素类型为int的,大小为5的array对象
array <int, 5> arr;

尖括号对<>表明了array是一个类模板。编译器将根据元素的类型和array对象的大小来分配合适的内存空间(一个分配内存的声明,它的更合适的叫法应该是定义)。array对象的大小必须是一个无符号整型。

使用array对象的例子

#include <array>
#include <iostream>
#include <iomanip>using namespace std;int main()
{array<int, 5> arr1;static array<int, 10> arr;cout << setw(7) << "Element" << setw(13) << "Values" << endl;for (int i = 0; i < 5; i++){cout << setw(5) << "arr1[" << i << "]" << setw(13) << arr1[i] << endl;}cout << "\n";for (int i = 0; i < 10; i++){cout << setw(5) << "arr[" << i << "]" << setw(13) << arr[i] << endl;}
}

运行结果:
在这里插入图片描述

从结果中看,自动的array对象并不会隐式的初始化为0,静态的array对象会隐式的初始化为0。静态的array对象与静态的局部变量一样,只会在函数第一次调用时进行初始化,之后直到程序结束才会销毁。

使用初始化列表初始化array对象

在array对象的声明中,也可以对其元素进行初始化。具体做法是:在array对象名称的后面加一个等号和一个用逗号分隔的初始化列表,该列表用花括号括起来。

例如:

array <int, 5> a = {};

如果初始化列表中的值的个数小于array对象中元素的个数,那么剩下的对象元素都被初始化为0。上面的例子中,初始化列表中值的个数比array对象中元素的个数少(实际上一个值也没有),所以将没有对应值的元素初始化为0。
注:此方法只能在声明时使用

如果要在非声明的地方初始化array对象的元素,可以使用一个循环语句。

提示:
如果在一个array对象的声明中指定了array对象大小和初始化列表,那么初始化值的个数必须小于或等于array对象的大小。

下面的array对象声明语句就会引起编译错误:

array <int, 5> = { 1,2,3,4,5,6 } // error

使用常量变量指定array对象的大小

在C语言中,使用下面的语句是不被允许的:

const int i = 5;
int arr[i] = { 1,2,3,4,5 }; // error

在C语言中声明一个数组,数组的元素个数必须是一个常量。使用const修饰的变量虽然使用上具有常量的性质(初始化之后无法被修改,但是其本质上仍是一个变量)。

在C++中我们就可以使用常量变量来指定一个array对象的大小,比如:

const int a = 5;
array <int, i> arr = { 1,2,3,4,5 };

但是绝对不能使用变量作为array对象的大小;
在这里插入图片描述

注意:使用常量变量时,必须在声明它的时候进行初始化
在这里插入图片描述

二、基于范围的for语句

这是一个C++11的新特性,该语句允许程序员不使用计数器就可以完成所有元素的编历,从而避免array缓冲区溢出的可能性,且减少了程序员的工作量(不需要他们自己去实现对边界的检查功能)。

提示:当处理array对象的所有元素时,如果没有访问array对象元素下标的需求,那么使用基于范围的for语句可以较大程度上预防错误的发生

基于范围的for语句的语法形式:

for(范围变量声明 : 表达式)语句

其中范围变量声明中必须包含一个类型名称和一个标识符(例如:int item),表达式是需要迭代遍历的array对象。范围变量声明中的类型必须与array对象的元素类型相一致,而标识符代表循环的连续迭代中下一个array对象的值。

下面给出一个使用基于范围的for语句的例子。

#include <iostream>
#include <array>using namespace std;int main()
{array <int, 5> items = { 1,2,3,4,5 };cout << "items before modification: ";for (int item : items){cout << item << " ";}for (int item : items){item *= 2;}cout << "\nitems after modification(non-reference): ";for (int item : items){cout << item << " ";}for (int& item : items){item *= 2;}cout << "\nitems after modification(reference): ";for (int item : items){cout << item << " ";}
}

运行结果:
在这里插入图片描述

可以看到在这种基于范围的for语句中,使用的标识符是array对象的一个副本,对它进行修改并不会对array对象本身的值产生影响。所以这里需要使用引用,来实现对array对象值的修改。

注意:要使用基于范围的for语句,循环对象必须要有begin函数(它是什么我们会在迭代器章节介绍)

三、利用array对象存放成绩的GradeBook类

GradeBook.h

#include <string>
#include <array>class GradeBook
{
public:static const size_t students = 10; // 测试数据,学生人数GradeBook(const std::string &, const std::array<int, students> &);void displayMessage() const;void setCourseName(const std::string &);std::string getCourseName() const;//auto getCourseName() const -> std::string; // 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型void processGrades() const;int getMaximum() const;int getMinimum() const;double getAverage() const;void outputBarChart() const;void outputGrades() const;private:std::string CourseName;std::array<int, students> grades; // 保存学生的成绩
};

GradeBook.cpp

#include "GradeBook.h"
#include <iostream>
#include <iomanip>using namespace std;// 构造函数
GradeBook::GradeBook(const string& name, const array<int, students>& gradeArray)// or const array<int, GradeBook::students>& gradeArray) // 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}// 打印欢迎信息
void GradeBook::displayMessage() const
{cout << "Welcome to the Grade Book for\n" << getCourseName() << "!" << endl;
}// set成员函数
void GradeBook::setCourseName(const string& name)
{CourseName = name;
}// get成员函数
string GradeBook::getCourseName() const
{return CourseName;
}// 对成绩进行多种操作
void GradeBook::processGrades() const
{// 打印成绩outputGrades();// 打印班级平均成绩cout << setprecision(2) << fixed; // 打印浮点数后面两位,不足补0cout << "\nClass Average is " << getAverage() << endl;// 打印最低成绩和最高成绩cout << "Lowest grade is " << getMinimum() << endl<< "Highest grade is " << getMaximum() << endl;// 打印班级成绩分布条形图outputBarChart();
}int GradeBook::getMaximum() const
{int max = 0; // 成绩是一个非负数,将最大值初始化为0// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句// 表达式是要循环的对象,也就是数据成员gradesfor (int grade : grades){if (grade > max){max = grade;}}return max;
}int GradeBook::getMinimum() const
{int min = 100; // 成绩最大值为100,将最小值初始化为100// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句for (int grade : grades){if (grade < min){min = grade;}}return min;
}double GradeBook::getAverage() const
{int total = 0;for (int grade : grades){total += grade;}return (static_cast<double>(total) / students);// or return (static_cast<double>(total) / grades.size());// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数// 该值与使用类模板创建一个array对象时的第二个参数相同
}void GradeBook::outputBarChart() const
{cout << "\nGrade distribution:" << endl;// 将成绩分成11个区间// 0-9// 10-19// 20-29// 30-39// ...// 90-99// 100const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0// 用以保存每个区间中学生的人数// 遍历成绩数组,获取每个区间的人数for (int grade : grades){frequency[grade / 10]++;}// 打印条形图for (int i = 0; i < frequencySize; i++){// 打印表头if(i != 10)cout << setw(2) << i * 10 << " - " << setw(3) << 9 + i * 10 << ": ";elsecout << setw(10) << "100: ";// 打印符号*,表示一个人for (int stars = 0; stars < frequency[i]; stars++){cout << "*";}cout << endl;}
}// 打印学生的成绩
void GradeBook::outputGrades() const
{cout << "\nThe grades are: \n";for (int student = 1; student <= grades.size(); student++){cout << "student" << setw(2) << student << ":" << setw(3) << grades[student - 1] << endl;}
}

test.cpp

#include "GradeBook.h"using namespace std;int main()
{// 学生成绩array<int, GradeBook::students> grades = { 87,68,94,100,88,92,78,67,83,98 };// 课程名string CourseName = "CS1201 C++ Programming";// 创建一个GradeBook对象GradeBook myGradeBook(CourseName, grades);myGradeBook.displayMessage();myGradeBook.processGrades();
}

运行结果:
在这里插入图片描述

其中使用了array类中的一个成员函数:

在这里插入图片描述

注意:类中定义的static的数据成员是所有成员共有的,有const的static数据成员可以在类定义时就初始化,没有const的数据成员必须在类外进行初始化。并不像普通的数据成员一样每一个对象都有一个副本

四、array对象的排序与查找

排序
在这里插入图片描述
查找
在这里插入图片描述

使用排序和查找的例子

在介绍示例之前我们先看一段代码:

#include <string>
#include <iostream>using namespace std;int main()
{string s1 = "abcf";string s2 = "abcd";if (s1 < s2){cout << "s1 < s2" << endl;}else{cout << "s1 >= s2" << endl;}
}

这段代码在C语言中是不可行的,因为关系运算符是无法比较字符串的大小的,但是C++中引入了运算符重载的概念(后面会介绍),所以string对象的大小可以使用关系运算符进行比较。

#include <iostream>
#include <algorithm>
#include <array>
using namespace std;int main()
{array<int, 5> a = { 5,4,2,3,1 };cout << "Before sort:" << endl;for (int i : a){cout << i << " ";}sort(a.begin(), a.end());cout << "\n\nAfter sort:" << endl;for (int i : a){cout << i << " ";}
}

运行结果:
在这里插入图片描述

上面传递给sort函数模板的参数类型如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

关于begin和end两个函数,我们会在后续介绍迭代器的章节详细说明。

另一个例子:

#include <iostream>
#include <string>
#include <array>
#include <algorithm>using namespace std;int main()
{const int arraySize = 7;array <string, arraySize> colors = { "red", "yellow", "blue", "green", "orange", "indigo", "violet"};cout << "Unsorted array:" << endl;for (string item : colors){cout << item << " ";}sort(colors.begin(), colors.end());cout << "\n\nSorted array:" << endl;for (string item : colors){cout << item << " ";}bool found = binary_search(colors.begin(), colors.end(), "indigo");cout << "\n\n\"indigo\"" << (found? " was " : " was not ")<< "found in colors." << endl;found = binary_search(colors.begin(), colors.end(), "cyan");cout << "\n\n\"cyan\"" << (found ? " was " : " was not ")<< "found in colors." << endl;
}

运行结果:

在这里插入图片描述
注意:要利用binary_search函数确定一个值是否在array对象中,前提是该array对象中的值是升序排序好的。该函数并不会检查array对象是否已排序

五、多维array对象

多维的array对象是通过嵌套语句的形式进行声明的。例如:

#include <array>
using namespace std;
// 声明一个二维array对象
array<array<int, 4>, 3> arr = {}; // 所有值初始化为0
const int rows = 2;
const int columns = 3;
array<array<int, columns>, rows> arr2 = { 1,2,3,4,5 }; 

上面代码定义了一个3行4列的二维array对象,初始化为0。
arr是一个array对象(有3个元素),它的元素的类型也是一个array对象(有4个int类型的元素)。

二维array对象的使用——嵌套的基于范围的for语句

for (const auto& row : arr2)
{for (auto const& column : row){// operation}
}

上面的for语句中,使用auto关键字作为变量的类型,它的含义是让编译器根据该变量初始化值来确定它的数据类型。

六、利用二维array对象的GradeBook类

在上面的GradeBook类的代码中,我们只有一个一维的array对象用来保存成绩,但是一个学期不可能只有一次考试,所以这显然是不够的。

假设一个学期进行4次考试:当前班级中有10个学生,所以我们需要一个10x4的array对象来保存这些数据。

GradeBook.h

#include <string>
#include <array>class GradeBook
{
public:static const size_t students = 10; // 测试数据,学生人数static const size_t tests = 4;GradeBook(const std::string&, const std::array<std::array<int, tests>, students>&);void displayMessage() const;void setCourseName(const std::string&);std::string getCourseName() const;//auto getCourseName() const -> std::string; // 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型void processGrades() const;int getMaximum() const;int getMinimum() const;double getAverage(const std::array<int, tests> &) const;void outputBarChart() const;void outputGrades() const;private:std::string CourseName;std::array<std::array<int, tests>, students> grades; // 保存学生的成绩
};

GradeBook.cpp

#include "GradeBook.h"
#include <iostream>
#include <iomanip>using namespace std;GradeBook::GradeBook(const string& name,const array<array<int, tests>, students>& gradeArray)// const array<int, GradeBook::students>& gradeArray) // 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}// 打印欢迎信息
void GradeBook::displayMessage() const
{cout << "Welcome to the Grade Book for\n" << getCourseName() << "!" << endl;
}// set成员函数
void GradeBook::setCourseName(const string& name)
{CourseName = name;
}// get成员函数
string GradeBook::getCourseName() const
{return CourseName;
}// 对成绩进行多种操作
void GradeBook::processGrades() const
{// 打印成绩outputGrades();// 打印最低成绩和最高成绩cout << "Lowest grade is " << getMinimum() << endl<< "Highest grade is " << getMaximum() << endl;// 打印班级成绩分布条形图outputBarChart();
}int GradeBook::getMaximum() const
{int max = 0; // 成绩是一个非负数,将最大值初始化为0// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句// 表达式是要循环的对象,也就是数据成员gradesfor (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){if (grade > max){max = grade;}}}return max;
}int GradeBook::getMinimum() const
{int min = 100; // 成绩最大值为100,将最小值初始化为100// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句for (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){if (grade < min){min = grade;}}}return min;
}double GradeBook::getAverage(const array<int, tests>& setOfGrades) const
{int total = 0;// 计算一个学生一学期的平均成绩for (auto const& grade : setOfGrades){total += grade;}return (static_cast<double>(total) / tests);// or return (static_cast<double>(total) / setOfGrades.size());// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数// 该值与使用类模板创建一个array对象时的第二个参数相同
}void GradeBook::outputBarChart() const
{cout << "\nGrade distribution:" << endl;// 将成绩分成11个区间// 0-9// 10-19// 20-29// 30-39// ...// 90-99// 100const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0// 用以保存每个区间中学生的人数// 遍历成绩数组,获取每个区间的人数for (auto const& student : grades) // 使用引用,减少复制副本的开销{for (auto const& grade : student){frequency[grade / 10]++;}}// 打印条形图for (int i = 0; i < frequencySize; i++){// 打印表头if(i != 10)cout << setw(2) << i * 10 << " - " << setw(3) << 9 + i * 10 << ": ";elsecout << setw(10) << "100: ";// 打印符号*,表示一个人for (int stars = 0; stars < frequency[i]; stars++){cout << "*";}cout << endl;}
}// 打印学生的成绩
void GradeBook::outputGrades() const
{cout << "\nThe grades are: \n";cout << setw(10) << " "; // 打印表头,对应student idfor (int i = 0; i < tests; i++){cout << setw(5) << "Test" << setw(2) << i + 1;}cout << setw(9) << "Average" << endl;// 输出所有学生的成绩for (int student = 1; student <= grades.size(); student++){cout << "student" << setw(2) << student << ":" ;// 输出一个学生的所有成绩for (int test = 0; test < tests; test++){cout << setw(7) << grades[student - 1][test];}// 输出该学生的平均成绩cout << setprecision(2) << fixed << setw(9) << getAverage(grades[student - 1]) << endl;}
}

test.cpp

#include "GradeBook.h"using namespace std;int main()
{// 学生成绩array<array<int, GradeBook::tests>, GradeBook::students> grades = {87,  96,  70,  97,68,  87,  90,  93,94, 100,  90,  98,100,  82,  81,  92,83,  65,  83,  80,78,  87,  65,  81,67,  78,  85,  90,77,  79,  63,  88,99, 100,  95,  96,85,  83,  79,  90};// 课程名string CourseName = "CS1201 C++ Programming";// 创建一个GradeBook对象GradeBook myGradeBook(CourseName, grades);myGradeBook.displayMessage();myGradeBook.processGrades();
}

运行结果:

在这里插入图片描述

七、C++标准库类模板vector的介绍

vector对象的声明语法:
vertor<类型> 名称(大小);

示例代码

#include <iostream>
#include <vector>using namespace std;void outputVector(const vector<int> &);
void inputVector(vector<int> &);int main()
{// 与array类模板的声明类似,在<>中指定保存元素的类型,但是容量在变量名后指定vector<int> integer1(7); // 创建一个有7个int类型元素的vector对象vector<int> integer2(10); // 创建一个有7个int类型元素的vector对象// 输出两个vector对象的大小及默认初始值cout << "\nSize of vector integer1 is " << integer1.size() << endl<< "vector after initialization:";outputVector(integer1);cout << "\nSize of vector integer2 is " << integer2.size() << endl<< "vector after initialization:";outputVector(integer2);// 输出17个整数用于初始化两个vector对象cout << "Enter 17 ingeters:" << endl;inputVector(integer1);inputVector(integer2);// 输出赋值后的vector对象的值cout << "\nAfter input, the vectors contain:\n"<< "integer1:" << endl;outputVector(integer1);cout << "integer2:" << endl;outputVector(integer2);cout << "\nEvaluation: integer1 != integer2" << endl;if (integer1 != integer2){cout << "integer1 and integer2 are not equal" << endl;}// 创建一个新vector对象,并使用integer1赋值vector<int> integer3(integer1);cout << "\nSize of vector integer3 is " << integer3.size() << endl<< "vector after initialization:";outputVector(integer3);// 对vector对象直接使用'='进行赋值cout << "\nAssigning integer2 to integer1: " << endl;integer1 = integer2;cout << "integer1:" << endl;outputVector(integer1);cout << "integer2:" << endl;outputVector(integer2);cout << "\nEvaluation: integer1 == integer2" << endl;if (integer1 == integer2){cout << "integer1 and integer2 are equal" << endl;}cout << "\ninteger1[5] is " << integer1[5] << endl;cout << "\n\nAssigning 1000 to integer1[5]." << endl;integer1[5] = 1000;cout << "integer1:" << endl;outputVector(integer1);// 异常处理,访问越界try {cout << "\n\nAttempt to display integer1.at(15)." << endl;cout << integer1.at(15) << endl; // error,越界}catch (out_of_range &ex){cerr << "An exception occured: " << ex.what() << endl;}cout << "\nCurrent Size of integer3 is " << integer3.size() << endl;integer3.push_back(1000); // 在integer3的末尾添加一个元素3cout << "New integer3 size is " << integer3.size() << endl;cout << "integer3 now contains: " << endl;outputVector(integer3);
}void outputVector(const vector<int>& array)
{// 使用基于范围的for语句遍历整个vector对象for (int item : array){cout << item << "  ";}cout << endl;
}void inputVector(vector<int>& array)
{for (int item : array){cin >> item;}
}

运行结果:

在这里插入图片描述

代码中使用的库函数:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

从上面的程序执行结果可以看出,vector对象可以使用关系运算符进行比较操作。

一个vector对象可以用另一个vector对象进行初始化。也可以使用一个vector对象为另一个vector对象赋值。

还可以像数组一样使用[]和下标来访问指定的vector元素,但是在使用[]进行访问时,C++是不会进行边界检查的。但是在vector类提供的at函数中,是提供了边界检验功能的。

异常处理:处理超出边界的下标

异常是一个在程序运行时出现的问题的表现。异常处理使程序员能够创建可以解决(或处理)异常的容错程序。在很多情况下,在处理异常的同时还允许程序继续运行,就像没有遇到异常一样。

try语句:
为了处理一个异常需要把可能抛出一个异常的任何代码放置在一个try语句中。

catch语句:
包含了发生异常时,负责处理异常的代码。

比如,上面例子中try语句中包含了一个调用vector类的at成员函数的语句,该函数提供了边界检查和抛出异常的功能,当这个函数的实参是一个无效下标时,就会抛出一个异常。在默认的情况下这会导致C++程序终止。在这里下标15显然不是一个有效的下标,所有异常出现,由该try语句对应的catch语句来处理这个异常。
从上面的库函数介绍图中,可以看出,at函数抛出的异常是out_of_range类型的异常。所以在上面代码的catch语句指定了处理的异常的类型为out_of_range,且声明了一个用于接收引用的异常形参ex。在这个语句块中,可以使用形参的标识符来实现与捕捉到的异常对象的交互。

注意,try和catch是两个不同的语句块,它们的作用域不同,在try中声明的变量无法在catch中使用。

异常形参的what函数:
在上面的代码中调用了这个异常对象的what成员函数,来得到并显示存储在此异常对象中的错误信息。

更详细的异常处理内容会在之后的章节中说明。

vector对象和array对象的主要区别

vector对象和array对象的一个主要区别就是vector对象可以动态增长以容纳更多元素。

使用成员函数push_back可以为vector对象增加一个元素,对应的可以使用pop_back这个成员函数删除vector对象中的一个元素。

除了像上面一样使用for循环语句对vector对象进行初始化,还可以使用初始化列表对vector对象进行初始化。例如:

#include <iostream>
#include <vector>using namespace std;int main()
{vector<int> integer4 = { 1,2,3,4,5 };// or vector<int> integer4{1,2,3,4,5};for (int item : integer4){cout << item << "  ";}
}

上面这段代码中,使用初始化列表将vector对象integer4初始化为有5个元素vector对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/49010.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能之数学基础:二次型

本文重点 二次型作为线性代数领域的重要概念,架起了代数方程与几何分析之间的桥梁。从古典解析几何中的圆锥曲线方程到现代优化理论中的目标函数,二次型以其简洁的数学表达和丰富的结构特性,在数学物理、工程技术和经济金融等领域发挥着不可替代的作用。 二次型的基本概念…

eNSP中路由器RIP协议配置完整实验实验和命令解释

一、实验拓扑 二、配置命令 R1配置并先测试一下连通性 R1、R2和R3接口配置完后再测试连通性&#xff0c;直连路由可通 启动RIP进程&#xff0c;宣告直连网络 查看路由表&#xff0c;测试连通性 环回接口配置 三、命令解释及注意事项 配置命令逐行解释 system-view: 从用户视…

[6-1] TIM定时中断 江协科技学习笔记(45个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 TRGO是“Trigger Output”的缩写&#xff0c;中文意思是“触发输出”。在STM32微控制器中&#xff0c;TRGO是一个非常重要的功能&#xff0c;它允许定时器&#xff08;Timer&#xff09;在特定事件发生时输出一个触发信号。这个触发信号可以用…

工业与协议融合篇:如何将多个协议集成进一个系统?

🏭 本文为《嵌入式通信协议全解析》第六篇,深入探讨如何在工业或物联网系统中同时集成 BLE、CAN、LoRa、MQTT、RS485 等多种通信协议,实现一个高效、可控、稳定运行的嵌入式通信架构。 🧭 一、为什么需要多协议融合? 在真实产品中,单一通信协议往往无法满足所有业务需…

宁德时代区块链+数字孪生专利解析:去中心化身份认证重构产业安全底座

引言&#xff1a;当动力电池巨头瞄准数字孪生安全 2025年5月6日&#xff0c;金融界披露宁德时代未来能源&#xff08;上海&#xff09;研究院与母公司宁德时代新能源科技股份有限公司联合申请的一项关键专利——“身份验证方法、系统、电子设备及存储介质”。这项技术将区块链…

【计网】TCP/IP四层模型(一)

OSI七层模型 OSI&#xff08;Open Systems Interconnection&#xff09;七层模型是国际标准化组织&#xff08;ISO&#xff09;提出的网络通信框架&#xff0c;用于标准化不同厂商设备之间的通信流程。 物理层&#xff08;Physical Layer&#xff09;​​ ​​作用​​&#xf…

自监督学习(Self-supervised Learning)李宏毅

目录 Self-supervised Learning简介&#xff1a; BERT : How to use BERT case1&#xff1a;sequence to class 语言积极性OR消极性判断 case2&#xff1a;sequence to sequence句子中的词语词性标注 case3&#xff1a;sequence2 to class两个句子是不是一个为前提一个为…

DeepSeek实战--微调

1.为什么是微调 &#xff1f; 微调LLM&#xff08;Fine-tuning Large Language Models&#xff09; 是指基于预训练好的大型语言模型&#xff08;如GPT、LLaMA、PaLM等&#xff09;&#xff0c;通过特定领域或任务的数据进一步训练&#xff0c;使其适应具体需求的过程。它是将…

蓝桥杯FPGA赛道第二次模拟题代码

一、顶层文件 module test( input wire sys_clk, input wire sys_rst, input wire [3:0]key_in, output reg [7:0]led,output wire scl, inout wire sda,//i2c的信号output wire [7:0]sel, output wire [7:0]seg//数码管的驱动 );wire [23:0] data ; reg [31:0] dsp_dat…

R 语言机器学习:为遥感数据处理开启新视角

技术点目录 基础理论、机器学习与数据准备建模与空间预测实践案例与项目了解更多 ——————————————————————————————————————————— 前言综述 在当今科技快速发展的时代&#xff0c;遥感技术为生态学研究提供了海量的数据资源&#xf…

AI与脑机接口:人机融合的终极形态?

AI与脑机接口&#xff1a;人机融合的终极形态&#xff1f; 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 AI与脑机接口&#xff1a;人机融合的终极形态&#xff1f;摘要引言技术路线对比1. 信号采集&#xff1a;侵…

20250508在WIN10下使用移远的4G模块EC200A-CN直接上网

1、在WIN10/11下安装驱动程序&#xff1a;Quectel_Windows_USB_DriverA_Customer_V1.1.13.zip 2、使用移远的专用串口工具&#xff1a;QCOM_V1.8.2.7z QCOM_V1.8.2_win64.exe 3、配置串口UART42/COM42【移远会自动生成连续三个串口&#xff0c;最小的那一个】 AT命令&#xf…

南京大学OpenHarmony技术俱乐部正式揭牌 仓颉编程语言引领生态创新

2025年4月24日&#xff0c;由OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;项目群技术指导委员会与南京大学软件学院共同举办的“南京大学OpenHarmony技术俱乐部成立大会暨基础软件与生态应用论坛”在南京大学仙林校区召开。 大会聚焦国产自主编程语言…

中小企业设备预测性维护:从技术原理到中讯烛龙实践落地指南

在工业 4.0 与智能制造浪潮的推动下&#xff0c;中小企业正面临设备管理模式的深刻变革。传统的事后维修与预防性维护策略&#xff0c;因缺乏数据驱动与智能决策能力&#xff0c;已难以满足企业降本增效的核心诉求。据 Gartner 统计&#xff0c;非计划停机导致的生产损失平均每…

服务器数据恢复—硬盘坏道导致EqualLogic存储不可用的数据恢复

服务器存储数据恢复环境&故障&#xff1a; 一台EqualLogic某型号存储中有一组由16块SAS硬盘组建的RAID5阵列。上层采用VMFS文件系统&#xff0c;存放虚拟机文件&#xff0c;上层一共分了4个卷。 磁盘故障导致存储不可用&#xff0c;且设备已经过保。 服务器存储数据恢复过程…

STM32的SysTick

SysTick介绍 定义&#xff1a;Systick&#xff0c;即滴答定时器&#xff0c;是内核中的一个特殊定时器&#xff0c;用于提供系统级的定时服务。该定时器是一个24位的递减计数器&#xff0c;具有自动重载值寄存器的功能。当计数器到达自动重载值时&#xff0c;它会自动重新加载…

电子电气架构 --- 如何有助于提安全性并减少事故

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

跨浏览器自动化测试的智能生成方法

一、背景与挑战&#xff1a;跨浏览器测试为什么“难”&#xff1f; 在现代Web应用开发中&#xff0c;跨浏览器兼容性是用户体验的底线保障。面对Chrome、Firefox、Safari、Edge乃至IE、移动浏览器等多种运行环境&#xff0c;开发者与测试人员常面临&#xff1a; 相同DOM在不同…

小程序与快应用:中国移动互联网的渐进式革命——卓伊凡的技术演进观

小程序与快应用&#xff1a;中国移动互联网的渐进式革命——卓伊凡的技术演进观 在知乎看到很多&#xff1a;“懂王”发布的要把内行笑疯了的评论&#xff0c;卓伊凡必须怼一下&#xff0c;真印证那句话&#xff0c;无知者无畏 一、Web与小程序的技术本质差异 1.1 浏览器渲染…

抛物线法(二次插值法)

抛物线法简介 抛物线法&#xff08;Quadratic Interpolation Method&#xff09;是一种用于一维单峰函数极值搜索的经典优化方法。该方法通过在区间内选取三个不同的点&#xff0c;拟合一条二次抛物线&#xff0c;并求取这条抛物线的极值点作为新的迭代点&#xff0c;从而逐步…