第4章 数组和指针
C++程序应尽量使用vector 和 迭代器类型,避免使用低级的数组和指针
4.1 数组
数组是由 类型名、标识符 和 维数 组成的复合数据类型,类型名规定了存放在数组中的元素的类型,维数 指定 数组中包含的元素个数,数组的维数必须用值大于等于1的常量表达式定义,此常量表达式只能包含 整形字面值常量、枚举常量 或者用常量表达式初始化的 整形const对象
在函数体外定义的内置数组,其元素均初始化为0,在函数体内 定义的内置数组,其元素无初始化
如果指定了数组维数,那么初始化列表提供的元素个数不能超过维数值,如果维数大于列出的元素初值个数,则只初始化前面的数组元素,剩下的其他元素,若是内置类型则初始化为0,若是类类型则调用该类的默认构造函数进行初始化
不允许数组直接复制和赋值,数组下标的正确类型是 size_t
4.2 指针
指针 是指向某种类型对象的复合数据类型,是用于数组的迭代器,指向数组中的一个元素(保存元素的地址),对指针进行解引用操作,可获得该指针所指向对象的值
指针用于指向对象,具体来说,指针保存的是另一个对象的地址,取地址操作符&只能用于左值,因为 只有当变量用作左值时 ,才能取其地址,理解指针声明语句时,请从右向左阅读,将符号 * 紧贴着指针变量名放置不易引起误解
一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址,指向某个对象后面的另一个对象,或者是 0值
除非所指向的对象已经存在,否则不要先定义指针,如果必须分开定义指针和其所指向的对象,则将指针初始化为0(字面值0,或者在编译时可获得0值的const量,或者C++语言从C语言中继承下来的预处理变量 NULL,该变量在cstdlib头文件中定义,其值为0)
C++提供了一种特殊的指针类型void*,它可以保存任何类型对象的地址,void*指针支持的操作:与另一个指针进行比较,向函数传递void*指针或从函数返回void*指针,给另一个void*指针赋值
解引用操作符,返回指定对象的左值 ,如果对左操作数进行解引用,则修改的是指针所指对象的值,如果没有使用解引用操作,则修改的是指针本身的值
在表达式中使用数组名时,该名字会自动转换为指向该数组第一个元素的指针,如果希望使指针指向数组中的一个元素,可使用下标操作符给某个元素定位,然后用取地址操作符&获取该元素的存储地址
指针的算术操作:指针上加上或减去一个整形数值,两个指针做减法
在指针上加上一个整形数值,其结果仍然是指针,允许在这个结果上直接进行解引用操作,而不必先把它赋给一个新指针,两个指针减法操作的结果是标准库类型ptrdiff_t的数据,也是一种与机器相关的类型,在cstddef头文件中定义,是signed整形
在使用下标访问数组时,实际上是对指向数组元素的指针做下标操作
指针加数组长度即可以计算出数组的超出末端指针,C++允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作
允许把非const对象的地址赋给指向const对象的指针,不能用指向const对象的指针修改基础对象,然而如果该指针指向的是一个非const对象,可用其他方法修改其所指向的对象,指向const的指针常用作函数的形参,确保传递给函数的实际对象在函数中不因为形参而被修改
与任何const量一样,const指针也必须在定义时初始化,任何企图给const指针赋值的行为即使给指针赋回同样的值,都会导致编译时的错误
指向const对象的const指针,既不能修改指针所指向对象的值,也不允许修改该指针的指向
4.3 C风格字符串
4.4多维数组
C++中没有多维数组,通常所指的多维数组其实就是 数组的数组
//array of size 3, each element is an array of ints of size 4 int ia[3][4];
如果 数组的元素 又是 数组,则称为二维数组,其每一维对应一个下标,第一维称为行,第二维则称为列,C++并未限制可用的下标个数,也就是说,可以定义元素是数组(其元素又是数组,以此类推)的数组
为了对多维数组进行索引,每一维都需要一个下标,当需要访问数组中的特定元素时,必须提供其行下标和列下标,行下标指出需要哪个内部数组,列下标则选取该内部数组的指定元素
使用 多维数组名 时,实际上将其自动转换为指向该数组第一个元素的指针
#include<stdio.h> int main() { int arr[2][3] = { 1,2,3, 4,5,6 }; int(*q)[3] = &arr[0]; //int(*q)[3] = arr; //arr 自动转换为,指向,该数组第一个元素( arr[0] )的地址 //arr[0] 是一维数组名,一维数组元素的首地址,*arr[0]即arr[0][0] 元素为1 //int *p = arr[0]; p++; printf("%d",*p); q++; printf("%d",**q); return 0; }
#include<stdio.h> int main() { int arr[2][3] = { 1,2,3, 4,5,6 }; typedef int int_arr[3]; //定义类型为int[3]的新的类型为int_arr int_arr *q = &arr[0]; // int(*q)[3] //遍历二维数组 arr for( ; q != arr+2; ++q ){ //q++ q 保存的是行的地址 for( int* p=*q; p != *q+3; ++p ){ //*q 解引用是行的地址 printf("%d ", *p ); } printf("\n"); } return 0; }
#include<stdio.h> int main() { int arr[2][3] = { 1,2,3, 4,5,6 }; int(*q)[3] = &arr[0]; //取arr第一个元素的地址 //int(*q)[3] = ( int(*)[3] ) arr[0]; int*p = *q; //一维指针的指向,即arr第一个元素的地址 //int* p = arr[0]; //打印结果一样 printf("%p\n",arr[0]); //第一个元素的地址 printf("%p\n",&arr[0]); //取第一个元素的地址 printf("%p\n",p); //一维指针的指向 printf("%p\n",q); //行指针的指向 return 0; }