数组

来源:互联网 发布:淘宝最美网红 编辑:程序博客网 时间:2024/05/17 07:44

数组是C++语言中类似于标准库vector类型的内置数据结构.与vector类似,数组也是一种存储单一数据类型对象的容器,其中每个对象都没有单独的名字,而是通过它在数组中的位置对它进行访问.

与vector类型相比,数组的显著缺陷在于:数组的长度是固定的,而且程序员无法知道一个给定数组的长度.数组没有获取其容量大小的size操作,也不提供push_back操作在其中自动添加元素.如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组空间中去. 

----------------------------------------------------------华丽的分割线------------------------------------------------------

小心:与使用标准vector类型的程序相比,依赖于内置数组的程序更容易出错而且难于调试

-----------------------------------------------------------华丽的分割线,继续往下----------------------------------------

在出现标准库之前,C++程序大量使用数组保存一组对象.而现代的C++程序则更多地使用vector来取代数组,数组被严格限制于程序内部使用,只有当性能测试表明使用vector无法达到必要的速度要求时,才使用数组.然而,在将来一段时间之内,原来依赖于数组的程序仍大量存在,因此,C++程序还是必须掌握数组的使用方法.

4.1  数组

数组是由类型名、标识符和维数组成的复合数据类型,类型名规定了存放在数组中的元素的类型,而维数则指定了数组中包含的元素个数.

------------------------------------------------------------华丽的分割线-----------------------------------------------------

注解:数组定义中的类型名可以是内置数据类型或类类型;除引用之外,数组元素的类型还可以是任意的复合类型.没有所有元素都是引用的数组

-------------------------------------------------------------华丽,继续往下----------------------------------------------------

4.1.1数组的定义和初始化

数组的维数必须用值大于等于1的常量表达式定义.此常量表达式只能包含整数字面值常量、枚举常量或者用常量表达式初始化的整型const对象.非const变量以及要到运行阶段才知道其值的const变量都不能用于定义数组的维数.

数组的维数必须在一对方括号[]内制定:

//both buf_size and max_files are const
const unsigned buf_size=512,max_files=20;
int staff_size=27;   //nonconst
const unsigned sz=get_size();   //const value not known until run time
char input_buffer[buf_size];    //ok:const variable
string fileTable[max_files+1]; //ok:constant expression
double salaries[staff_size];    //error:non const variable
int test_scores[get_size];      //error:non const expression
int vals[sz];                   //error:size not known until run time

虽然staff_size是用字面值常量进行初始化,但staff_size本身是一个非const对象,只有在运行时才能获得它的值,因为,使用该变量来定义数组维数是非法的.而对于sz,尽管它是一个const常量,但它的值也是要等到运行时调用get_size函数后才知道,因此,它也不能用于定义数组维数.另一方面,由于max_files是const变量,因此表达式max_files+1是常量表达式,编译时即可计算出该表达式的值为21.

1.显式初始化数组元素

在定义数组时,可为其元素提供一组用逗号分隔的初值,这些初值用花括号{}括起来,称为初始化列表:

const unsigned array_size=3;
int ia[array_size]={0,1,2};

如果没有显式提供元素初值,则数组元素会像普通变量一样初始化.

a.在函数体外定义的内置数组,其元素均初始化为0;
b.在函数体内定义的内置数组,其元素无初始化;
c.不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式初始化.

-----------------------------------------------------------------华丽的分割线-----------------------------------------------------------

注解:除非显式地提供元素初值,否则内置类型的局部数组的元素没有初始化.此时,除了给元素赋值外,其他使用这些元素的操作没有定义.

------------------------------------------------------------------华丽,往下---------------------------------------------------------------

显式初始化的数组不需要指定数组的维数值,编译器会根据列出的元素个数来确定数组的长度:

int ia[]={0,1,2};    //an array of dimension 3

如果指定了数组维数,那么初始化列表提供的元素个数不能超过维数值.如果维数大于列出的元素初值个数,则只初始化前面的数组元素;剩下的其他元素,若是内置类型则初始化为0,若是类类型则调用该类的默认构造函数进行初始化:

const unsigned array_size=5;
//Equivalent to ia={0,1,2,0,0}
//ia[3] and ia[4] default initialized to 0
int ia[array_size]={0,1,2};
//Equivalent to str_arr={"hi","bye","","",""}
//str_arr[2] through str_arr[4] default initialized to the empty string
string str_arr[array_size]={"hi","bye"};

2.特殊的字符数组

字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化.然而,要注意这两种初始化形式并不完全相等,字符串字面值包含一个额外的空字符(null)用于结束字符串.当使用字符串字面值来初始化创建的新数组时,将在新数组中加入空字符:

char ca1[]={'c','+','+'};    //no null
char ca2[]={'c','+','+','/0'};  //explicit null
char ca3[]="C++";            //null terminator added automatically

ca1的维数是3,而ca2跟ca3的维数则是4.为什么ca3的维数是4????????????????????????????

使用一组字符字面值初始化字符数组时,一定要记得添加结束字符串的空字符.例如,下面的初始化将导致编译时的错误:

const char ca3[6]="Daniel"; //error: Daniel is 7 elements

上述字符串字面值包含了六个显式字符,存放该字符串的数组则必须有7个元素----------6个用于存储字符字面值,而1个用于存放空字符null

3.不允许数组直接复制和赋值

与vector不同,一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组,看看下列这些操作:

int ia[]={0,1,2};  //ok:array of ints
int ia2[](ia);     //error:cannot initialized one array with another
int main()
{
 const unsigned array_size=3;
 int ia3[array_size];  //ok:but elements are uninitialized!
 ia3=ia;             //error:cannot assign one array to another
 return 0;
}

-------------------------------------------------------------华丽的分割线-------------------------------------------------------------

小心:一些编译器允许将数组赋值作为编译器扩展.但是如果希望编写的程序能在不同的编译器上运行,则应该避免使用像数组赋值这类依赖于编译器的非标准功能.

------------------------------------------------------------华丽,继续 ------------------------------------------------------------------

习题:

习题4.1  假设get_size是一个没有参数并返回int值的函数,下列哪些定义是非法的?为什么?

unsigned buf_size=1024;

a.int ia[buf_size];
b.int ia[get_size()];
c.int ia[4*7-14];
d.char st[11]="fundamental";

a中buf_size是一个变量,不能用于定义数组维数.b中get_size是函数调用,不是常量表达式,不能用于数组维数的定义.d中维数定义为11,不够,因为char类型还需要在字符串结束的时候添加一个null来结束.因此该数组需要12个元素

习题4.2   下列数组的值是什么?

strng sa[10];
int ia[10];
int main(){
 string sa2[10];
 int ia2[10];
}

sa跟sa2为元素类型string的数组,自动调用string类的默认构造函数将各元素初始化为空字符串,ia在函数体外定义,元素全部初始化为0,ia2在函数体内定义,各元素没有被初始化,值不确定

习题4.3  下列哪些定义是错误的?

a.int ia[7]={0,1,1,2,3,5,8};
b.vector<int>ivec={0,1,1,2,3,5,8};
c.int ia2[]=ia1;
d.int ia3[]=ivec;

b.vector对象不能这样初始化.c中,数组不能用另外一个数组来初始化.d中,不能用vector对象来初始化数组

习题4.4   如何初始化数组的一部分或全部元素?

定义数组时可使用初始化列表(用花括号括住的一组以逗号分隔的元素初值)来初始化数组的部分或全部元素.如果是初始化全部元素,可以省略定义数组时方括号中给出的数组维数值.如果指定了数组维数,则初始化列表提供的元素个数不能超过维数值.如果数组维数大于列出的元素初值个数,则只初始化前面的数组元素,剩下的其他元素,若是内置类型则初始化为0,若是类类型,则调用该类的默认构造函数进行初始化.字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化.

习题4.5  列出使用数组而不是vector的缺点

与vector类型相比,数组的显著缺陷在于:数组的长度是固定的,而且程序员无法知道一个给定数组的长度.数组没有获取其容量大小的size操作,也不提供push_back操作在其中自动添加元素.如果需要更改数组的长度,程序员只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组空间中去. 与使用vector类型相比,使用内置数组的程序更容易出错且难以调试