PS,1880后程序员

看不完的牙,写不完的程序,跑不完的步。
随笔 - 97, 文章 - 34, 评论 - 10, 引用 - 0
数据加载中……

C++ Primer 之 读书笔记 第四章

 

第四章数组和指针

Arrays and Points

vectorarray类似的地方就是它们都是同一对象类型的集合。不同点是array是固定长度的。iterator之于vector就如同指针之于array

使用指针的一个重要原因是vector不能提供所需的访问速度。

数组类型不能是引用(reference

4.1 Array

关于Array初始化:

l         使用class默认的构造函数初始化每个单元。

l         Character Array即可以用字符数组来初始化也可以用string来初始化,注意如果用string,那么自动在末尾追加了null作为结束符,这样数组的长度+1.

下标操作时,要使用数据类型是:size_t,就像在vector中使用size_type

for (size_t ix = 0; ix != array_size; ++ix)

                    ia[ix] = ix;

4.2 Pointers

什么是指针

Pointers are iterators for arrays.指针是用于数组的迭代器。

pointer holds the address of another object:。具体来说,指针保存的是另一个对象的地址。

string *sp = &s; // sp holds the address of s

*sp里面*代表sp是一个指针。

Best practice:指针初始化时,如果不能指向具体的地址,就设置为0,这样在程序中就可以检测出指针没有指向一个对象(object)。

指针初始化和赋值操作的约束

指针初始化和赋值

只有4类值可以初始化指针和指针赋值:

1.值为0的常量表达式。不能把任何的int赋值给指针,即使这个int的值是0,但是可以把值是0const 或者数值0赋值给指针。NULL定义为0,所以也可以使用。NULL叫做预处理变量。

int *pi = NULL

2.类型匹配的对象的地址

3.另一对象末的下一地址

4.同类型的其它有效的指针

void*指针,这是一个特殊类型的指针,它能够是任何对象的地址。它就是说明它的值是一个指针,但是指针所指向的对象的类型是不可知的。

因此void*指针只能执行通用的操作:

l         指针比较

l         传递给function或者作为function的返回值。

l         赋值给另一个void*指针

Operations on Pointer(指针操作)

注意*在这里是一个operatordereference a pointer。解引用操作(dereference operator)返回指定对象的左值lvalue。因此可以进行赋值操作。

引用和指针的区别:

1.        引用总是指向对象object。引用必须初始化,但指针是可以仅仅定义,而无需初始化的。

2.        赋值:引用的赋值会改变引用所绑定的对象的值;引用是不能重新绑定新的对象的。一旦初始化,引用总是指向同一个对象。

引用:

int &ri = ival, &ri2 = ival2;

ri = ri2;    // assigns ival2 to ival这里riri2还是指向2个不同的地址单元

指针:

int ival = 1024, ival2 = 2048;

int *pi = &ival, *pi2 = &ival2;

pi = pi2;    // pi now points to ival2pipi2都指向了同一个地址单元

指向指针的指针**ppi,代码:

int ival=1024;

int *pi = &ival;

int **ppi=π

int *pi2 =*ppi; //或者 int *pi2 = pi;

ppi解引用2次,就可以得到ival的值了。

1.        使用指针访问数组单元

当使用数组的名字时,这个名字就自动转换为指向数组第一个单元的指针。

int ia[] = {0,2,4,6,8};

int *ip = ia; // ip points to ia[0] 定义ip是指针,赋值为ia

指针的算数运算会产生一个新指针。

两指针相减得到的数据类型是ptrdiff_t。它是一个

int last = *(ia + 4); // ok: initializes last to 8, the value of ia[4]

如何获得一个数组的结尾?

const size_t arr_size = 5;

int arr[arr_size] = {1,2,3,4,5};

int *p = arr;           // ok: p points to arr[0]

int *p2 = p + arr_size; // ok: p2 points one past the end of arr

p2就是指向了数组的结尾。

指向const对象的指针和const指针

1.        指向const对象的指针

如果指针指向的是一个const对象,那么肯定不希望它能够修改这个const对象的值。那么这样的指针如何定义?

const double *cptr; //cptr是指向const double类型的指针

对于这个定义的理解是这样子的:

A.        这里的限定词(qualifier-const是限定cptr指向的数据类型必须是const double,而不是限定cptr本身。

B.        cptr本身不是const

C.       不能做的是用cptr去修改它指向的对象的值

但是也可以把指向const对象的指针赋值为非const对象的地址。(A pointer to a const object can be assigned the address of a nonconst object

int val=10;

const int *cptr = &val;

val=30;   //这样写是对的

*cptr = 30; //这样写会死人的L

不过我想,这只不过是代码上的文字游戏而已,如果程序这样写,也许会死人的。混乱!

这种指针的用途是作为方法的参数,这可以保证这个参数不会在方法中被修改。(哎,要不怎么说是大师呢,佩服!)

2.        const指针

const指针的值是不可以修改的,但是const指针指向的对象的值是可以修改的。

int errNumb = 0;

int *const curErr = &errNumb; // curErr is a constant pointer

*curErr = 0; // ok: reset value of the object to which curErr is bound

3.        指针和typedef

复习:

typedef 可以用来定义类型的同义词。wages就是double的同义词

typedef double wages;       // wages is a synonym for double

(以下的这段很饶人啊)

typedef string *pstring; //pstringstring的同义词;并且pstring是指针类型

const pstring cstr; //这是指向stringconst指针,而不是指向const string的指针

第一绕:pstring类型是指向string类型的指针类型。

第二绕:const是用来修饰pstring类型的,const pstring就是conststring指针

第三绕:这不存在简单的文字替换的游戏:const pstring cstr;等于const string* cstr;所以就是指向const string的指针。错误!

4.3 C风格字符串

不建议在C++中使用C风格的字符串,原因是它有“many many”的安全问题。

1.        什么是C风格的字符串?

它不是一种类型,而是以空字符 null 结束的字符数组。

定义:

char ca2[] = {'C', '+', '+', '"0'}; // explicit null

char ca3[] = "C++";     // null terminator added automatically

const char *cp = "C++"; // null terminator added automatically

char *cp2 = ca2;   // points to first element of a null-terminated char array

遍历字符串

const char *cp = "some value";

while (*cp) {

    // do something to *cp

    ++cp;

}

2.        字符串函数

C标准库提供了一系列的字符串函数,但是这些函数都不检查参数的合法性(限制条件)。这就是Lippman不建议在C++中使用C风格的字符串的原因。

主要的限制:

1.        传递给这些标准库函数的指针必须是非空的。

2.        每个指针必须是以null结尾的。

3.        数组的长度要足够大

strlen(s),返回的是s的长度,但是这里并不包含null,因此数组的实际长度是strlen(s)+1

3.        使用动态数组

为什么要使用动态数组?

通常是因为在编译时无法知道数组的维数,所以才需要动态创建该数组。

size_t n = get_size(); // get_size returns number of elements needed

int* p = new int[n];

如果是普通的定义数组,以上的定义是根本无法实现的,因为在编译期是不能确定数组的大小的。只能这样定义:

const n=45;

int p[n];

因此就可以得出结论:动态数组主要是用于当数组的尺寸不能在编译期确定的情况。

数组释放:

delete [] p ;

4.        疑问代码(P139):

我认为在const size_t len = strlen(pc +1);  这行存在笔误,应该是

const size_t len = strlen(pc )+1;

否则copy后得到的结果pc2不是C风格的字符串,因为最后一个单元的内容是’g’而不是null

const char *pc = "a very long literal string";

 const size_t len = strlen(pc +1);     // space to

 // performance test on string allocation and copy

 for (size_t ix = 0; ix != 1; ++ix) {

     char *pc2 = new char[len + 1]; // allocate the space

     strcpy(pc2, pc);               // do the copy

     cout << "pc2=" << pc2 << endl;

     cout << "pc2[25]=" << (pc2+25) << endl;

     delete [] pc2;                 // free the memory

 }

4.4多维数组 Multidimensioned Arrays

C++实际是没有多维数组的,

int ia[3][4]

可以理解为数字大小是3,每个单元element又是一个大小是4int数组。或者叫做33列。

1.        指针和多维数组

这段代码就如同“回”字的N多种写法一样:

       int ia[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};

       //*ip是一个指针变量,它指向的是长度是4int数组。

       int (*ip)[4]=ia;

       //*ipo是一个指针数组

       int *ipo[4] ;

       ipo[2]=ia[2]; //对指针数组的单元赋值

       //*ipt就是一个最普通的指针,对指针变量赋值

       int *ipt=ia[2];

       //

       int (*ipn)[4]=ia;

       ipn=&ia[2]; //也可以写为ia+2

      

       cout << "(*(ip+2))[0]=" << (*(ip+2))[0] << endl;

       cout << "ipo[2][0]=" << ipo[2][0] << endl;

       cout << "ipt[0]=" << ipt[0] << endl;

       cout << "(*ipn)[0]=" << (*ipn)[0] << endl;

打印结果是一样的,都是‘8’。

2.        以下2种定义的区别(圆括号是必不可少的)

指针数组:

 int *ip[4]; // array of pointers to int

如果从内向外阅读 ip 的声明,则可理解为:*ip int[4] 类型——即 ip 是一个指向含有 4 个元素的数组的指针。

 int (*ip)[4]; // pointer to an array of 4 ints

进一步的理解:

int (*ip)[4]=ia;

ip=&ia[2]; //也可以写为ia+2

刚开始,我觉得应该写成ip=ia[2];结果得到报错信息:

error: cannot convert `int[4]' to `int (*)[4]' in assignment

因为ia[2]就是一个数组啊,再想如果这样写ip=ia[2];这就相当于

int ia[4]= {0,1,2,3};

int *ip=ia;

ip=ia[2];

当然是错误的。

posted on 2009-05-06 09:59 amenglai 阅读(262) 评论(0)  编辑  收藏 所属分类: C++ Primer 之 读书笔记


只有注册用户登录后才能发表评论。


网站导航: