C++基础学习系列第一部分——再议数组与指针

来源:互联网 发布:淘宝上面名龙堂好吗 编辑:程序博客网 时间:2024/06/06 18:25

 

      离上一篇复习笔记到现在已经有好几天了,这段时间有些忙,更新的些慢了,以后我会多抽些时间来更新的,希望大家多多支持我。在上一篇中,主要分开回顾了一下数组与指针的一些基础知识,在这里,我将通过一些具体的demo来写一些关于指针操作的东西。

使用指针访问数组元素

         C++ 语言中,指针和数组密切相关。特别是在表达式中使用数组名时,该名

字会自动转换为指向数组第一个元素的指针:

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

    int *ip=ia;//ip point to ia[0]

如果希望使指针指向数组中的另一个元素,则可使用下标操作符给某个元素

定位,然后用取地址操作符 & 获取该元素的存储地址:

    ip = &ia[4];//ip point to last element in ia

指针的算术操作

         指针的算术操作和迭代器的算术操作以相同的方式实现(也具有相同的约束)。使用指针的算术操作在指向数组某个元素的指针上加上(或减去)一个整型数值,就可以计算出指向数组另一元素的指针值:

    ip = ia;//ip point to ia[0]

    int *ip2 = ip+4;//ip2 point toia[4]

在指针上加上(或减去)一个整型数值 n等效于获得一个新指针,该新指针指向指针原来指向的元素之后(或之前)的第 n 个元素。在指针ip上加4得到一个新的指针,指向数组中ip当前指向元素后的第四个元素。

         指针的算术操作只有在原指针和计算出来的新指针都指向同一个数组的元素,或指向该数组存储空间的下一单元时才是合法的。如果指针指向一对象,我们还可以在指针上加1从而获取指向相邻的下一个对象的指针。假如数组ia只有4个元素,则在ia的基础上加10是错误的:

    int *ip3=ia+10;//error:ia+10 is an invalid address

只要两个指针指向同一个数组或有一个指向该数组末端的下一单元,C++还支持这两个指针做减法操作:

         ptrdiff_t n = p2-p1; //ok,distance between the pointers

结果是 4,这两个指针所指向的元素间隔为 4 个对象。两个指针减法操作的结果是标准库类型(library type)ptrdiff_t 的数据。与 size_t 类型一样,ptrdiff_t 也是一种与机器相关的类型,在 cstddef 头文件中定义。size_t 是unsigned 类型,而 ptrdiff_t 则是 signed 整型。这两种类型的差别体现了它们各自的用途:size_t 类型用于指明数组长度,它必须是一个正数;ptrdiff_t 类型则应保证足以存放同一数组中两个指针之间的差距,它有可能是负数。例如,ip 减去 ip2,结果为 -4。

解引用和指针操作之间的相互作用

         在指针上加一个整型数值,其结果仍然是指针。允许在这个结果上直接进行解引用操作,而不必先把它赋给一个新指针:

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

这个表达式计算出 ia 所指向元素后面的第 4 个元素的地址,然后对该地址进行解引用操作,等价于 ia[4]。加法操作两边用圆括号括起来是必要的。如果写为:

         last = *ia + 4;// ok: last = 4,equivalent to ia[0]+4

意味着对ia进行解引用,获得 ia 所指元素的值 ia[0],然后加 4。由于加法操作和解引用操作的优先级不同,上述表达式中的圆括号是必要的。我们将在第 5.10.1 节讨论操作符的优先级。简单地说,优先级决定了有多个操作符的表达式如何对操作数分组。

下标和指针

         在表达式中使用数组名时,实际上使用的是指向数组第一个元素的指针。这种用法涉及很多方面,当它们出现时我们会逐一指出来。其中一个重要的应用是使用下标访问数组时,实际上是使用下标访问指针:

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

int i = ia[0];// ia points to thefirst element in ia

ia[0] 是一个使用数组名的表达式。在使用下标访问数组时,实际上是对指向数组元素的指针做下标操作。只要指针指向数组元素,就可以对它进行下标操作:

    int *p = &ia[2];// ok: p points tothe 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 thesame element as ia[0]

指针输出数组元素

         C++ 允许使用指针遍历数组。和其他内置类型一样,数组也没有成员函数。因此,数组不提供 begin end 操作,程序员只能自己给指针定位,使之分别标志数组的起始位置和超出末端位置。可在初始化中实现这两个指针的定位:初始化指针 pbegin指向 int_arr 数组的第一个元素,而指针 pend则指向该数组的超出末端的位置:

下面将用指针输出数组元素,请看以下代码:

运行效果如图:

指针与const限定符

指向const对象的指针

         指向const对象的指针又称为常量指针。常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针(变量)。指针指向的对象是常量,那么这个对象不能被更改。在C/C++中,常量指针是这样声明的:

1const type *p;

2type const *p;

常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值。因为常量指针是一个变量,因此,常量指针可以不被赋初始值,且可以被重新赋值。C++ 语言强制要求指向 const 对象的指针也必须具有 const 特性:

int a=5;

const int b=10;

    const int *pC = &a;//ok: but can't change a through pC

    *pC=6;//error:you cannot assign to a variablethat is const

       pC=&b;//ok:常量指针可以被重新赋值

不能使用void* 指针(第4.2.2 节)保存const对象的地址,而必须使用 const void* 类型的指针保存 const对象的地址。在实际的程序中,指向 const 的指针常用作函数的形参。将形参定义为指向 const的指针,以此确保传递给函数的实际对象在函数中不因为形参而被修改。

const的位置在指针声明运算符*的左侧。只要const位于*的左侧,无论它在类型名的左边或右边,都声明了一个指向常量的指针,叫做常量指针。

const指针

         const指针又称为指针常量。在C/C++中指针常量是这样声明的:

         type* const var_name; 

指针常量把指针本身声明为常量,其他 const量一样,const指针的值不能修改,这就意味着不能使 const指针指向其他对象。因为指针常量是一个常量,在声明的时候一定要给它赋初始值。一旦赋值,以后这个常量再也不能指向别的地址。虽然指针常量的值不能变,可是它指向的对象是可变的,因为我们并没有限制它指向的对象是常量。

         char *a=”abcde1234”;

         char *const pA; //error:const object must be initialized ifnot extern

     pA=a; //error: you cannot assign to a variablethat is const

       char *const pB=a;//OK*pB输出为a

       a[0]=’A’; //编译能通过,但是运行会出现错误。编译器的优化设置,会将程序中出现的字符串常量存储在只读区。因此 "abcde1234"的内容是不可修改的

       a=”Hello”; //a重新指向新的地址,*pB输出还是为a。因为a被重新赋值,指向一块新的地址,但是pB还是指向a原来的地址,所出*pB输出还是a

指向const对象的const指针

         指向常量的指针常量就是一个常量,并且它指向的对象也是一个常量。因为是一个指针常量,那么它指向的对象当然是一个指针对象,而它又指向常量,说明它指向的对象不能变化。在C/C++中,这么声明:

        const int a = 25;

         const int * const b = &a;

const*左边,是常量指针,指针指向常量,指针指向的对象的值不可以改变,但指针可以指向其他常量;

const*右边,是指针常量,指针的值不可以改变,但指向的对象的值可以改变,指针只指向初始化时指向的地址块;

const*两边,是指向常量的指针常量,指针的值和指针指向对象的值都不可以改变。

指针与多维数组

多维数组

         严格地说,C++中没有多维数组,通常所指的多维数组其实就是数组的数组:

int ia[3][4];  // array of size 3, each element is anarray of ints of size 4

在使用多维数组时,记住这一点有利于理解其应用。如果数组的元素又是数组,则称为二维数组,其每一维对应一个下标:

ia[2][3] ; // fetches lastelement from the array in the last row

第一维通常称为行(row),第二维则称为列(column)。C++中并未限制可用的下标个数,也就是说,我们可以定义元素是数组(其元素又是数组,如此类推)的数组。

         多维数组的初始化:和处理一维数组一样,程序员可以使用由花括号括起来的初始化式列表来初始化多维数组的元素。对于多维数组的每一行,可以再用花括号指定其元素的初

始化式:

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

其中用来标志每一行的内嵌的花括号是可选的。下面的初始化尽管有点不清楚,但与前面的声明完全等价:

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

多维数组下标的引用:为了对多维数组进行索引,每一维都需要一个下标。当需要访问数组中的特定元素时,必须提供其行下标和列下标。行下标指出需要哪个内部数组,列下标则选取该内部数组的指定元素。了解多维数组下标引用策略有助于正确计算其下标值,以及理解多维数组如何初始化。如果表达式只提供了一个下标,则结果获取的元素是该行下标索引的内层数组。如 ia[2]将获得ia 数组的最后一行,即这一行的内层数组本身,而并非该数组中的任何元素。

指针与多维数组

         与普通数组一样,使用多维数组名时,实际上将其自动转换为指向该数组第一个元素的指针。定义指向多维数组的指针时,千万别忘了该指针所指向的多维数组其实是数组的数组。因为多维数组其实就是数组的数组,所以由多维数组转换而成的指针类型应是指向第一个内层数组的指针。尽管这个概念非常明了,但声明这种指针的语法还是不容易理解:

int ia[3][4];  // array of size 3, each element is an array of ints of size 4

int (*ip)[4] = ia;// ip points to anarray of 4 ints

ip = &ia[2];// ia[2] is anarray of 4 ints

下面,我将以一个例子来说明指针与二维数组

 

运行结果如图所示:

 

 

         希望大家多多关注支持我!文中有什么不妥的地方,望大家多多指正,谢谢!

原创粉丝点击