您的位置:首页 > 编程语言 > C语言/C++

C++Primer (第四版) 第四章 数组和指针

2014-02-21 00:05 513 查看
第四章 数组和指针

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

4.1数组

数组声明应指出以下三点:

@ 存储在每个元素中的值的类型

@ 数组名

@ 数组中的元素数

声明数组的通用格式:

typeName arrayName[arraySizee];表达式 arraySize 指定元素数目,它必须是整型常数(如10)或 const 值,也可以是常量表达式(如 8*sizeof(int)),即 arraySize 不能是常量。

arraySize >= 1;arraySize 须为 整型字面值常量、枚举常量或者用常量表达式初始化的整型 const 对象。

//both buf_size and max_files are const
const unsigned buf_size = 512, max_files = 20;
int staff_size = 27; //non const
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

显示初始化数组元素

@ 在函数体外定义的内置数组,其元素均初始化为0

@ 在函数体内定义的内置数组,其元素无初始化

@ 不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式的初始化。

对于下标访问: vector 使用 vector::size_type 作为下标类型, 而数组下标的正确类型是 size_t 。

检查数组下标:除了程序员自己注意细节,并彻底测试自己的程序之外,没有别的方法可以防止数组越界。 (buffer overflow :缓冲区溢出)

4.2 指针

指针:用于指向对象。 即:指针保存的是另一个对象的地址。

string s("hello world");
string *sp = &s;

指针的阅读:从右向左阅读

string *pstring;  把 pstring 定义为一个指向 string 类型对象的指针变量

对指针进行初始化或者赋值只能使用以下四种类型的值:

(1) 0值常量表达式。

(2) 类型匹配的对象的地址。

(3) 另一对象之后的下一地址。

(4) 同类型的另一个有效指针。

int ival;
int zero = 0;
const int c_ival = 0; //error: pi initialized form int value of ival
int *pi = ival; //error: pi assigned int value of zero
pi = zero; //ok: c_ival is a const with compile-time value of 0
pi = c_ival; //ok: directly initialize to literal constant 0
pi = 0;

int *pi2 = NULL; //ok: equivalent to int *pi2 = 0;
void* 指针

void* 指针:它可以保存任何类型对象的地址。

double obj = 3.14;
double *pd = &obj;
//ok: void* can hold the address value of any data pointer type
void *pv = &obj;	//obj can be an object of any type
pv = pd;		//pd can be a pointer to any type

void* 表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。

void* 指针只支持几种有限的操作:与另一个指针进行比较; 向函数传递 void* 指针或从函数返回 void* 指针; 给另一个 void* 指针赋值。

不允许使用 void* 指针操纵它所指向的对象。

关键概念:给指针赋值 或 通过指针赋值



引用与指针的区别:

<1>引用必须初始话

<2>不存在指向空值的引用,但存在指向空值的指针

<3>引用一旦初始化就无法对其进行修改(从一而终)

指向指针的指针:

int ival = 1024;
int *pi = &ival;
int **ppi = π




下标与指针:

int ia[] = {0,2,4,6,8};
int i = ia[0]; //ia points to the first element in ia

int *p = &ia[2]; //ok: p points to the element indexed by 2
int j = p[1]; //ok: p[1] equivalent to *(p+1),
// p[1] is the same element as ia[3]
int k = p[-2]; //ok: p[-2] is the same element as ia[0]

输出数组元素:

const size_t arr_sz = 5;
int int_arr[arr_sz] = {0,1,2,3,4};
//pbegin points to first element, pend points just after the last
for (int *pbegin = int_arr, *pend = int_arr+arr_sz; pbegin != pend; ++pbegin)
cout<<*pbegin<<' '; //print the current element


指针和 const 限定符:

指向 const 对象的指针 

//指向 const 对象的指针
const double *cptr; //cptr may point to a double that is const
//(cptr是一个指向 double 类型 const 对象的指针)
*cptr = 42; //error: *cptr might be const

//把一个 const 对象的地址赋给一个普通的、非 const 对象的指针也会导致编译时错误
const double pi = 3.14;
double *ptr = π //error: ptr is a plain pointer
const double *ptr = π//ok: cptr is a pointer to const

//不能使用 void* 指针保存 const 对象的地址,而必须使用 const void* 类型的指针保存 const 对象的地址:
const int universe = 42;
const void *cpv = &universe; //ok: cpv is const
void *pv = &universe; //error: universe is const
//允许把 非const 对象的地址赋给指向 const 对象的指针:
double dval = 3.14; //dval is a double; its value be changed
cptr = &dval; //ok: but can't change dval through cptr

dval = 3.14159; //dval is not const
*cptr = 3.14159; //error: cptr is a pointer to const
double *ptr = &dval;//ok: ptr points at non-const double
*ptr = 2.72; //ok: ptr is plain pointer

const指针(本身的值不能够修改)

int errNum = 0;
int *const curErr = &errNum; //curErr is a constant pointer
//(read: curErr 是指向 int 型对象的 const 指针)

指向 const 对象的 const 指针

const double pi = 3.14159;
//pi_ptr is const and points to a const object
const double *const pi_ptr = π //pi_ptr and *pi_ptr 均不可修改


指针和 typedef (注意)

typedef string *pstring;
const pstring cstr;
//我们理解为:
const string *cstr; //wrong interpretation of const pstring cstr
//也就是说,const pstring 是一种指针,指向 string 类型的 const 对象,但这是错误的。
/*
错误的原因在于将 typedef 当做文本扩展了。声明 const pstring 时,
const 修饰的是 pstring 类型,这是一个指针。因此,该声明语句应该是把
cstr 定义为指向 string 类型对象的 const 指针,这个定义等价于:
*/
//cstr is a const pointer to string
string *const cstr; //equivalent to const pstring cstr;
//建议:理解复杂的 const 类型的声明
string const s1;	//s1 and s2 have same type
const string s2;	//they're both strings that are const

string s;
typedef string *pstring;
const pstring cstr1 = &s; //written this way the type is obscured
pstring const cstr2 = &s; //all three decorations are the same type
string *const cstr3 = &s; //they're all const pointers to string

const int ic = 1;
int *const cpi = ⁣
//error: cpi 是一个指向 int 型对象的指针,不能用 const int 型
//对象 ic 的地址对其进行初始化 (cpi:int* const   &ic:const int*)


初始化动态分配的数组

string *psa = new string[10];	//array of 10 empty strings
int *pia = new int[10];	//array of 10 uninitialized ints
int *pia2 = new int[10]();	//array of uninitialized ints
//注:对于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像
//数组变量一样,用初始化列表为数组元素提供各不相同的初值


const 对象的动态数组 (用处不大)

//error: uninitialized const array
const int *pci_bad = new const int[100];
//ok: value-initialized const array
const int *pci_ok = new const int[100]();
const string *pcs_ok = new const string[100];


允许动态分配的数组

size_t n = get_size();
int *p = new int
;
for (int *q=p; q!=p+n; ++q)
/*process the array*/

char arr[0];
char *cp = new char[0];
//注:C++虽然不允许定义长度为 0 的数组变量,但明确指出,
//调用 new 动态创建长度为 0 的数组是合法的。
动态空间的释放

delete [] pia;


//使用数组初始化 vector 对象
const size_t arr_size = 6;
int int_arr[arr_size] = {0, 1, 2, 3, 4, 5};
vector<int> ivec(int_arr, int_arr+arr_size);
//被标出的元素可以是数组的子集
//copies 3 elements: int_arr[1], int_arr[2], int_arr[3]
vector<int> ivec2(int_arr+1, int_arr+4);

//多维数组 之 指针与多维数组
//定义指向多维数组的指针时,千万别忘了该指针所指向的多维数组其实是数组的数组
int ia[3][4] = {{0,0,0,0},{1,1,1,1},{0,0,0,0}};
//array of size 3, each element is an array of ints of size 4
int (*ip)[4] = ia; //ip points to an array 4 ints
ip = &ia[2]; //ia[2] is an array of 4 ints
//理解(由内而外阅读):*ip是int[4]类型——即 ip 是一个指向含有 4 个元素的数组的指针

//下面的声明中,圆括号必不可少
int *ip[4]; //array of pointers to int
int (*ip)[4]; //pointer to an array of 4 ints

//用 typedef 简化指向多维数组的指针
typedef int int_array[4];
int_array *ip2 = ia;
for (int_array *p = ia; p != ia+3; ++p)
for (int *q = *p; q != *p + 4; ++q)
cout<< *q << endl;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: