C++Primer学习笔记:第3章 字符串、向量和数组

  • 可以使用using声明而无需专门的前缀:using namespace::name;.。位于头文件的代码一般来说不应该使用using声明,这是因为头文件的内容会拷贝到所有引用他的文件中去,如果头文件中有某个using声明,那么每个使用了该头文件的文件都会有这个声明。对于某些程序来说,由于不经意间包含了一些名字,反而可能产生始料未及的名字冲突。

  • 使用string类型需要添加头文件#include<string>,并且要对string进行声明:using std::string;

  • string类型的初始化:

    string s1;		默认初始化,s1是一个空字符串
    string s2 = s1;	s2是s1的副本,等价于s2(s1)
    string s3 = "hello";	s3是该字符串字面值的副本,等价于s3("hello");
    string s4(10, 'c');	s4的内容是10个c
    

    需要注意的是s3是的内容不包括字面值最后的空字符。当初始值只有一个的时候,拷贝初始化(使用=)和直接初始化都可以,但是如果有多个初始值(s4的初始化),就只能够使用直接初始化的方式。

  • string的操作

    os<<s		将s写入都输出流os中,返回os
    is>>s		从is中读取字符串赋给s,字符串以空白分隔,返回is
    getline(is, s)	从is中读取一行赋给s,返回is
    s.empty()	s为空返回true,否则返回false
    s.size()	返回s中字符的个数
    s[n]		返回s中第n个字符的引用
    s1+s2		返回s1和s2连接后的结果
    s1=s2		用s2的副本代替s1中原本的字符
    s1==s2		如果s1和s2所包含的字符完全一样,则返回true
    s1!=s2
    <,<=,>,>=	根据字典序进行比较	
    

    可以使用while(cin>>s)进行循环读入,getline读入换行符,但是不会把换行符保存到string对象中。因为getline返回的也是输入流,因此也可以使用while(getline(cin,s))进行循环读入

  • size()函数返回值是string::size_type类型,这是一个无符号整型,因此如果我们直接使用size()的返回值和一个负数比较,则几乎肯定是true,这是因为负数n会自动转换成一个比较大的无符号整数。(在C++中intunsigned int在一起的时候前者会自动转换为后者)。尽量还是用一个int变量保存返回值或者进行强制类型转换。

  • 如果两个字符串前面都相同,长的那个比短的大

  • 复合运算符+=负责把右侧string对象追加到左侧string对象的后面

  • 当把string对象和字符(串)字面值混在一条语句中使用时,必须确保每个加法运算符+两侧的运算对象至少有一个是string

    string a = "Hello";
    string b = a + "world" + "!";	//正确
    string c = "Hello" + "world" + a;	//错误
    

    字符串字面值与string是不同的类型

  • 应该尽可能使用C++版本的C标准库头文件(去掉结尾的.h,在前面加上c表示属于C标准库的头文件),虽然两者内容一样,但是在名为cname中的头文件中定义的名字从属于命名空间std,而.h头文件则不然。

  • 可以使用库cctype判断一个字符的类别

    isalnum(c)	当c为字母或数字为真
    isalpha(c)	当c为字母为真
    iscntrl(c)	当c为控制字符为真
    isdigit(c)	当c为数字为真
    islower(c)	当c为小写字母为真
    ispunct(c)	当c为标点符号为真
    isspace(c)	当c为空白字符为真
    isupper(c)	当c为大写字母为真
    tolower(c)	如果c是大写字母则返回小写字母,否则原样输出
    toupper(c)	如果c是小写字母则返回大写字母,否则原样输出	
    
  • 如果想要改变string对象中字符的值则必须把循环变量定义成引用类型:

    string s;
    cin >> s;
    //将s中每个字母变成大写
    for(auto &c : s)
    {c = toupper(c);
    }
    cout << s << endl;
    

    从这里也可以看出c每次会重新定义

  • string类型的下标是string::size_type类型的,任何一个带符号类型的值将自动转化为这种无符号类型。注意不要越界,越界的行为是未定义的。

  • 注意逻辑运算符&&||的短路性质

  • const string的每一个字符是const char类型的

  • 模板本身不是类或者函数,可以将模板看做编译器生成类或者函数编写的一份说明。编译器根据模板创建类或函数的过程成为实例化 。当使用模板时,需要指出编译器应把类或函数实例化成何种类型。

    vector<int> a;
    vector<vector<string>> file;	
    

    vector能容纳绝大多数类型的对象作为元素,但是因为引用不是对象,所以不存在包含引用的vector
    需要指出的是,在旧版本中多维vector的声明中最后的>之间必须有空格,否则编译器会认为是右移运算符。

  • vector初始化:

    vector<T> v1;		v1是一个空的vector,潜在的元素是T类型的,执行默认初始化
    vector<T> v2(v1);	v2包含有v1所有元素的副本
    vector<T> v2 = v1;	等价于v2(v1)
    vector<T> v3(n, val)v3包含了n个重复元素,每个元素的值都是val
    vector<T> v4(n)		v4包含了n个重复地执行了值初始化的对象
    vector<T> v5{a, b, c,...}v5包含了初始值个数的元素,每个元素被赋予对应的初始值
    vector<T> v5 = {a, b, c...}等价于v5{a, b, c,...}	
    
  • C++几种初始化方式一般来说可以相互等价地使用,但是也有几种特殊情况:

    • 使用拷贝初始化(使用=的时候)只能提供一个初始值
    • 类内初始化只能使用拷贝初始化或花括号的形式
    • 如果提供的是初始元素之的列表,则只能把初始值放在花括号里而不能放在圆括号里
  • 可以只提供vector对象容纳的元素数量而略去初始值,此时库会创建一个值初始化的元素初值,并把它赋给容器中的所有元素。但是如果元素对象是一个类,而这个类明确要求需要提供初始值,则无法完成初始化工作。

  • 如果使用圆括号来初始化,可以说提供的值是用来构造vector对象的;如果使用花括号,可以表述成我们想列表初始化该vector对象。但是如果提供的值不支持列表初始化,编译器就会尝试理解为直接初始化(把{当做(来处理),如果仍旧无法进行初始化,则报错

  • 使用push_back方法向vector的尾部添加元素。C++标准要求vector应该能在运行时高效添加元素,因为vector对象能够高效地增长,在定义vector对象设定其大小没有什么必要,事实上这么做性能可能更差,这一点和Java不同。

  • 如果循环体内部包含向vector对象添加元素的语句,则不能使用范围for循环(for(auto item:a)

  • 常见的vector操作:

    v.empty()
    v.size()
    v.push_back(t)
    v[n]
    v1 = v2		用v2中元素的拷贝替换v1中的元素
    v1 = {a,b,c...}	用列表中元素的拷贝替换v1中的元素
    v1 == v2 	v1和v2相等当且仅当他们的元素数量相同而且对应位置的元素值都相同
    <, <=, >, >=	顾名思义,以字典顺序进行比较	
    
  • size函数返回size_type类型,需要指定对应的模板类型,例如:

    vector<int>::size_type		//正确
    vector::size_type			//错误	
    

    使用比较运算符需要元素可以相互比较
    vector的下标运算符可用于访问已经存在的元素,而不能用于添加元素

  • 所有标准库容器都可以使用迭代器,但是其中只有少数几种才同事支持下标运算符。严格来说,string对象不属于容器类型,但是string支持很多与容器类型类似的操作。这些类型都拥有名为beginend的成员,其中begin成员负责指向第一个元素的迭代器,end成员负责返回指向容器尾元素的下一位置的迭代器(尾后迭代器或尾迭代器)。如果容器为空,beginend返回同一个迭代器。使用auto进行迭代器的定义比较方便。
    常见操作:

    *iter 	返回迭代器所指元素的引用
    iter->member	相当于(*iter).member
    ++iter	令迭代器指向容器的下一个元素
    --iter	令迭代器指向容器的上一个元素
    iter1 == iter2	判断两个迭代器是否相等
    iter1 != iter2 	
    

    试图解引一个尾后迭代器是未定义的行为

    //以此处理s的字符串直到我们全部处理完或遇到空白字符
    for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
    {*it = toupper(*it);
    }	
    
  • 在C++中我们更愿意使用迭代器和!=判断是否到达尾部。这样做的原因是所有容器都支持这些操作,而下标和<则只有很少的容器定义。

  • 迭代器的类型有两种:iteratorconst_iterator,后者表示不能修改元素值,如果vectorstringconst的,则只能使用这种类型。

    string::iterator it1;
    vector<int>::const_iterator it2;
    

    如果容器是常量,则beginend返回的类型是const_iterator类型的迭代器。如果我们使用cbegincend则无论容器是否是常量都返回const_iterator类型的迭代器。

    //依次输出text的每一行直到遇到第一个空白行
    for(auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
    {cout << *it << endl;3
    }	
    
  • 使用范围for循环或者使用迭代器进行循环都不能改变容器对象的容量,否则有可能使得迭代器失效

  • 迭代器运算:stringvector的迭代器提供了更多的运算符,可以让迭代器每次跨过多个元素,另外也支持迭代器进行关系运算

    //小心越界
    iter + n 		迭代器向后移动n个元素
    iter - n		迭代器向前移动n个元素
    iter += n
    iter -= niter1 - iter2 	返回两个迭代器之间的距离
    <, <=, >, >=
    

    其中迭代器之间的-返回difference_type的带符号整数

    int bSearch(const vector<int> &a, int x)
    {	auto begin = a.cbegin();auto end = a.cend();auto mid = begin + (end - begin) / 2;while(mid != end && *mid != x){if(*mid < x)begin = mid + 1;else end = mid;mid = begin + (end - begin) / 2;}if(mid == end) return -1;else return mid - begin;
    }
    
  • 数组也是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问,不过数组的大小不能改变。

  • 数组是一种复合类型,元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的(维度必须是一个常量表达式)。数组的元素会被默认初始化,如果数组的元素是内置类型而且数组在函数内部定义,则每个元素不会被初始化。不允许用auto关键字由初始值的列表推断类型,且不存在引用的数组

  • 如果用初始值列表初始化数组,则数组的维度可以不指明,默认为初始值列表的长度。如果指定维度的话则维度至少要比初始值列表的长度长,剩下的元素会被默认初始化

  • 字符数组可以用字符串字面值进行初始化,不过需要注意的是字符串字面值的末尾有一个空字符也会被拷贝到字符数组中,因此字符数组的长度应该是可见的字符个数加一

  • 不能将数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值

  • 对于声明中有括号的应该先理解括号里面的,再从右往左进行理解

    int *ptr[10];	ptr是含有10个整型指针的数组
    int &ptr[10];	错误,不存在引用的数组
    int (*ptr)[10];	ptr是指针,指向含有10个元素的数组
    int (&ptr)[10] = arr;	ptr是引用,指向一个含有10个元素的数组	
    
  • 在使用数组下标时,通常将其定义为size_t了类型。size_t是一种机器相关的无符号类型,被设计得足够大能够表示内存中任意对象的大小。在cstddef头文件中定义

  • 对于数组我们同样可以使用范围for循环:

    unsigned scores[11] = {};	//进行初始化
    for (auto i : scores)cout << i << " ";	
    
  • 在C++中,使用指针的时候编译器一般会把它转换成指针。在很多用到指针名字的地方,编译器都会自动将其替换为一个指向数组首元素的指针。

  • 当我们将数组作为一个auto变量的初始值时,推断得到的类型是指针而非数组。但是用decltype返回的类型仍然是数组

    int ia[] = {0, 1, 2, 3, 4};
    auto ia2(ia);	//ia2是一个整型指针
    decltype(ia) ia3 = {};	//含有5个元素的整型数组	
    
  • 我们可以像使用迭代器一样使用指针,为了让指针的使用更简单、安全,C++11新标准引入两个名为beginend的函数。这两个函数定义在iterator头文件中

    int a[10] = {};
    int *beg = begin(a);	//相当于int *beg = a;
    int *last = end(a);		//相当于int *last = &a[10];
    

    同尾后迭代器一样,尾后指针不能执行解引操作和递增操作

  • 迭代器支持的操作指针都支持,包括和整数进行加减、指针和指针的减法、指针和指针比较大小,但是需要注意的是上面的操作两个指针要在同一个数组中才有意义。特别地,允许给空指针加上或减去一个值为0 的整型常量表达式。两个空指针也循序彼此相减,结果当然是0。

  • 指针同时有解引和其他运算的时候最好加上括号标明运算顺序

  • 标准库类型限定使用的下标必须是无符号类型,而内置的下表运算无此要求

  • 尽管C++支持C风格字符串,但在C++程序中最好还是不要使用他们,这是因为C风格字符串不仅使用起来不太方便,而且极容易引发程序漏洞,是诸多安全问题的根本原因。

  • C风格字符串存放在字符数组中并以空字符结束。

  • 在头文件cstring中有一些操作C风格字符串的函数:

    strlen(p)		返回p的长度
    strcmp(p1, p2)	比较p1和p2,如果p1==p2,返回0,如果p1<p2,返回负数,否则返回正数
    strcat(p1, p2)	将p2附加到p1之后,返回p1
    strcpy(p1, p2)	将p2拷贝给p1,返回p1
    

    传入此类函数的指针必须指向以空字符作为结束的数组

  • 任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代:

    • 允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值
    • string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象(不能两个对象都是),在string对象的复合赋值运算中允许使用以空白字符结尾的字符数组作为右侧的运算对象
  • string对象的成员函数c_str()返回值是一个C风格的字符串,也就是说,函数的返回值是一个指针, 该指针指向一个以空字符结束的字符数组,而这个数组所存的数据恰好与那个string对象一样。结果指针的类型是const char*,从而确保我们不会改变字符数组的内容。我们无法保证c_str()函数返回的数组一直有效,事实上,如果后续的操作改变了s的值就可能让之前返回的数组失去作用。如果执行完c_str()函数后程序想一直都能使用其返回的字符数组,最好将该数组重新拷贝一份。

    const char *str = s.c_str();	
    
  • 允许使用数组来初始化vector对象,只需要指明拷贝区域的首元素地址和尾后地址即可。

    int int_arr[] = {0, 1, 2, 3};
    vector<int> a(begin(int_arr), end(int_arr));	
    
  • 现代的C++程序应当尽量使用vector和迭代器,避免使用内置数组和指针;应该尽量使用string,避免使用C风格的基于数组的字符串

  • C++语言中没有多维数组,通常所说的多维数组其实是数组的数组。

  • 多维数组的初始化

    int ia[3][4] = {{0, 1, 2, 3}.{4, 5, 6, 7},{8, 9, 10, 11}
    };
    int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
    int ia[3][4] = { {0}, {4}, {8} };	只初始化每行的首元素,其他未列出的元素执行默认初始化
    int ia[3][4] = {0, 3, 6, 9};	只初始化第一行的元素,其他的初始化为0	
    

    多维数组的操作:

    int (&row)[4] = ia[1];	//把row绑定到ia的第二个4元素数组上
    int cnt = 0;
    for (auto &row : ia) {for( auto &col : row) {col = cnt++;}
    }	
    

    注意:要使用范围for循环处理多维数组,除了最内层的循环外,其他所有循环控制变量都应该是引用类型。如果不是引用类型,编译器的会把数组类型转化成指针类型,这样内层循环就无法使用范围for语句了,因为对一个指针进行循环显然没有意义。

  • 当程序使用多维数组的名字时,也会自动将其转换成指向数组首元素的指针。因为多维数组实际上是数组的数组,所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针。

    int ia[3][4]
    int (*p)[4] = ia;	//p指向含有4个整数的数组ia[0]
    p = &ia[2];			//p指向ia的尾元素ia[2]	
    

    上面的括号必不可少,如果没有括号,int *p[4]的意义将会是大小为4的整型指针数组

  • 随着C++11新标准的提出,通过使用auto或者decltype就能尽可能避免在数组前面加上一个指针类型了。

    int a[3][4];
    for (auto p = ia; p != ia + 3; ++p) {
    //int (*p)[4]for (auto q = *p; q != p + 4; ++q) {//int *qcout << *q << ' ';}cout << endl;
    }	
    

    可以使用标准库函数beginend实现同样的功能:

    for (auto p = begin(ia); p != end(ia); ++p) {for (auto q = begin(*p); q != end(*p); ++q) {cout << *q << ' ';}cout << endl;
    }	
    

    可以使用类型别名简化多维数组的指针

    using int_arr = int[4];
    typedef int int_arr[4];	//同上面等价+	
    
  • 第三章看完啦,啦啦啦啦,后面要稍微加快进度

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

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

相关文章

C++Primer学习笔记:第4章 表达式

表达式由一个或多个运算对象组成&#xff0c;对表达式求值将得到一个结果。字面值和变量是最简单的表达式&#xff0c;其结果就是字面值和变量的值。把一个运算符和一个或多个运算对象组合起来可以生成较复杂的表达式。 重载运算符包括运算对象的类型和返回值的类型&#xff0…

C++Primer学习笔记:第5章 语句

一个表达式末尾加上分号就变成了表达式语句。最简单的语句是空语句&#xff08;一个单独的分号&#xff09;&#xff1a;语法上需要一条语句但是逻辑上不需要 复合语句是指用花括号括起来的&#xff08;可能为空&#xff09;语句和声明的序列&#xff1a;用在语法上需要一条语…

z3 C++学习笔记

因为项目需要使用z3库来解决问题&#xff0c;所以自己学习了一下&#xff0c;结果发现网上教程比较少&#xff0c;而且大部分都是使用Python&#xff0c;而我本人是C的忠实信徒&#xff0c;在知道C也可以使用z3库以后我毫不犹豫地着手用C使用z3&#xff0c;但是我很快发现&…

C++Primer学习笔记:第6章 函数

通过调用运算符()调用函数 函数的调用完成两项工作&#xff1a; 用实参初始化函数对应的形参将控制权转移给被调用函数&#xff1a;主调函数的执行被暂时中断&#xff0c;被调函数开始执行 尽管实参与形参存在对应关系&#xff0c;但是并没有规定实参的求值顺序。编译器能以任…

C++Primer学习笔记:第8章 IO库

C语言不直接处理输入输出&#xff0c;而是通过一族定义在标准库中的类型来处理IO iostream定义了用于读写流的基本类型fstream定义了读写命名文件的类型sstream定义了读写内存string对象的类型 标准库使得我们能够忽略这些不同类型的流之间的差异&#xff0c;是通过继承机制实…

C++Primer学习笔记:第7章 类

类的基本思想是数据抽象data abstraction和封装encapsulation。数据抽象是一种依赖于接口interface和实现implementation分离的编程技术 在类中&#xff0c;由类的设计者负责考虑类的实现过程&#xff0c;使用该类的程序员只需要抽象地思考类型做了什么&#xff0c;而无须了解…

每日一题:leetcode191.位1的个数

题目描述 题目分析 很自然地想到了二进制枚举&#xff0c;直接循环检查每一个二进制位。 class Solution { public:int hammingWeight(uint32_t n) {int ret 0;uint32_t t 1;for (int i 0; i < 32; i, t << 1) {if (n & t) {ret;}}return ret;} };AC之后看了…

每日一题:leetcode341.扁平化嵌套列表迭代器

题目描述 题目分析 这个题目自己大概花了一个小时&#xff0c;虽然是一遍AC&#xff0c;但是速度有点慢&#xff0c;太长时间不写代码导致自己对代码不太敏感&#xff0c;写起来慢腾腾的。 看到这个的想法就是&#xff0c;要用栈来保存列表的迭代器&#xff0c;这样将孩子列表…

每日一题:leetcode82. 删除排序链表中的重复元素 II

题目描述 题目分析 这才是正常的中等题难度嘛&#xff0c;昨天的中等题题解我半天看不懂。。。 首先&#xff0c;需要增加一个哑节点&#xff08;操作链表的常规操作&#xff09;&#xff0c;因为有可能删除首节点&#xff0c;我们不想要为首节点添加单独的逻辑。其次&#xf…

每日一题:leetcode456.132模式

题目描述 题目分析 我觉得这道题应该是我做过最难的中等题之一了&#xff0c;这是昨天的每日一题&#xff0c;但是昨天用nlogn的做法做出来以后在看题解&#xff0c;发现有些看不懂&#xff08;觉得题解有点故弄玄虚&#xff09;。然后今天中午又花了一点时间才搞懂&#xff0…

leetcode283.移动零

题目描述 题目分析 在写简单题放松&#xff0c;看到这道题第一个想法是用STL库函数&#xff0c;虽然知道大概要用双指针之类的&#xff0c;但是库函数爽哇。 class Solution { public:void moveZeroes(vector<int>& nums) {stable_sort(nums.begin(), nums.end(), …

每日一题:leetcode61.旋转链表

题目描述 题目分析 很容易发现&#xff0c;如果k是n的整数倍&#xff0c;相当于没有移动。这样直接对k%n使得k在一个可以接受的范围。 因为是顺序移动&#xff0c;各元素之间的相对位置保持不变&#xff0c;所以就想着将链表先变成一个环。然后再移动头指针&#xff0c;最后再…

每日一题:leetcode173.二叉搜索树迭代器

题目描述 题目分析 更加地觉得编程重要的不在于如何写代码&#xff0c;用什么具体的技巧&#xff0c;编码本身只是一种将思维呈现的方式&#xff0c;但是如果思维是不清晰的&#xff0c;那么就算懂得再多的编码的奇技淫巧也是没有什么帮助的。相反&#xff0c;如果有一个清晰的…

Ubuntu20.04 Clion/Pycharm/IDEA 输入中文+光标跟随解决方案

ibus输入法&#xff08;弃用&#xff09; 之前一直用的搜狗输入法&#xff0c;但是搜狗输入法无法在Jetbrains全家桶下使用&#xff0c;但是又需要输入中文&#xff0c;没有办法我只能下载了谷歌输入法&#xff0c;十分难用&#xff0c;但是也没有其他办法&#xff0c;经常到网…

leetcode11.盛最多水的容器

题目描述 题目分析 看到题目后第一个想法当然是O(n2)O(n^2)O(n2)的&#xff0c;但是数据范围是3e4&#xff0c;应该会超时&#xff0c;而且这种数据范围也不是让暴力求解的 。 相当于求解∑i<jmax((j−i)∗min(a[i],a[j]))\sum_{i<j}{max((j-i)*min(a[i],a[j]))}∑i<…

每日一题:leetcode190.颠倒二进制位

题目描述 题目分析 题目本身很简单&#xff0c;没觉得有什么技巧可以再进行优化了&#xff0c;觉得位运算是无法打乱相对顺序的&#xff0c;而这里需要进行镜像颠倒的操作。因此就踏实地写了一个循环。 在使用位运算得到每一位的时候&#xff0c;我吸取了经验&#xff0c;用一…

结构屈曲分析

结构屈曲分析主要用于判定结构受载后是否有失稳风险&#xff0c;作为工程应用&#xff0c;一般分为线性屈曲分析和非线性屈曲分析。 线性屈曲分析需要具备较多的前提条件&#xff0c;如载荷无偏心、材料无缺陷等&#xff0c;在实际工程应用中结构制作过程和加载方式很难达到线性…

每日一题:leetcode74.搜索二维矩阵

题目描述 题目分析 感觉这是一个放错标签的简单题。题目非常简单&#xff0c;思路应该很明确是二分&#xff0c;我很快写了一个&#xff08;虽然不小心把!打成调试了一会&#xff09;。 class Solution { public:bool searchMatrix(vector<vector<int>>& mat…

每日一题:leetcode90.子集贰

题目描述 题目分析 感觉这道题让自己对枚举排列有了一个更好的认识&#xff0c;感觉自己的这种思路不错。 假设没有重复元素&#xff08;退化成78.子集&#xff09;&#xff0c;我们应该怎么做&#xff1f;初始的时候幂集中只有一个空集&#xff0c;然后对每个元素&#xff0…

每日一题:leetcode1006.笨阶乘

题目描述 题目分析 因为顺序一定且没有括号&#xff0c;所以逻辑很简单。我们要顺序处理的矛盾在于&#xff0c;减号后面会再出现乘法和除法&#xff0c;我们不妨将对乘法和除法用一个临时值进行计算&#xff0c;计算结束后再合并到值里面&#xff0c;一般来讲乘法和除法的处理…