数组

1、定义和初始化内置数组:

数组是一种复合类型。数组的声明形如a【d】,其中a是数组的名字,d是数组的维度。维度说明数组中元素的个数,因此必须大于0。数组的元素个数也属于数组类型的一部分,编译的时候唯独因该是已知的。也就是说,维度必须是一个常量表达式。

默认情况下,数组的元素被默认初始化。

数组的元素为对象,因此不存在引用的数组。

对数组进行列表初始化时,可以忽略数组的维度,编译器自己会推断出来。

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

一些编译器支持数组的赋值,这就四所谓的编译器扩展。

int * a[10];//a是含有10个整形指针的数组

不存在引用的数组。

int (*a)[10]=&arr;//a指向一个含有10个整数的数组。

int (&a)[10]=arr;//a引用一个含有10个整数的数组。

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

char ca[]={"c","+","+","+"};//并没有以空字符结尾

cout<<strlen(ca)<<endl;//严重错误,ca没有以空字符串结尾。

谨记,当使用数组的事后其实真正用的是指向数组首元素的指针。因此,上面的if条件实际上比较的两个const char * 的值。

2、显示初始化数组元素:

可以对数组元素进行列表初始化,此时允许忽略数组的维度。如果在声明时没有指明维度,编译器会根据初始值的数量计算并推测出来、相反,如果指明了维度,那么初始值的总数量不因该超出指定的大小。如果维度比提供的初始值数量大,则用提供的初始值初始化考前的元素,剩下的元素被初始化成默认值。

1
int a[4]={1,2,3};//等价于a[4]={1,2,3,0};

3、字符数组的特殊性:

字符数组有一种额外的初始化方式,我们可以用字符串字面值对此类数组初始化。当使用这种方式时,一定要注意字符串值的结尾处还有一个空字符,这个空字符也会向字符串的其他字符一样被拷贝到字符串数组中去。

1
2
3
4
char a[]={"c","+","+"};//列表初始化,没有空字符
char a{}={"c","+",""};//列表初始化,还有显示的空字符
char a[]="c++";//自动添加表示字符串结束的空字符
const char a[6]="daniel";//错误没有空间可存放空字符

尽管看起来daniel有6个字符,但是数组的大小必须至少是7,其中6个位置存放字面值的内容,另外一个存放结尾处的空字符。

4、不允许拷贝和赋值:

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

1
2
int a[]={1,3,2};//含有3个整数的数组
int a[]=a;//错误,不允许使用一个数组初始化另一个数组

5、理解复杂的数组声明:

和vector一样,数组能存放大多数类型的对象。可以存放指针类型的对象,所以允许定义数组的指针记数组的引用。在这几种情况中,定义存放指针的胡祖比较简单和直接,但是定义数组的指针或者数组的引用就稍微复杂一点了。

6、访问数组元素;

数组和vector和string一样,数组的元素也可以使用范围for语句,下标运算符来访问。

7、指针和数组:

在C++语言中,指针和数组有着非常紧密的联系,就如:使用数组的时候编译器一般会把他转换成指针。

通常情况下,使用去地址符,来获取某个指向某个对象的指针,区地址可以用于任何对象,对数组使用下标运算符得到该数组制定的位置的元素。因此像其他对象一样,对数组元素使用取地址符就能得到指向该元素的指针。

1
2
string nums[]={"ws","wc"};
string * p=&nums[0];//p指向nums的第一个元素

然而数组还有一个特性,在很多用到数组名字的地方,编译器都会自动的将其替换为一个指向数组首元素的指针。

1
string *p=nums;

在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。

由上可知,在一些情况下数组的操作实际上是指针的操作,这一结论有很多隐含的意思。其中一层的意思是当使用一个auto变量的初始值时,推断得到的类型是指针而不是数组。

8、指针也是迭代器:

指向指针元素的指针拥有更多的功能。vector和string的迭代器,支持的运算,数组的指针全部都支持。允许使用递增运算符将指向数组元素的指针向前移动到下一个位置。

9、标准库函数begin和end:

尽管能计算得到为后指针,但这种方法极易出错。为了让指针的使用更加简单,安全,C++引入了两个名为begin和end的函数。这两个函数与容器中两个同名成员功能相似。不过数组不是类类型,因此这两个函数不是成员函数。正确的使用形式是将数组作为他们的参数。

1
2
3
int a[]={1,2,3,4};//定义了一个含有4个整数的数组
int * p=begin(a);//指向数组首元素的指针
int * b=end(a);//指向数组尾的下一个元素的指针

使用begin和end可以很容易的写出一个循环并处理数组中的元素。

注意:一个指针如果指向了某种内置类型数组的尾元素的“下一位置”,则其具备与vector的end函数返回的与迭代器类似的功能。尾后指针不能执行解引用和递增操作。

在很多情况下,使用数组的名字其实用的是一个指向数组首元素

的指针。

10、C风格字符串。

字符串字面值是一种通用的结构的实例,这种结构即使C++由C继承而来的C风格字符串。C风格字符串不是一种类型,而是为了表达和使用字符串形成的一种约定俗成的写法。

C标准库string函数:

strlen(p) 返回p的长度
strcmp(p1,p2)

比较p1和p2的相等性

strcat(p1,p2) 将p2附加到p1之后
strcpy(p1,p2) 将p2拷贝给p1,返回p1

11、与旧代码的接口:

很多C++程序员在标准库出现之前就已经写成了,他们坑定没有想到string和vector类型.而且,有一些C++程序实际上是与C语言的接口程序,当然也无法使用C++标准库。因此,现代的C++程序不得不与那些充满了数组或C风格字符串的代码衔接,为了使这一工作简单易行,C++转梦提供了这一组功能。

混用string对象和C风格字符串:

string s("hello world");//s的内容是hello world

不能用string对象直接初始化指向字符的指针。为了完成该功能,string专门提供了一个名为c_str的成员函数。

char * str=s;//错误,不能使用string对象来初始化char × 对象

const char * str=s.c_str();//正确,

顾名思义,c_str函数的返回值是一个c风格的字符串。也就是说,函数的返回结果是一个指针,该指针指向一个空字符结束的字符数组,而这个数组所存的数据恰好与那个string对象一样,结果指针的类型是const char* ,从而确保我们不会改变字符数组的内容。

使用数组初始化vector对象:

我们知道一个数组不可以为另一个数组赋值,但是允许私用数组来初始化vector对象。要实现这一目的,只需指名要拷贝的区域的首元素地址和尾后地址就行了。

1
2
3
int a[]={1,2,3};
vector<int>ivec(begin(a),end(a));
//ivec有3个元素,分别是a中对应的元素的副本

在上述代码中,用于创建ivec的两个指针实际上指明了用来初始化的值在数组a中的位置,其中第二个指针应指向待拷贝区域尾元素的下一位置。此列中使用了标准库函数gegin和end来分别计算a的首指针和尾指针。

注意:使用指针和数组很容易出错。部分原因是概念上的问题:指针常用于底层操作,因此容易引发一些与细节有关的问题。

现代的c++程序,应当尽量使用vector和迭代器,避免使用内置数组和指针,应该尽量使用string类型,避免使用C风格的基于数组的字符串。

12、多维数组:

严格说来,在C++语言中没有多维数组,多维数组其实就是数组的数组。

当一个数组的元素仍然是数组时,通常使用两个维度来定义它,一个维度表示数组本身大小,另外一个维度表示其元素(数组)的大小。

当一个数组的元素仍然是数组时,通常使用两个维度来定义它,一个维度表示数组本身大小,另外一个维度表示其元素(也是数组)的大小。

int a[3][4]//大小为3的数组,每个元素都是含有4个整数的数组。

int a[10][20][30]=0;//将所有元素初始化为0;

大小为10的数组,每个元素都是大小为20的数组,这些数组是含有30个整数的数组。

实际上,定义数组时对下表运算符的数量并没有限制,因此只要愿意就可以这样定义一个数组,他的元素是数组,下一级数组的元素还是数组,在下一级数组的元素还是数组,以此类推。

对于二维数组来说,通常把第一个维度称作行,第二个维度称作列。

13、多维数组的初始化:

允许使用花括号括起来的一组值初始化多维数组,这点和普通的数组一样。下面初始化形式中,多维数组的每一行分别用花括号括了起来:

实际上,内层的花括号并不是必须要的,例如,下面的初始化语句,形式上更为简洁,完成的功能和上面的这段代码完全一样:

类似于一位数组,在初始化多维数组是也并非所有元素的值都必须包含在初始化列表之内。如果仅仅想初始化每一行的第一个元素,通过下面的方式即可;

int a[2][3]={{0}{3}};//其他初始化的元素执行默认初始化,这个过程和一位数组一样。在这种情况下在省掉内层的花括号,结果就大不一样了。

int a[2][3]={0,3};//这样仅仅初始化了第一行的元素,其他元素被初始化为0

14、多维数组的下标引用:

可以使用下标运算符来访问多维数组的元素,此时数组的每个维度对应一个下表运算符。

如果表达式含有的下标运算符数量和数组一样多,该表达式的结果将是给定类型的元素;反之表达式含有的下标运算符数量比数组的维度小,则表达式的结果将给定索引处的一个内层数组;

在程序中经常会用到使用两层嵌套的for循环来处理多维数组的元素;外层的for循环遍历ia的所有元素,注意这里的元素是一位数组;内层的for循环则遍历那些一维数组的整数元素;

15、使用范围for语句处理多维数组。

由于在C++11新标准中新增了范围for语句,所以前一个程序可以简化为如下形式:

1
2
3
4
5
size_t cnt=0;
for(auto &row:a)//对于外层数组的每一个元素
    for(auto &col:row)//对于内层数组的每一个元素
        col=cnt;//将下一个值赋给该元素
        ++cnt;//将cnt+1

注意:要使用for语句处理多维数组,除了最内层的循环之外,其他的所有循环的控制变量都是引用类型。

16、指针和多维数组:

当程序使用多维数组的名字时,也会将其转换成指向数组首元素的指针。

定义指向多维数组的指针时,千万别忘了这个多维数组实际上就是数组的数组。

应为多维数组实际上就是数组的数组,所以有多维数组名转换得来的指针实际上是指向第一个内层数组的指针。

int a[3][4];//实际上是大小为3的数组,每个元素都是含有4个整数的数组。

int (*p)[4]=a;//p指向了含有4个整数的数组

p=&a[2];//p指向了a的尾元素

根据以前的策略:我们首先明确,(×p)意味着p是一个指针。接着观察右边发现,指针p所指的是一个维度为4的数组;在观察左边知道,数组中的元素是整数。因此,p就是指向含有4个整数的数组的指针。

注意:数组是一种类似于标准库类型vector的数据结构,但又与vector有所不同。与vector不同的地方是,数组的大小确定不变,不能随意的想数组增加元素。由于数组的大小固定,因此对某些特殊的应用程序来说程序的性能很好,但是相应的也损失了一些灵活性。

不能将数组的内=内容作为拷贝给其他的数组作为初始值。也不能用数组为其他数组赋值。不存在引用的数组。

原文地址:https://www.cnblogs.com/yjds/p/8597229.html