3.5数组

Tip: 不清楚元素的确切个数,请使用vector

 

3.5.1 定义和初始化内置数组

数组是一种复合类型

 unsigned cnt = 42;

 constexpr unsigned sz = 42;

 int arr[10] ;//含有十个整数的数组

 int *parr[sz];  //含有42个整形指针的数组

 string bad [cnt];//错cnt不是常量表达式

 string strs[get_size()]//当get_size是constexpr时正确;否则错误

waning:和内置类型的变量一样,如果函数内部定义了某种内置类型的数组,那么默认初始化会令数组含有未定义的值

 

不允许用 auto定义数组

和vector一样,元素都是对象不能有引用

 

显示初始化数组元素

如果维度比初始值大,初始化靠前的元素,剩下初始化为默认值

 const unsigned sz = 3;

 int ial[sz] = {1,2,3}

 int a3[5] = {0,1,2} // 等价于 0 1 2 0 0

字符数组的特殊性

字符串字面值的结尾有一个空字符,这个空字符也会想字符串的其他字符一样被拷贝到字符数组中去

 char a1[] = {'C','+','+'} //列表初始化没有空字符        维度是3

 char a2[] = {'C','+','+','\0'} //列表初始化,含有显示的空字符  维度是4

 char a3[] = {"C++"}; // 自动添加空字符                     维度是4

 char a4[6] = {"Danial"} // 错误:无处存放空字符

不允许拷贝和赋值

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

 int a2[] = a;

 a2 = a;

Warning 一些编译器支持数组的赋值,也就是编译器扩展(compiler extension)

一般来说避免使用非标准特性,可能在其他编译器上无法工作

 

理解复杂的数组声明

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

 int &refs[10] = /*?*/;  //错误:不存在引用的数组

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

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

 

 int *(&arry)[10] = ptrs;// arry是数组的引用,该数组含有10个指针

 

Tip:想要理解数组声明的含义,最好的办法是从数组的名字开始按照由内向外的顺序阅读

 

3.5.2 访问数组元素

 

数组也能用范围for语句或下标运算符来访问

在使用数组下标的时候,通常将其定义为 size_t 类型

 size_t 是一种机器相关的无符号类型,被设计的足够大表示内存中任意对象的大小

 在cstddef 头文件中定义了 size_t

数组下标是由c++语言直接定义的

容器下标是库模板vector定义的,只能用于vector类型的运算对象

检查下标的值

 

warning: 大多数常见的安全问题都源于缓冲区溢出错误。当数组或其他类似数据结构的下标越界并试图访问非法内存区域时,就会产生此类错误

 

3.5.3 指针和数组

使用数组的时候编译器一般会把它转换成指针

很多用到数组名字的地方,编译器会自动地将其替换成为一个指向数组首元素的指针

 string *p2 = nums; // 等价于 p2 = &nums[0]

 

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

 

 int ia[] = {0,1,2,3,4,5,6,7,8,9}//ia是一个含有十个整数的数组

 auto ia2(ia); //ia2是一个整形指针,指向ia的第一个元素

 ia2 = 42; //错误,ia2是一个指针

 实际执行时是

 auto ia2(ia[ 0 ]); // 显然ia2的类型是int*

当使用decltype关键字的时候不会发生转换

 decltype( ia ) ia3 = {0,1,2,3,4,5,6,7,8,9};

 ia3 =p; // 错:不能给整形指针赋值

指针也是迭代器

vector和string的迭代器支持的运算,数组的指针全部支持

 arr[10] = {};

 int *e = &arr[10]//指向arr尾元素的下一位置的指针

 for(int *b = arr; b!=e; ++b)

 cout << *b << endl; //输出arr的元素

标准库函数begin和end

这两个函数和vector的两个同名函数功能类似,因为数组不是类类型,使用形式不同

 int ia[ ] = {0,1,2,3,4,5,6,7,8,9};//ia是一个含有10个整数的数组

 int *beg = begin(ia);

 int *last = end(ia);

寻找arr中第一个负数

 int *pbeg = begin(arr), *pend = end(arr);

 while (pbeg!= pend && *pbeg >=0)

++pbeg;

Note : 特别注意,尾后指针不能执行解引用和递增操作

指针运算

指向数组元素的指针和迭代器的运算操作完全相同(见前表)

 auto n = end(arr) - begin(arr);//n的值就是arr中元素的数量

两个指针相减的结果的类型是一种名为ptrdiff_t的标准库类型

和 size_t一样,ptrdiff_t 也是定义在cstddef头文件的机器相关的类型,带符号

解引用和指针运算的交互

 int last = *(ia + 4);//正确:ia[4]的值

要加圆括号

下标和指针

 int *p = &ia[2];    //p指向索引为2的元素

 int j = p[1];           //p[1]等价于*(p+1),就是ia[3]

 int k = p [-2];          // ia[0]

Warning: 标准库限定使用的下表类型是无符号型

内置下标运算符所用的索引值不是无符号类型,和string和vector不一样

 

3.5.4 C风格字符串

warning:尽管C++支持C风格字符串,但在C++程序中最好不要用

C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法

习惯字符串存放在字符数组中并以空字符结束

C标准库String函数

 

定义在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

 

warning:这些函数不负责验证其字符串参数

 

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

 char ca[] = {'C','+','+'};    //不以空字符结束,这类不行!

比较字符串

如果把c++运算用在c风格上

 const char ca1[] = "A string example";

 const char ca2[] = "A different string";

 if(ca1 <ca2)   // 未定义的:试图比较两个无关地址

实际上是两个 const char* 比较,两个指针指向并非同一对象,得到结果未定义

目标字符串的大小由调用者指定

c++风格

 string largeStr = s1 + " "+s2;

 如果用c就是两个数组相加,没有意义且非法

正确方法用 strcat和 strcpy

Tip:对大多数应用来说,使用string更安全

 

3.5.5 与旧代码的接口

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

若在某处需要一个c风格的字符串

 char *str = s;//错误 : 不能用string对象初始化 char*

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

 string中的一个名为c_str的成员函数返回值是一个C风格的字符串

函数返回结果是一个指针,指针指向一个以空字符串结束的字符数组

warning: 如果执行完 c_str() 函数后程序一直都能使用其返回的数组,最好将该数组重新拷贝一份

 

使用数组初始化vector 对象

不允许使用一个数组为另一个内置类型的数组赋初始值,也不允许vector对象初始化数组。

相反的允许使用数组来初始化vector对象,

只需指名要拷贝区域的首元素地址和尾后地址就可以

 vector<int> ivec(begin(int_arr),end(int_arr));

//拷贝三个元素: int_arr[1],int_arr[2],int_arr[3];

 vector<int> subVec(int_arr +1, int_arr + 4);

3个元素的值来自 【1】,【2】,【3】

建议:尽量使用标准库类型而非数组

尽量用vector和迭代器少用数组指针

尽量用string少用c风格的字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值