数组的表示方法
int N=5;
int a1[N];
int *a2=new int[N];//释放用delete
数组几乎可以用vector代替,试着练习了一个重载函数
#include<iostream>
#include<vector>
using namespace std;
ostream&operator <<(ostream& o, const vector<int>& n){
for(auto x:n){
o<<x<<endl;
}
return o;
}
int main(){
vector<int>num;
for(int i=0;i<10;++i){
num.push_back(i);
}
cout<<num;
}
c++11后有一个新的遍历数组的方式for(auto x: array),非常像python里的for i in array。
虽然说向量也可以用vector<int>num(10)的方式指定创建一个大小为10的向量,如果直接用for(int i=0;i<num.size();++i)或者迭代器,for(i=num.begin();i!=num.end();++i),会轮出20个,前面都是0,说明你没有溢出,因为向量就是要给你开辟足够的空间。我们老师说向量不建议这样使用,因为它本身就是一个灵活的容器,都指定大小了,那你不如去用数组。
另外对于ostream中的这个引用,引用就是引用了输入的实参的值,本质上是防止倒灌。(更容易接受周强老师的解释,如果直接传入这个变量,相当于把这个变量的全部都传进去了,比如说该变量是一个结构体,那就会把这个结构体中所有元素都传进去,效率低下。如果只是引用,传进去就是一个地址。)
向量遍历——迭代器的使用
迭代器就相当于一个遍历。
迭代器遍历可以这样写:
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int>num;
for(int i=0;i<10;++i){
num.push_back(i);
}
vector<int>::iterator it;
for(it=num.begin();it!=num.end();++it){
cout<<*it<<endl;
}
}
num.begin()相当于该向量的起始位置,array.end()是结束位置,前者指向第一个元素0,后者指向最后一个元素9的后面。迭代器的++是重载。
当需要查找容器内某个元素时,可以使用find(引入头文件algorithm),返回一个迭代器,指向这个元素。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
vector<int>num;
for(int i=0;i<10;++i){
num.push_back(i+7);
}
vector<int>::iterator it;
it=find(num.begin(),num.end(),10);
cout<<*it<<endl;
}
这时候*it是10,即迭代器指向了10这个元素,it即为这个元素的位置(迭代器形式)
同上,如果没有找到,迭代器就会在移到容器末端(num.end())的时候停止移动,此时*it就是容器末端那个地址指向的数字。
二维数组
昨天重修c++的时候也听老师说了,二维数组表面上是二维的,实质上还是一维数组,是数组的数组。
下面两种情况第一种是我们熟知的二维数组定义方式。
第一种代表数组元素是由4个整形变量组成的数组
虽然之前说过,int *a2=int [4]可以定义一维数组,但是第二种定义的不是二维数组
int a1[3][4];
int **a2=int [3][4]
分析一下,*a2说明a2是一个指针,指向什么呢?*a2的前面还有一个*,所以a2是指向一个指针的指针,它指向的指针指向一个整型变量。现在分析a2[1][1]。
a2[1]是:a2指向的指针的地址+1后的地址,该地址属于一个指针。
a2[1][0]是:上述指针指向的一个整型变量
所以a2[1][1]是:上述整型变量的地址+1,该地址属于一个整型变量。
回过头我们来看二维数组,数组的所有地址都是连续的,即使变为二维数组,上下两行的地址也是连续的。但是第二种写法,根据我们解析的,指针的地址是连续的,但是指针指向的地址是系统动态分配的,不一定连续。所以后者不是二维数组。
int a1[3][4];
int (*p)[4];
p=a1;
一维数组的时候,数组名即数组首地址。指针指向数组首地址,没毛病。
二维数组的时候,之前说二维数组是数组的数组,数组名还是数组首地址,数组中这里每个元素中有4个元素。p这个指针指向[4],[4]代表是一个有四个元素的数组,前面的变量类型为int,说明p指向一个有4个整型元素的数组。
假如写成了这样:
int *p[4];
意思就变了。p先和括号结合:p[4],代表一个有4个元素的数组,*代表这四个元素都是指针类型,int表示这些指针分别指向一个整型变量
昨天重修听老师说,二维数组可以忽略行数,但必须强调列数。当时老师的解释是:否则数组会不知道如何分配这些元素。
所以说参数中有二维数组的函数要这样写:
int func1(int a[][4],int n);
int func2(int(*p)[4],int n);
根据之前的分析,上述两种都可以。另外如果只是函数声明,可以省去名字,像这样:
int func2(int(*)[4],int n);
小括号不能丢。虽然省去了名字,但名字实际还是在的,否则就会变成我们之前分析过的那种错误写法。
字符串
字符串可以这样写
char *p="hello";
char p1[]="hello";
char *p2="hello";
会发现p和p2的地址是一样的,但p和p1的地址不同。因为c语言中分常量区和栈区,前者在常量区,后者在栈区。
对于p1字符串,它的长度是6,因为字符串末尾都会有一个'\0'作为结束符号。
c++提供库运行正则表达式
#include<regex>
可以这样用。很多和python里import re之后的用法几乎一样。
#include<iostream>
#include<regex>
#include<string>
using namespace std;
int main(){
string s="abc123@abc12.xyz12";
regex r("[a-z]{1,3}[0-9]{1,3}@[a-z]{1,3}[0-9]{1,2}\.[a-z]{1,3}[0-9]{1,2}");
cout<<regex_match(s,r);
return 0;
}